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 
getSharedPreferences(Context context)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      */
shouldShowAccountPrompt(Context context)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      */
neverShowAccountPromptAgain(Context context)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      */
launchAccountPrompt(Activity activity)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 
getAccountManagerCallback( final Activity activity)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