package com.xiaomi.xms.sales.xmsf.account;
import android.accounts.Account;
import android.accounts.AccountManager;
import android.accounts.AccountManagerFuture;
import android.accounts.AuthenticatorException;
import android.accounts.OperationCanceledException;
import android.content.BroadcastReceiver;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.database.Cursor;
import android.os.Bundle;
import android.provider.BaseColumns;
import android.text.TextUtils;
import android.util.Log;
import android.util.Pair;
import com.xiaomi.xms.sales.UploadLogService;
import com.xiaomi.xms.sales.activity.MainActivity;
import com.xiaomi.xms.sales.db.DBContract.DataMimeType;
import com.xiaomi.xms.sales.db.DBContract.DataStats;
import com.xiaomi.xms.sales.model.Tags;
import com.xiaomi.xms.sales.request.ExtendedAuthToken;
import com.xiaomi.xms.sales.request.HostManager;
import com.xiaomi.xms.sales.request.Request;
import com.xiaomi.xms.sales.util.Constants;
import com.xiaomi.xms.sales.util.LogUtil;
import com.xiaomi.xms.sales.util.Utils;
import com.xiaomi.xms.sales.xmsf.account.data.AccountInfo;
import com.xiaomi.xms.sales.xmsf.account.exception.AccessDeniedException;
import com.xiaomi.xms.sales.xmsf.account.exception.InvalidCredentialException;
import com.xiaomi.xms.sales.xmsf.account.exception.InvalidResponseException;
import com.xiaomi.xms.sales.xmsf.account.utils.CloudHelper;
import org.json.JSONObject;
import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
public class LoginManager {
private static final String TAG = "ShopLoginManager";
private Context mContext;
private AccountManager mAccountManager;
private LoginCallback mLoginCallback;
private LogoutCallback mLogoutCallback;
private HashSet<AccountListener> mAccountLsteners;
private static LoginManager sLoginManager;
public static final int STATUS_SYSTEM_LOGIN = 1;
public static final int STATUS_SYSTEM_LOGOUT = 2;
public static final int STATUS_LOCAL_LOGIN = 3;
public static final int STATUS_LOCAL_LOGOUT = 4;
public static final int STATUS_SYSTEM_UNACTIVE = 5;
public static final int ERROR_LOGIN_COMMON = 0;
public static final int ERROR_LOGIN_USER_CANCELED = 1;
public static final int ERROR_LOGIN_NO_ACCOUNT = 2;
public static final int ERROR_LOGIN_NETWORK = 3;
public static final int ERROR_LOGIN_SERVER = 4;
public static final int ERROR_LOGIN_UNACTIVE = 5;
private LoginManager(Context context) {
mContext = context;
mAccountManager = AccountManager.get(context);
mAccountLsteners = new HashSet<AccountListener>();
// 注册账户切换的监听器
context.registerReceiver(mAccountChangedReceiver, new IntentFilter(
Constants.Account.ACTION_LOGIN_ACCOUNTS_PRE_CHANGED));
}
@Override
protected void finalize() throws Throwable {
mContext.unregisterReceiver(mAccountChangedReceiver);
}
public static void init(Context context) {
if (sLoginManager == null) {
sLoginManager = new LoginManager(context);
}
}
public static LoginManager getInstance() {
return sLoginManager;
}
public String getUserId() {
String userId = null;
if (Utils.Preference.getBooleanPref(mContext, Constants.Account.PREF_LOGIN_SYSTEM, false)) {
userId = Utils.Preference.getStringPref(mContext, Constants.Account.PREF_SYSTEM_UID, null);
} else {
userId = Utils.Preference.getStringPref(mContext, Constants.Account.PREF_UID, null);
}
return userId;
}
public ExtendedAuthToken getExtendedAuthToken(String sid) {
String extendedAuthToken = null;
// 如果使用的是系统登录
if (Utils.Preference.getBooleanPref(mContext, Constants.Account.PREF_LOGIN_SYSTEM, false)) {
if (TextUtils.equals(sid, Constants.Account.DEFAULT_SERVICE_ID)) {
extendedAuthToken = Utils.Preference.getStringPref(mContext,
Constants.Account.PREF_SYSTEM_EXTENDED_TOKEN, "");
if (TextUtils.isEmpty(extendedAuthToken)) {
extendedAuthToken = getSystemAccountAuthToken(sid);
}
} else {
extendedAuthToken = getSystemAccountAuthToken(sid);
}
} else {
if (TextUtils.equals(sid, Constants.Account.DEFAULT_SERVICE_ID)) {
extendedAuthToken = Utils.Preference.getStringPref(mContext,
Constants.Account.PREF_EXTENDED_TOKEN, "");
if (TextUtils.isEmpty(extendedAuthToken)) {
extendedAuthToken = getLocalAccountExtendedAuthToken(sid);
}
} else {
extendedAuthToken = getLocalAccountExtendedAuthToken(sid);
}
}
return TextUtils.isEmpty(extendedAuthToken) ? null : ExtendedAuthToken
.parse(extendedAuthToken);
}
public void setSystemLogin(boolean isLoginSystem) {
Utils.Preference.setBooleanPref(mContext, Constants.Account.PREF_LOGIN_SYSTEM, isLoginSystem);
}
public synchronized void addLoginListener(AccountListener listener) {
if (listener == null) {
return;
}
if (mAccountLsteners == null) {
mAccountLsteners = new HashSet<AccountListener>();
}
if (!mAccountLsteners.contains(listener)) {
mAccountLsteners.add(listener);
}
}
public synchronized void removeLoginListener(AccountListener listener) {
if (listener == null) {
return;
}
if (mAccountLsteners != null) {
mAccountLsteners.remove(listener);
}
}
/**
* for internal use
*/
public void onAccountLoginSucceed(String userId, String authToken, String security) {
if (mLoginCallback != null) {
mLoginCallback.onLoginSucceed(userId, authToken, security);
}
if (mAccountLsteners != null && !mAccountLsteners.isEmpty()) {
for (AccountListener listener : mAccountLsteners) {
listener.onLogin(userId, authToken, security);
}
}
Log.d(TAG, "account has login:" + userId);
}
/**
* for internal use
*/
public void onAccountLoginFailed(int error) {
if (mLoginCallback != null) {
mLoginCallback.onLoginFailed(error);
}
Log.d(TAG, "account login failed: " + error);
}
/**
* for internal use
*/
private void onAccountLogout() {
if (mLogoutCallback != null) {
mLogoutCallback.onLogout();
}
if (mAccountLsteners != null && !mAccountLsteners.isEmpty()) {
for (AccountListener listener : mAccountLsteners) {
listener.onLogout();
}
}
Log.d(TAG, "account has logout");
}
/**
* 是否登录
*
* @return boolean
*/
public boolean hasLogin() {
String userId;
String extendedAuthToken;
if (Utils.Preference.getBooleanPref(mContext, Constants.Account.PREF_LOGIN_SYSTEM, false)) {
userId = getSystemAccountId();
if (!TextUtils.isEmpty(userId)) {
return true;
}
return false;
} else {
userId = Utils.Preference.getStringPref(mContext, Constants.Account.PREF_UID, "");
extendedAuthToken = Utils.Preference.getStringPref(mContext,
Constants.Account.PREF_EXTENDED_TOKEN, "");
}
if (!TextUtils.isEmpty(userId) && !TextUtils.isEmpty(extendedAuthToken)) {
return true;
}
return false;
}
public boolean hasSystemAccount() {
return !TextUtils.isEmpty(getSystemAccountId());
}
public String getSystemAccountId() {
Account[] account = mAccountManager.getAccountsByType(Constants.Account.ACCOUNT_TYPE);
return account.length > 0 ? account[0].name : null;
}
public String getPassToken() {
if (hasLogin()
&& !Utils.Preference.getBooleanPref(mContext, Constants.Account.PREF_LOGIN_SYSTEM,
false)) {
return Utils.Preference.getStringPref(mContext, Constants.Account.PREF_PASS_TOKEN, "");
}
return null;
}
public void invalidAuthToken() {
if (Utils.Preference.getBooleanPref(mContext, Constants.Account.PREF_LOGIN_SYSTEM, false)) {
Utils.Preference.removePref(mContext, Constants.Account.PREF_EXTENDED_TOKEN);
} else {
Utils.Preference.removePref(mContext, Constants.Account.PREF_SYSTEM_EXTENDED_TOKEN);
}
if (mAccountLsteners != null && !mAccountLsteners.isEmpty()) {
for (AccountListener listener : mAccountLsteners) {
listener.onInvalidAuthonToken();
}
}
}
private String getLocalAccountExtendedAuthToken(String sid) {
String userId = Utils.Preference.getStringPref(mContext, Constants.Account.PREF_UID, "");
String passToken = Utils.Preference.getStringPref(mContext, Constants.Account.PREF_PASS_TOKEN, "");
if (TextUtils.isEmpty(userId) || TextUtils.isEmpty(passToken)) {
return null;
}
try {
AccountInfo account = CloudHelper.getServiceTokenByPassToken(userId, passToken, sid);
String extendedAuthToken = ExtendedAuthToken.build(account.getSecurity(),
account.getSecurity()).toPlain();
Utils.Preference.setStringPref(mContext, Constants.Account.PREF_EXTENDED_TOKEN,
extendedAuthToken);
return extendedAuthToken;
} catch (InvalidResponseException e) {
e.printStackTrace();
} catch (InvalidCredentialException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (AccessDeniedException e) {
e.printStackTrace();
}
return null;
}
public String getSystemAccountAuthToken(String sid) {
Account[] account = mAccountManager.getAccountsByType(Constants.Account.ACCOUNT_TYPE);
if (account.length > 0) {
AccountManagerFuture<Bundle> future = mAccountManager.getAuthToken(account[0], sid, null,
null, null, null);
try {
if (future != null) {
Bundle result = future.getResult();
if (result != null) {
String extendedAuthToken = result.getString(AccountManager.KEY_AUTHTOKEN);
if (!TextUtils.isEmpty(extendedAuthToken)) {
return extendedAuthToken;
}
}
}
} catch (OperationCanceledException e) {
e.printStackTrace();
} catch (AuthenticatorException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
public void loginSystem(String authToken) {
if (!TextUtils.isEmpty(authToken)) {
LogUtil.d(TAG, "system login");
setSystemLogin(true);
String uid = getSystemAccountId();
ExtendedAuthToken token = ExtendedAuthToken.parse(authToken);
Utils.Preference.setStringPref(mContext, Constants.Account.PREF_SYSTEM_UID, uid);
Utils.Preference.setStringPref(mContext, Constants.Account.PREF_SYSTEM_EXTENDED_TOKEN,
authToken);
onAccountLoginSucceed(uid, token.authToken, token.security);
}
}
public void removeLoginCallback() {
this.mLoginCallback = null;
}
public void logout() {
logout(null);
}
/**
* 登出本地账户,该方法会刷新LoginManager中的缓存数据
*/
public void logout(LogoutCallback logoutCallback) {
this.mLogoutCallback = logoutCallback;
// 删除所有的登录信息
Utils.Preference.removePref(mContext, Constants.Account.PREF_UID);
Utils.Preference.removePref(mContext, Constants.Account.PREF_EXTENDED_TOKEN);
Utils.Preference.removePref(mContext, Constants.Account.PREF_PASS_TOKEN);
Utils.Preference.removePref(mContext, Constants.Account.PREF_SYSTEM_UID);
Utils.Preference.removePref(mContext, Constants.Account.PREF_SYSTEM_EXTENDED_TOKEN);
Utils.Preference.removePref(mContext, Constants.Account.PREF_LOGIN_SYSTEM);
Utils.Preference.removePref(mContext, Constants.Account.PREF_USER_ORGID);
Utils.Preference.removePref(mContext, Constants.Account.PREF_USER_NAME);
Utils.Preference.removePref(mContext, Constants.Account.PREF_USER_ORGNAME);
Intent intent = new Intent(mContext, UploadLogService.class);
mContext.stopService(intent);
onAccountLogout();
}
private BroadcastReceiver mAccountChangedReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (TextUtils.equals(action, Constants.Account.ACTION_LOGIN_ACCOUNTS_PRE_CHANGED)) {
int type = intent.getIntExtra(Constants.Account.EXTRA_UPDATE_TYPE, -1);
Account account = intent.getParcelableExtra(Constants.Account.EXTRA_ACCOUNT);
if (!TextUtils.equals(account.type, Constants.Account.ACCOUNT_TYPE)) {
return;
}
if (type == Constants.Account.TYPE_ADD) {
// TODO:系统账户增加时,可以问用户是否登录
} else if (type == Constants.Account.TYPE_REMOVE) {
// 系统账户删除时自动登出
Utils.Preference.removePref(mContext, Constants.Account.PREF_SYSTEM_UID);
Utils.Preference.removePref(mContext, Constants.Account.PREF_SYSTEM_EXTENDED_TOKEN);
if (Utils.Preference.getBooleanPref(mContext, Constants.Account.PREF_LOGIN_SYSTEM,
false)) {
// 如果正在使用系统帐号,则登出事件
setSystemLogin(false);
onAccountLogout();
}
}
}
}
};
public Map<String, ExtendedAuthToken> getWebRequiredCachedServiceTokens() {
Map<String, ExtendedAuthToken> map = null;
Cursor c = mContext.getContentResolver().query(DataStats.CONTENT_URI,
new String[] {
DataStats.STATS
},
DataStats.TYPE + "='" + DataMimeType.SERVICE_TOKEN + "'", null, null);
if (c != null) {
try {
if (c.moveToFirst()) {
do {
String stats = c.getString(0);
if (!TextUtils.isEmpty(stats)) {
Pair<String, String> pair = DataMimeType.parseServiceToken(stats);
if (map == null) {
map = new HashMap<String, ExtendedAuthToken>();
}
map.put(pair.first, ExtendedAuthToken.parse(pair.second));
LogUtil.d(TAG, "The cached serviceToken is:" + pair.second);
}
} while (c.moveToNext());
}
} finally {
c.close();
}
}
return map;
}
public Map<String, ExtendedAuthToken> getWebRequiredServiceTokens() {
Map<String, ExtendedAuthToken> map = getWebRequiredCachedServiceTokens();
// 重置系统帐号中所有的serviceToken
if (map != null) {
Iterator<Entry<String, ExtendedAuthToken>> iterator = map.entrySet().iterator();
while (iterator.hasNext()) {
Entry<String, ExtendedAuthToken> entry = iterator.next();
LogUtil.d(TAG, "Invalide serviceToken:" + entry.getValue());
mAccountManager.invalidateAuthToken(Constants.Account.ACCOUNT_TYPE, entry.getValue().toPlain());
}
map.clear();
}
Map<String, String> sidsMap = getSidsMap();
if (sidsMap != null) {
Iterator<Entry<String, String>> iterator = sidsMap.entrySet().iterator();
while (iterator.hasNext()) {
Entry<String, String> entry = iterator.next();
// Web上没有有效的serviceToken过期机制,现在每次都重新取serviceToken,防止web上Token过期,抢购
// 活动时候没有登录的现象发生
ExtendedAuthToken serviceToken = getExtendedAuthToken(entry.getValue());
if (serviceToken != null) {
if (map == null) {
map = new HashMap<String, ExtendedAuthToken>();
}
map.put(entry.getKey(), serviceToken);
saveServiceToken(entry.getValue(), serviceToken.toPlain());
}
LogUtil.d(TAG, "The sid " + entry.getValue() + " 's serviceToken is "
+ (serviceToken == null ? "null" : serviceToken.authToken));
}
}
return map;
}
private void saveServiceToken(String sid, String serviceToken) {
Cursor c = mContext.getContentResolver().query(
DataStats.CONTENT_URI,
new String[] {
BaseColumns._ID
},
DataStats.TYPE + "='" + DataMimeType.SERVICE_TOKEN + "' AND " + DataStats.STATS
+ " LIKE '" + sid + "%'", null, null);
ContentValues values = new ContentValues();
values.put(DataStats.STATS, DataMimeType.formatServiceToken(sid, serviceToken));
try {
if (c != null && c.getCount() > 0) {
// 如果有缓存,那么更新缓存
if (c.moveToFirst()) {
long id = c.getLong(0);
mContext.getContentResolver().update(DataStats.CONTENT_URI, values,
BaseColumns._ID + "=" + id, null);
}
} else {
// 如果缓存中没有token,那么直接插入数据
values.put(DataStats.TYPE, DataMimeType.SERVICE_TOKEN);
mContext.getContentResolver().insert(DataStats.CONTENT_URI, values);
}
} finally {
if (c != null) {
c.close();
}
}
}
/**
* 获取商城需要的所有服务的serviceToken ids
*/
private Map<String, String> getSidsMap() {
Map<String, String> map = null;
Request request = new Request(HostManager.getServiceTokens());
if (request.getStatus() == Request.STATUS_OK) {
JSONObject json = request.requestJSON();
LogUtil.d(TAG, json.toString());
if (json != null && json.optInt(Tags.CODE) == 0) {
JSONObject sids = json.optJSONObject(Tags.DATA);
if (sids != null) {
Iterator<String> iter = sids.keys();
while (iter.hasNext()) {
if (map == null) {
map = new HashMap<String, String>();
}
String key = iter.next();
// 默认的SID通过APP有有效的过期重置机制,无需每次重新获取
if (!TextUtils.equals(Constants.Account.DEFAULT_SERVICE_ID, key)) {
map.put(sids.optString(key), key);
LogUtil.d(TAG, "The sid is " + key + " and the value is "
+ sids.optString(key));
}
}
}
}
}
return map;
}
/**
* 登录监听
*/
public interface AccountListener {
public void onLogin(String userId, String authToken, String security);
public void onInvalidAuthonToken();
public void onLogout();
}
/**
* 登录回调
*/
public interface LoginCallback {
public void onLoginSucceed(String userId, String authToken, String security);
public void onLoginFailed(int error);
}
/**
* 登出回调
*/
public interface LogoutCallback {
public void onLogout();
}
}