1558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki/*
2558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki * Copyright (C) 2011 The Android Open Source Project
3558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki *
4558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki * Licensed under the Apache License, Version 2.0 (the "License");
5558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki * you may not use this file except in compliance with the License.
6558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki * You may obtain a copy of the License at
7558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki *
8558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki *      http://www.apache.org/licenses/LICENSE-2.0
9558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki *
10558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki * Unless required by applicable law or agreed to in writing, software
11558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki * distributed under the License is distributed on an "AS IS" BASIS,
12558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki * See the License for the specific language governing permissions and
14558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki * limitations under the License.
15558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki */
16558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki
17558669dab4109afebd19eade1f95a396215fb44dMakoto Onukipackage com.android.contacts.editor;
18558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki
19558669dab4109afebd19eade1f95a396215fb44dMakoto Onukiimport com.android.contacts.model.AccountType;
20558669dab4109afebd19eade1f95a396215fb44dMakoto Onukiimport com.android.contacts.model.AccountTypeManager;
21558669dab4109afebd19eade1f95a396215fb44dMakoto Onukiimport com.android.contacts.model.AccountWithDataSet;
22558669dab4109afebd19eade1f95a396215fb44dMakoto Onukiimport com.google.common.annotations.VisibleForTesting;
23558669dab4109afebd19eade1f95a396215fb44dMakoto Onukiimport com.google.common.collect.ImmutableList;
24558669dab4109afebd19eade1f95a396215fb44dMakoto Onukiimport com.google.common.collect.Sets;
25558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki
26558669dab4109afebd19eade1f95a396215fb44dMakoto Onukiimport android.accounts.Account;
27558669dab4109afebd19eade1f95a396215fb44dMakoto Onukiimport android.accounts.AccountManager;
28558669dab4109afebd19eade1f95a396215fb44dMakoto Onukiimport android.app.Activity;
29558669dab4109afebd19eade1f95a396215fb44dMakoto Onukiimport android.content.Context;
30558669dab4109afebd19eade1f95a396215fb44dMakoto Onukiimport android.content.Intent;
31558669dab4109afebd19eade1f95a396215fb44dMakoto Onukiimport android.content.SharedPreferences;
32558669dab4109afebd19eade1f95a396215fb44dMakoto Onukiimport android.preference.PreferenceManager;
33558669dab4109afebd19eade1f95a396215fb44dMakoto Onukiimport android.text.TextUtils;
34131e6ac666868645b48ae6932575d85751ff57c0Makoto Onukiimport android.util.Log;
35558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki
36558669dab4109afebd19eade1f95a396215fb44dMakoto Onukiimport java.util.ArrayList;
37558669dab4109afebd19eade1f95a396215fb44dMakoto Onukiimport java.util.List;
38558669dab4109afebd19eade1f95a396215fb44dMakoto Onukiimport java.util.Set;
39558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki
40558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki/**
41558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki * Utility methods for the "account changed" notification in the new contact creation flow.
42558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki */
43558669dab4109afebd19eade1f95a396215fb44dMakoto Onukipublic class ContactEditorUtils {
44558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki    private static final String TAG = "ContactEditorUtils";
45558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki
46558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki    private static final String KEY_DEFAULT_ACCOUNT = "ContactEditorUtils_default_account";
47558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki    private static final String KEY_KNOWN_ACCOUNTS = "ContactEditorUtils_known_accounts";
48558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki    // Key to tell the first time launch.
49558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki    private static final String KEY_ANYTHING_SAVED = "ContactEditorUtils_anything_saved";
50558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki
51558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki    private static final List<AccountWithDataSet> EMPTY_ACCOUNTS = ImmutableList.of();
52558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki
53558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki    private static ContactEditorUtils sInstance;
54558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki
55558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki    private final Context mContext;
56558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki    private final SharedPreferences mPrefs;
57558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki    private final AccountTypeManager mAccountTypes;
58558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki
59558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki    private ContactEditorUtils(Context context) {
60558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki        this(context, AccountTypeManager.getInstance(context));
61558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki    }
62558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki
63558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki    @VisibleForTesting
64558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki    ContactEditorUtils(Context context, AccountTypeManager accountTypes) {
6542342a7e91b5076bc222802379e12b56272ca366Makoto Onuki        mContext = context.getApplicationContext();
66558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki        mPrefs = PreferenceManager.getDefaultSharedPreferences(mContext);
67558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki        mAccountTypes = accountTypes;
68558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki    }
69558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki
70558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki    public static synchronized ContactEditorUtils getInstance(Context context) {
71558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki        if (sInstance == null) {
72558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki            sInstance = new ContactEditorUtils(context);
73558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki        }
74558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki        return sInstance;
75558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki    }
76558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki
77558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki    void cleanupForTest() {
78558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki        mPrefs.edit().remove(KEY_DEFAULT_ACCOUNT).remove(KEY_KNOWN_ACCOUNTS)
79558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki                .remove(KEY_ANYTHING_SAVED).apply();
80558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki    }
81558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki
82131e6ac666868645b48ae6932575d85751ff57c0Makoto Onuki    void removeDefaultAccountForTest() {
83131e6ac666868645b48ae6932575d85751ff57c0Makoto Onuki        mPrefs.edit().remove(KEY_DEFAULT_ACCOUNT).apply();
84131e6ac666868645b48ae6932575d85751ff57c0Makoto Onuki    }
85131e6ac666868645b48ae6932575d85751ff57c0Makoto Onuki
86131e6ac666868645b48ae6932575d85751ff57c0Makoto Onuki    /**
87131e6ac666868645b48ae6932575d85751ff57c0Makoto Onuki     * Sets the {@link #KEY_KNOWN_ACCOUNTS} and {@link #KEY_DEFAULT_ACCOUNT} preference values to
88131e6ac666868645b48ae6932575d85751ff57c0Makoto Onuki     * empty strings to reset the state of the preferences file.
89131e6ac666868645b48ae6932575d85751ff57c0Makoto Onuki     */
90131e6ac666868645b48ae6932575d85751ff57c0Makoto Onuki    private void resetPreferenceValues() {
91131e6ac666868645b48ae6932575d85751ff57c0Makoto Onuki        mPrefs.edit().putString(KEY_KNOWN_ACCOUNTS, "").putString(KEY_DEFAULT_ACCOUNT, "").apply();
92131e6ac666868645b48ae6932575d85751ff57c0Makoto Onuki    }
93131e6ac666868645b48ae6932575d85751ff57c0Makoto Onuki
94558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki    private List<AccountWithDataSet> getWritableAccounts() {
95558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki        return mAccountTypes.getAccounts(true);
96558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki    }
97558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki
98558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki    /**
99558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki     * @return true if it's the first launch and {@link #saveDefaultAndAllAccounts} has never
100558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki     *     been called.
101558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki     */
102558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki    private boolean isFirstLaunch() {
103558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki        return !mPrefs.getBoolean(KEY_ANYTHING_SAVED, false);
104558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki    }
105558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki
106558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki    /**
107558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki     * Saves all writable accounts and the default account, which can later be obtained
108558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki     * with {@link #getDefaultAccount}.
109558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki     *
110558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki     * This should be called when saving a newly created contact.
111558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki     *
112558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki     * @param defaultAccount the account used to save a newly created contact.  Or pass {@code null}
113558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki     *     If the user selected "local only".
114558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki     */
115558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki    public void saveDefaultAndAllAccounts(AccountWithDataSet defaultAccount) {
116131e6ac666868645b48ae6932575d85751ff57c0Makoto Onuki        final SharedPreferences.Editor editor = mPrefs.edit()
117131e6ac666868645b48ae6932575d85751ff57c0Makoto Onuki                .putBoolean(KEY_ANYTHING_SAVED, true);
118131e6ac666868645b48ae6932575d85751ff57c0Makoto Onuki
119131e6ac666868645b48ae6932575d85751ff57c0Makoto Onuki        if (defaultAccount == null) {
120131e6ac666868645b48ae6932575d85751ff57c0Makoto Onuki            // If the default is "local only", there should be no writable accounts.
121131e6ac666868645b48ae6932575d85751ff57c0Makoto Onuki            // This should always be the case with our spec, but because we load the account list
122131e6ac666868645b48ae6932575d85751ff57c0Makoto Onuki            // asynchronously using a worker thread, it is possible that there are accounts at this
123131e6ac666868645b48ae6932575d85751ff57c0Makoto Onuki            // point. So if the default is null always clear the account list.
124131e6ac666868645b48ae6932575d85751ff57c0Makoto Onuki            editor.putString(KEY_KNOWN_ACCOUNTS, "");
125131e6ac666868645b48ae6932575d85751ff57c0Makoto Onuki            editor.putString(KEY_DEFAULT_ACCOUNT, "");
126131e6ac666868645b48ae6932575d85751ff57c0Makoto Onuki        } else {
127131e6ac666868645b48ae6932575d85751ff57c0Makoto Onuki            editor.putString(KEY_KNOWN_ACCOUNTS,
128131e6ac666868645b48ae6932575d85751ff57c0Makoto Onuki                    AccountWithDataSet.stringifyList(getWritableAccounts()));
129131e6ac666868645b48ae6932575d85751ff57c0Makoto Onuki            editor.putString(KEY_DEFAULT_ACCOUNT, defaultAccount.stringify());
130131e6ac666868645b48ae6932575d85751ff57c0Makoto Onuki        }
131131e6ac666868645b48ae6932575d85751ff57c0Makoto Onuki        editor.apply();
132558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki    }
133558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki
134558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki    /**
135558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki     * @return the default account saved with {@link #saveDefaultAndAllAccounts}.
136558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki     *
137558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki     * Note the {@code null} return value can mean either {@link #saveDefaultAndAllAccounts} has
138558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki     * never been called, or {@code null} was passed to {@link #saveDefaultAndAllAccounts} --
139558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki     * i.e. the user selected "local only".
140558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki     *
141558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki     * Also note that the returned account may have been removed already.
142558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki     */
143558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki    public AccountWithDataSet getDefaultAccount() {
144558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki        final String saved = mPrefs.getString(KEY_DEFAULT_ACCOUNT, null);
145558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki        if (TextUtils.isEmpty(saved)) {
146558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki            return null;
147558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki        }
148131e6ac666868645b48ae6932575d85751ff57c0Makoto Onuki        try {
149131e6ac666868645b48ae6932575d85751ff57c0Makoto Onuki            return AccountWithDataSet.unstringify(saved);
150131e6ac666868645b48ae6932575d85751ff57c0Makoto Onuki        } catch (IllegalArgumentException exception) {
151131e6ac666868645b48ae6932575d85751ff57c0Makoto Onuki            Log.e(TAG, "Error with retrieving default account " + exception.toString());
152131e6ac666868645b48ae6932575d85751ff57c0Makoto Onuki            // unstringify()can throw an exception if the string is not in an expected format.
153131e6ac666868645b48ae6932575d85751ff57c0Makoto Onuki            // Hence, if the preferences file is corrupt, just reset the preference values
154131e6ac666868645b48ae6932575d85751ff57c0Makoto Onuki            resetPreferenceValues();
155131e6ac666868645b48ae6932575d85751ff57c0Makoto Onuki            return null;
156131e6ac666868645b48ae6932575d85751ff57c0Makoto Onuki        }
157558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki    }
158558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki
159558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki    /**
160558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki     * @return true if an account still exists.  {@code null} is considered "local only" here,
161558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki     *    so it's valid too.
162558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki     */
163558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki    @VisibleForTesting
164558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki    boolean isValidAccount(AccountWithDataSet account) {
165558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki        if (account == null) {
166558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki            return true; // It's "local only" account, which is valid.
167558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki        }
168558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki        return getWritableAccounts().contains(account);
169558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki    }
170558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki
171558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki    /**
172558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki     * @return saved known accounts, or an empty list if none has been saved yet.
173558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki     */
174558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki    @VisibleForTesting
175558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki    List<AccountWithDataSet> getSavedAccounts() {
176558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki        final String saved = mPrefs.getString(KEY_KNOWN_ACCOUNTS, null);
177558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki        if (TextUtils.isEmpty(saved)) {
178558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki            return EMPTY_ACCOUNTS;
179558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki        }
180131e6ac666868645b48ae6932575d85751ff57c0Makoto Onuki        try {
181131e6ac666868645b48ae6932575d85751ff57c0Makoto Onuki            return AccountWithDataSet.unstringifyList(saved);
182131e6ac666868645b48ae6932575d85751ff57c0Makoto Onuki        } catch (IllegalArgumentException exception) {
183131e6ac666868645b48ae6932575d85751ff57c0Makoto Onuki            Log.e(TAG, "Error with retrieving saved accounts " + exception.toString());
184131e6ac666868645b48ae6932575d85751ff57c0Makoto Onuki            // unstringifyList()can throw an exception if the string is not in an expected format.
185131e6ac666868645b48ae6932575d85751ff57c0Makoto Onuki            // Hence, if the preferences file is corrupt, just reset the preference values
186131e6ac666868645b48ae6932575d85751ff57c0Makoto Onuki            resetPreferenceValues();
187131e6ac666868645b48ae6932575d85751ff57c0Makoto Onuki            return EMPTY_ACCOUNTS;
188131e6ac666868645b48ae6932575d85751ff57c0Makoto Onuki        }
189558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki    }
190558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki
191558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki    /**
192558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki     * @return true if the contact editor should show the "accounts changed" notification, that is:
193558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki     * - If it's the first launch.
194558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki     * - Or, if an account has been added.
195558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki     * - Or, if the default account has been removed.
196131e6ac666868645b48ae6932575d85751ff57c0Makoto Onuki     * (And some extra sanity check)
197558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki     *
198558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki     * Note if this method returns {@code false}, the caller can safely assume that
199558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki     * {@link #getDefaultAccount} will return a valid account.  (Either an account which still
200558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki     * exists, or {@code null} which should be interpreted as "local only".)
201558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki     */
202558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki    public boolean shouldShowAccountChangedNotification() {
203558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki        if (isFirstLaunch()) {
204558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki            return true;
205558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki        }
206558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki
207558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki        // Account added?
208558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki        final List<AccountWithDataSet> savedAccounts = getSavedAccounts();
209131e6ac666868645b48ae6932575d85751ff57c0Makoto Onuki        final List<AccountWithDataSet> currentWritableAccounts = getWritableAccounts();
210131e6ac666868645b48ae6932575d85751ff57c0Makoto Onuki        for (AccountWithDataSet account : currentWritableAccounts) {
211558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki            if (!savedAccounts.contains(account)) {
212558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki                return true; // New account found.
213558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki            }
214558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki        }
215558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki
216131e6ac666868645b48ae6932575d85751ff57c0Makoto Onuki        final AccountWithDataSet defaultAccount = getDefaultAccount();
217131e6ac666868645b48ae6932575d85751ff57c0Makoto Onuki
218558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki        // Does default account still exist?
219131e6ac666868645b48ae6932575d85751ff57c0Makoto Onuki        if (!isValidAccount(defaultAccount)) {
220131e6ac666868645b48ae6932575d85751ff57c0Makoto Onuki            return true;
221131e6ac666868645b48ae6932575d85751ff57c0Makoto Onuki        }
222131e6ac666868645b48ae6932575d85751ff57c0Makoto Onuki
223131e6ac666868645b48ae6932575d85751ff57c0Makoto Onuki        // If there is an inconsistent state in the preferences file - default account is null
224131e6ac666868645b48ae6932575d85751ff57c0Makoto Onuki        // ("local" account) while there are multiple accounts, then show the notification dialog.
225131e6ac666868645b48ae6932575d85751ff57c0Makoto Onuki        // This shouldn't ever happen, but this should allow the user can get back into a normal
226131e6ac666868645b48ae6932575d85751ff57c0Makoto Onuki        // state after they respond to the notification.
227131e6ac666868645b48ae6932575d85751ff57c0Makoto Onuki        if (defaultAccount == null && currentWritableAccounts.size() > 0) {
228131e6ac666868645b48ae6932575d85751ff57c0Makoto Onuki            Log.e(TAG, "Preferences file in an inconsistent state, request that the default account"
229131e6ac666868645b48ae6932575d85751ff57c0Makoto Onuki                    + " and current writable accounts be saved again");
230558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki            return true;
231558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki        }
232558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki
233558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki        // All good.
234558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki        return false;
235558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki    }
236558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki
237558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki    @VisibleForTesting
238558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki    String[] getWritableAccountTypeStrings() {
239558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki        final Set<String> types = Sets.newHashSet();
240558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki        for (AccountType type : mAccountTypes.getAccountTypes(true)) {
241558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki            types.add(type.accountType);
242558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki        }
243558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki        return types.toArray(new String[types.size()]);
244558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki    }
245558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki
246558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki    /**
247558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki     * Create an {@link Intent} to start "add new account" setup wizard.  Selectable account
248558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki     * types will be limited to ones that supports editing contacts.
249558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki     *
250558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki     * Use {@link Activity#startActivityForResult} or
251558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki     * {@link android.app.Fragment#startActivityForResult} to start the wizard, and
252558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki     * {@link Activity#onActivityResult} or {@link android.app.Fragment#onActivityResult} to
253558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki     * get the result.
254558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki     */
255558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki    public Intent createAddWritableAccountIntent() {
256558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki        return AccountManager.newChooseAccountIntent(
257558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki                null, // selectedAccount
258558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki                new ArrayList<Account>(), // allowableAccounts
259558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki                getWritableAccountTypeStrings(), // allowableAccountTypes
260558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki                false, // alwaysPromptForAccount
261558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki                null, // descriptionOverrideText
262558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki                null, // addAccountAuthTokenType
263558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki                null, // addAccountRequiredFeatures
264558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki                null // addAccountOptions
265558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki                );
266558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki    }
267558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki
268558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki    /**
269558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki     * Parses a result from {@link #createAddWritableAccountIntent} and returns the created
270558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki     * {@link Account}, or null if the user has canceled the wizard.  Pass the {@code resultCode}
271558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki     * and {@code data} parameters passed to {@link Activity#onActivityResult} or
272558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki     * {@link android.app.Fragment#onActivityResult}.
273558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki     *
274558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki     * Note although the return type is {@link AccountWithDataSet}, return values from this method
275558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki     * will never have {@link AccountWithDataSet#dataSet} set, as there's no way to create an
276558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki     * extension package account from setup wizard.
277558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki     */
278558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki    public AccountWithDataSet getCreatedAccount(int resultCode, Intent resultData) {
279558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki        // Javadoc doesn't say anything about resultCode but that the data intent will be non null
280558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki        // on success.
281558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki        if (resultData == null) return null;
282558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki
283558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki        final String accountType = resultData.getStringExtra(AccountManager.KEY_ACCOUNT_TYPE);
284558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki        final String accountName = resultData.getStringExtra(AccountManager.KEY_ACCOUNT_NAME);
285558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki
286558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki        // Just in case
287558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki        if (TextUtils.isEmpty(accountType) || TextUtils.isEmpty(accountName)) return null;
288558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki
289558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki        return new AccountWithDataSet(accountName, accountType, null);
290558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki    }
291558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki}
292