1 /* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.contacts.util; 18 19 import android.accounts.AccountManager; 20 import android.accounts.AccountManagerCallback; 21 import android.accounts.AccountManagerFuture; 22 import android.accounts.AuthenticatorDescription; 23 import android.accounts.AuthenticatorException; 24 import android.accounts.OperationCanceledException; 25 import android.app.Activity; 26 import android.content.Context; 27 import android.content.SharedPreferences; 28 import android.os.Bundle; 29 import android.preference.PreferenceManager; 30 import android.util.Log; 31 32 import com.android.contacts.R; 33 import com.android.contacts.common.model.account.GoogleAccountType; 34 35 import java.io.IOException; 36 37 /** 38 * Utility class for controlling whether the standard "no account" prompt on launch is shown. 39 */ 40 public class AccountPromptUtils { 41 42 private static final String TAG = AccountPromptUtils.class.getSimpleName(); 43 44 /** {@link SharedPreferences} key for whether or not the "no account" prompt should be shown. */ 45 private static final String KEY_SHOW_ACCOUNT_PROMPT = "settings.showAccountPrompt"; 46 47 /** 48 * The following intent keys are understood by the {@link AccountManager} and should not be 49 * changed unless the API changes. 50 */ 51 private static final String KEY_INTRO_MESSAGE = "introMessage"; 52 private static final String KEY_ALLOW_SKIP_ACCOUNT_SETUP = "allowSkip"; 53 private static final String KEY_USER_SKIPPED_ACCOUNT_SETUP = "setupSkipped"; 54 55 private static SharedPreferences getSharedPreferences(Context context) { 56 return PreferenceManager.getDefaultSharedPreferences(context); 57 } 58 59 /** 60 * Returns true if the "no account" prompt should be shown 61 * (according to {@link SharedPreferences}), otherwise return false. Since this prompt is 62 * Google-specific for the time being, this method will also return false if the Google 63 * account type is not available from the {@link AccountManager}. 64 */ 65 public static boolean shouldShowAccountPrompt(Context context) { 66 // TODO: Remove the filtering of account types once there is an API in 67 // {@link AccountManager} to show a similar account prompt 68 // (see {@link AccountManager#addAccount()} in {@link #launchAccountPrompt()} 69 // for any type of account. Bug: 5375902 70 AuthenticatorDescription[] allTypes = 71 AccountManager.get(context).getAuthenticatorTypes(); 72 for (AuthenticatorDescription authenticatorType : allTypes) { 73 if (GoogleAccountType.ACCOUNT_TYPE.equals(authenticatorType.type)) { 74 return getSharedPreferences(context).getBoolean(KEY_SHOW_ACCOUNT_PROMPT, true); 75 } 76 } 77 return false; 78 } 79 80 /** 81 * Remember to never show the "no account" prompt again by saving this to 82 * {@link SharedPreferences}. 83 */ 84 public static void neverShowAccountPromptAgain(Context context) { 85 getSharedPreferences(context).edit() 86 .putBoolean(KEY_SHOW_ACCOUNT_PROMPT, false) 87 .apply(); 88 } 89 90 /** 91 * Launch the "no account" prompt. (We assume the caller has already verified that the prompt 92 * can be shown, so checking the {@link #KEY_SHOW_ACCOUNT_PROMPT} value in 93 * {@link SharedPreferences} will not be done in this method). 94 */ 95 public static void launchAccountPrompt(Activity activity) { 96 Bundle options = new Bundle(); 97 options.putCharSequence(KEY_INTRO_MESSAGE, activity.getString(R.string.no_account_prompt)); 98 options.putBoolean(KEY_ALLOW_SKIP_ACCOUNT_SETUP, true); 99 AccountManager.get(activity).addAccount(GoogleAccountType.ACCOUNT_TYPE, null, null, options, 100 activity, getAccountManagerCallback(activity), null); 101 } 102 103 private static AccountManagerCallback<Bundle> getAccountManagerCallback( 104 final Activity activity) { 105 return new AccountManagerCallback<Bundle>() { 106 @Override 107 public void run(AccountManagerFuture<Bundle> future) { 108 if (future.isCancelled()) { 109 // The account creation process was canceled 110 activity.finish(); 111 return; 112 } 113 try { 114 Bundle result = future.getResult(); 115 if (result.getBoolean(KEY_USER_SKIPPED_ACCOUNT_SETUP)) { 116 AccountPromptUtils.neverShowAccountPromptAgain(activity); 117 } 118 } catch (OperationCanceledException ignore) { 119 Log.e(TAG, "Account setup error: account creation process canceled"); 120 } catch (IOException ignore) { 121 Log.e(TAG, "Account setup error: No authenticator was registered for this" 122 + "account type or the authenticator failed to respond"); 123 } catch (AuthenticatorException ignore) { 124 Log.e(TAG, "Account setup error: Authenticator experienced an I/O problem"); 125 } 126 } 127 }; 128 } 129 } 130