Java tutorial
/* * Copyright 2014 hemou Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.hemou.android.account; import android.accounts.Account; import android.accounts.AccountManager; import android.accounts.AccountManagerFuture; import android.accounts.AccountsException; import android.accounts.AuthenticatorDescription; import android.accounts.AuthenticatorException; import android.accounts.OperationCanceledException; import android.app.Activity; import android.app.AlertDialog; import android.content.Context; import android.content.DialogInterface; import android.content.DialogInterface.OnCancelListener; import android.content.DialogInterface.OnClickListener; import android.os.Bundle; import android.util.Log; import com.eagleyes.social.api.model.UsrNormalDTO; import com.eagleyes.social.api.model.UsrSelfDTO; import com.eagleyes.social.api.model.UsrSelfDetailDTO; import com.hemou.android.R.string; import com.hemou.android.core.cons.Intents; import com.hemou.android.ui.base.LightAlertDialog; import com.hemou.android.util.StrUtils; import com.lidroid.xutils.util.LogUtils; import org.springframework.http.HttpStatus; import org.springframework.social.NotAuthorizedException; import org.springframework.util.StringUtils; import org.springframework.web.client.HttpClientErrorException; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; import static android.content.DialogInterface.BUTTON_POSITIVE; import static android.util.Log.DEBUG; import static com.hemou.android.core.cons.AppCons.ACCOUNT_TYPE; import static com.hemou.android.core.cons.AppCons.AUTHTOKEN_TYPE; /** * Helpers for accessing {@link AccountManager} */ public class AccountUtils { private static final String TAG = "AccountUtils"; private static boolean AUTHENTICATOR_CHECKED; private static boolean HAS_AUTHENTICATOR; private static final AtomicInteger UPDATE_COUNT = new AtomicInteger(0); private static class AuthenticatorConflictException extends IOException { private static final long serialVersionUID = 641279204734869183L; } /** * Verify authenticator registered for account type matches the package name * of this application * * @param manager * @return true is authenticator registered, false otherwise */ public static boolean hasAuthenticator(final AccountManager manager) { if (!AUTHENTICATOR_CHECKED) { final AuthenticatorDescription[] types = manager.getAuthenticatorTypes(); LogUtils.v("All Authenticator types:" + StrUtils.obj2Str(types)); if (types != null && types.length > 0) for (AuthenticatorDescription descriptor : types) { if (descriptor != null && ACCOUNT_TYPE.equals(descriptor.type)) { HAS_AUTHENTICATOR = "com.hemou.android".equals(descriptor.packageName); break; } } AUTHENTICATOR_CHECKED = true; } return HAS_AUTHENTICATOR; } /** * Is the given user the owner of the default account? * * @param context * @param user * @return true if default account user, false otherwise */ public static boolean isUser(final Context context, final UsrSelfDetailDTO user) { if (user == null) return false; // String login = user.getLogin(); String login = user.getAccount(); if (login == null) return false; return login.equals(getLogin(context)); } public static void updateAcntDataTotally(Context ctx, UsrSelfDTO dto) { if (ctx == null) throw new IllegalArgumentException(); Account acnt = getAccount(ctx); if (acnt == null) { LogUtils.e("The user aliving should be added to the AccountManager framework......"); return; } AccountManager.get(ctx).setUserData(acnt, Intents.EXTRA.USER, StrUtils.obj2Str(dto)); } public static UsrSelfDTO getMyInfo(Context ctx) { Account acnt = getAccount(ctx); if (acnt == null) return null; String usrStr = AccountManager.get(ctx).getUserData(acnt, Intents.EXTRA.USER); if (StrUtils.isEmpties(usrStr)) return null; return StrUtils.str2Obj(usrStr, UsrSelfDTO.class); } public static boolean isMe(Context ctx, UsrNormalDTO user) { if (user == null) return false; UsrSelfDTO dto = getMyInfo(ctx); if (dto == null) return false; return dto.getAccount().equals(user.getAccount()); } public static String getMyId(Context ctx) { UsrSelfDTO dto = getMyInfo(ctx); if (dto == null) throw new IllegalStateException("?..."); return dto.getAccount(); } /** * Get login name of configured account * * @param context * @return login name or null if none configure */ public static String getLogin(final Context context) { final Account account = getAccount(context); return account != null ? account.name : null; } /** * Get configured account * * @param context * @return account or null if none */ public static Account getAccount(final Context context) { final Account[] accounts = AccountManager.get(context).getAccountsByType(ACCOUNT_TYPE); return accounts.length > 0 ? accounts[0] : null; } private static Account[] getAccounts(final AccountManager manager) throws OperationCanceledException, AuthenticatorException, IOException { final AccountManagerFuture<Account[]> future = manager.getAccountsByTypeAndFeatures(ACCOUNT_TYPE, null, null, null); final Account[] accounts = future.getResult(); if (accounts != null && accounts.length > 0) return getPasswordAccessibleAccounts(manager, accounts); else return new Account[0]; } /** * Get default account where password can be retrieved * * @param context * @return password accessible account or null if none */ public static Account getPasswordAccessibleAccount(final Context context) { AccountManager manager = AccountManager.get(context); Account[] accounts = manager.getAccountsByType(ACCOUNT_TYPE); if (accounts == null || accounts.length == 0) return null; try { accounts = getPasswordAccessibleAccounts(manager, accounts); } catch (AuthenticatorConflictException e) { return null; } return accounts != null && accounts.length > 0 ? accounts[0] : null; } private static Account[] getPasswordAccessibleAccounts(final AccountManager manager, final Account[] candidates) throws AuthenticatorConflictException { final List<Account> accessible = new ArrayList<Account>(candidates.length); boolean exceptionThrown = false; for (Account account : candidates) try { manager.getPassword(account); accessible.add(account); } catch (SecurityException ignored) { exceptionThrown = true; } if (accessible.isEmpty() && exceptionThrown) throw new AuthenticatorConflictException(); return accessible.toArray(new Account[accessible.size()]); } /** * Get account used for authentication * * @param manager * @param act * @return account * @throws IOException * @throws AccountsException */ public static Account getAccount(final AccountManager manager, final Activity act) throws IOException, AccountsException { final String SUB_TAG = "acnt_get"; final boolean loggable = Log.isLoggable(SUB_TAG, DEBUG); if (loggable) Log.d(SUB_TAG, "Getting account"); if (act == null) throw new IllegalArgumentException("Activity cannot be null"); if (act.isFinishing()) { Log.v(SUB_TAG, act.getClass().getName() + "--->?finish()OperationCanceledException..."); throw new OperationCanceledException(); } Account[] accounts; try { if (!hasAuthenticator(manager)) { Log.e(SUB_TAG, "Current user is not under the authenticated environment...."); throw new AuthenticatorConflictException(); } while ((accounts = getAccounts(manager)).length == 0) { Bundle result = manager.addAccount(ACCOUNT_TYPE, AUTHTOKEN_TYPE, null, null, act, null, null) .getResult(); } } catch (OperationCanceledException e) { Log.d(SUB_TAG, "Excepting retrieving account", e); act.finish(); throw e; } catch (AccountsException e) { Log.d(SUB_TAG, "Excepting retrieving account", e); throw e; } catch (AuthenticatorConflictException e) { act.runOnUiThread(new Runnable() { public void run() { showConflictMessage(act); } }); throw e; } catch (IOException e) { Log.d(SUB_TAG, "Excepting retrieving account", e); throw e; } // if (loggable) Log.d(SUB_TAG, "Returning account " + accounts[0].name); return accounts[0]; } /** * Update account * * @param account * @param act * @return true if account was updated, false otherwise */ public static boolean updateAccount(final Account account, final Activity act) { if (act == null) throw new IllegalArgumentException("Activity cannot be null"); final String SUB_TAG = "acnt_update"; int count = UPDATE_COUNT.get(); synchronized (UPDATE_COUNT) { // Don't update the account if the account was successfully updated // while the lock was being waited for if (count != UPDATE_COUNT.get()) return true; AccountManager manager = AccountManager.get(act); try { if (!hasAuthenticator(manager)) throw new AuthenticatorConflictException(); manager.updateCredentials(account, AUTHTOKEN_TYPE, null, act, null, null).getResult(); UPDATE_COUNT.incrementAndGet(); return true; } catch (OperationCanceledException e) { Log.d(SUB_TAG, "Excepting retrieving account", e); act.finish(); return false; } catch (AccountsException e) { Log.d(SUB_TAG, "Excepting retrieving account", e); return false; } catch (AuthenticatorConflictException e) { act.runOnUiThread(new Runnable() { public void run() { showConflictMessage(act); } }); return false; } catch (IOException e) { Log.d(SUB_TAG, "Excepting retrieving account", e); return false; } } } /** * Show conflict message about previously registered authenticator from * another application * * @param activity */ private static void showConflictMessage(final Activity activity) { AlertDialog dialog = LightAlertDialog.create(activity); dialog.setTitle(activity.getString(string.authenticator_conflict_title)); dialog.setMessage(activity.getString(string.authenticator_conflict_message)); dialog.setOnCancelListener(new OnCancelListener() { @Override public void onCancel(DialogInterface dialog) { activity.finish(); } }); dialog.setButton(BUTTON_POSITIVE, activity.getString(android.R.string.ok), new OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { activity.finish(); } }); dialog.show(); } /** * Is the given {@link Exception} due to a 401 Unauthorized API response? * * @param e * @return true if 401, false otherwise */ public static boolean isUnauthorized(final Exception e) { Log.e(TAG, "Exception occured[" + Thread.currentThread().getId() + "]:{type:" + e.getClass().getName() + "," + e.getLocalizedMessage() + "}"); String errorMess = e.getMessage(); if (!StringUtils.isEmpty(errorMess) && (errorMess.contains("The authorization has expired") || errorMess.contains("401 Unauthorized") || errorMess.contains("403 Forbidden"))) return true; if (e instanceof NotAuthorizedException) { Log.e(TAG, "?..."); return true; } // if (e instanceof ResourceAccessException) // return true; if (e instanceof HttpClientErrorException) { HttpClientErrorException expt = (HttpClientErrorException) e; HttpStatus status = expt.getStatusCode(); if (Arrays.asList(HttpStatus.UNAUTHORIZED, HttpStatus.NETWORK_AUTHENTICATION_REQUIRED, HttpStatus.NON_AUTHORITATIVE_INFORMATION, HttpStatus.PROXY_AUTHENTICATION_REQUIRED, //403?????? HttpStatus.FORBIDDEN).contains(status)) return true; } return false; } }