Use standardized no account screen on first launch
- If there are no accounts on the device, then launch
an intent to show the prompt (check that there is no
flag in SharedPreferences preventing the prompt from
being shown).
- Only when the user explicitly selects "Not now" from
the no account screen, do we store a flag that says
we should never show the prompt again.
- Add "Manage accounts" permission in order to
perform AccountManager.addAccount, which gives us access
to the "no account" screen.
Bug: 5250360
Change-Id: I2f925c838bc0e7003a8dbb3280e5a22ed8680670
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index a1829d1..f4dcdf6 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -23,6 +23,7 @@
<uses-permission android:name="android.permission.CALL_PRIVILEGED" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.WRITE_CONTACTS" />
+ <uses-permission android:name="android.permission.MANAGE_ACCOUNTS" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
diff --git a/src/com/android/contacts/activities/PeopleActivity.java b/src/com/android/contacts/activities/PeopleActivity.java
index 332a953..d2759dc 100644
--- a/src/com/android/contacts/activities/PeopleActivity.java
+++ b/src/com/android/contacts/activities/PeopleActivity.java
@@ -53,6 +53,7 @@
import com.android.contacts.model.AccountWithDataSet;
import com.android.contacts.preference.ContactsPreferenceActivity;
import com.android.contacts.preference.DisplayOptionsPreferenceFragment;
+import com.android.contacts.util.AccountPromptUtils;
import com.android.contacts.util.AccountSelectionUtil;
import com.android.contacts.util.AccountsListAdapter;
import com.android.contacts.util.Constants;
@@ -918,6 +919,16 @@
mAllFragment.setEnabled(true);
}
} else {
+ // If there are no accounts on the device and we should show the "no account" prompt
+ // (based on {@link SharedPreferences}), then launch the account setup activity so the
+ // user can sign-in or create an account.
+ if (!areAccountsAvailable() && AccountPromptUtils.shouldShowAccountPrompt(this)) {
+ AccountPromptUtils.launchAccountPrompt(this);
+ return;
+ }
+
+ // Otherwise, continue setting up the page so that the user can still use the app
+ // without an account.
if (mAllFragment != null) {
mAllFragment.setEnabled(false);
}
diff --git a/src/com/android/contacts/util/AccountPromptUtils.java b/src/com/android/contacts/util/AccountPromptUtils.java
new file mode 100644
index 0000000..58865d0
--- /dev/null
+++ b/src/com/android/contacts/util/AccountPromptUtils.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * 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.android.contacts.util;
+
+import com.android.contacts.R;
+import com.android.contacts.model.GoogleAccountType;
+
+import android.accounts.AccountManager;
+import android.accounts.AccountManagerCallback;
+import android.accounts.AccountManagerFuture;
+import android.accounts.AuthenticatorException;
+import android.accounts.OperationCanceledException;
+import android.app.Activity;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.os.Bundle;
+import android.preference.PreferenceManager;
+import android.util.Log;
+
+import java.io.IOException;
+
+/**
+ * Utility class for controlling whether the standard "no account" prompt on launch is shown.
+ */
+public class AccountPromptUtils {
+
+ private static final String TAG = AccountPromptUtils.class.getSimpleName();
+
+ /** {@link SharedPreferences} key for whether or not the "no account" prompt should be shown. */
+ private static final String KEY_SHOW_ACCOUNT_PROMPT = "settings.showAccountPrompt";
+
+ /**
+ * The following intent keys are understood by the {@link AccountManager} and should not be
+ * changed unless the API changes.
+ */
+ private static final String KEY_INTRO_MESSAGE = "introMessage";
+ private static final String KEY_ALLOW_SKIP_ACCOUNT_SETUP = "allowSkip";
+ private static final String KEY_USER_SKIPPED_ACCOUNT_SETUP = "setupSkipped";
+
+ private static SharedPreferences getSharedPreferences(Context context) {
+ return PreferenceManager.getDefaultSharedPreferences(context);
+ }
+
+ /**
+ * Returns true if the "no account" prompt should be shown
+ * (according to {@link SharedPreferences}), otherwise return false.
+ */
+ public static boolean shouldShowAccountPrompt(Context context) {
+ return getSharedPreferences(context).getBoolean(KEY_SHOW_ACCOUNT_PROMPT, true);
+ }
+
+ /**
+ * Remember to never show the "no account" prompt again by saving this to
+ * {@link SharedPreferences}.
+ */
+ public static void neverShowAccountPromptAgain(Context context) {
+ getSharedPreferences(context).edit()
+ .putBoolean(KEY_SHOW_ACCOUNT_PROMPT, false)
+ .apply();
+ }
+
+ /**
+ * Launch the "no account" prompt. (We assume the caller has already verified that the prompt
+ * can be shown, so checking the {@link #KEY_SHOW_ACCOUNT_PROMPT} value in
+ * {@link SharedPreferences} will not be done in this method).
+ */
+ public static void launchAccountPrompt(Activity activity) {
+ Bundle options = new Bundle();
+ options.putCharSequence(KEY_INTRO_MESSAGE, activity.getString(R.string.no_account_prompt));
+ options.putBoolean(KEY_ALLOW_SKIP_ACCOUNT_SETUP, true);
+ AccountManager.get(activity).addAccount(GoogleAccountType.ACCOUNT_TYPE, null, null, options,
+ activity, getAccountManagerCallback(activity), null);
+ }
+
+ private static AccountManagerCallback<Bundle> getAccountManagerCallback(
+ final Activity activity) {
+ return new AccountManagerCallback<Bundle>() {
+ @Override
+ public void run(AccountManagerFuture<Bundle> future) {
+ if (future.isCancelled()) {
+ // The account creation process was canceled
+ activity.finish();
+ return;
+ }
+ try {
+ Bundle result = future.getResult();
+ if (result.getBoolean(KEY_USER_SKIPPED_ACCOUNT_SETUP)) {
+ AccountPromptUtils.neverShowAccountPromptAgain(activity);
+ }
+ } catch (OperationCanceledException ignore) {
+ Log.e(TAG, "Account setup error: account creation process canceled");
+ } catch (IOException ignore) {
+ Log.e(TAG, "Account setup error: No authenticator was registered for this"
+ + "account type or the authenticator failed to respond");
+ } catch (AuthenticatorException ignore) {
+ Log.e(TAG, "Account setup error: Authenticator experienced an I/O problem");
+ }
+ }
+ };
+ }
+}