1d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler/*
2d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler * Copyright (C) 2015 The Android Open Source Project
3d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler *
4d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler * Licensed under the Apache License, Version 2.0 (the "License");
5d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler * you may not use this file except in compliance with the License.
6d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler * You may obtain a copy of the License at
7d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler *
8d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler *      http://www.apache.org/licenses/LICENSE-2.0
9d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler *
10d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler * Unless required by applicable law or agreed to in writing, software
11d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler * distributed under the License is distributed on an "AS IS" BASIS,
12d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler * See the License for the specific language governing permissions and
14d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler * limitations under the License
15d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler */
16d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler
17d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantlerpackage com.android.settingslib.accounts;
18d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler
19d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantlerimport android.accounts.Account;
20d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantlerimport android.accounts.AccountManager;
21d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantlerimport android.accounts.AuthenticatorDescription;
22d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantlerimport android.content.BroadcastReceiver;
23d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantlerimport android.content.ContentResolver;
24d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantlerimport android.content.Context;
25d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantlerimport android.content.Intent;
26d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantlerimport android.content.IntentFilter;
27d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantlerimport android.content.SyncAdapterType;
28d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantlerimport android.content.pm.PackageManager;
29d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantlerimport android.content.res.Resources;
30d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantlerimport android.graphics.drawable.Drawable;
31d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantlerimport android.os.AsyncTask;
32d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantlerimport android.os.UserHandle;
33d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantlerimport android.util.Log;
34d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler
35d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantlerimport java.util.ArrayList;
36d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantlerimport java.util.HashMap;
37d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantlerimport java.util.Map;
38d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler
39d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler/**
40d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler * Helper class for monitoring accounts on the device for a given user.
41d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler *
42d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler * Classes using this helper should implement {@link OnAccountsUpdateListener}.
43d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler * {@link OnAccountsUpdateListener#onAccountsUpdate(UserHandle)} will then be
44d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler * called once accounts get updated. For setting up listening for account
45d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler * updates, {@link #listenToAccountUpdates()} and
46d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler * {@link #stopListeningToAccountUpdates()} should be used.
47d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler */
48d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantlerfinal public class AuthenticatorHelper extends BroadcastReceiver {
49d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler    private static final String TAG = "AuthenticatorHelper";
50d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler
51d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler    private final Map<String, AuthenticatorDescription> mTypeToAuthDescription = new HashMap<>();
52d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler    private final ArrayList<String> mEnabledAccountTypes = new ArrayList<>();
53d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler    private final Map<String, Drawable> mAccTypeIconCache = new HashMap<>();
54d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler    private final HashMap<String, ArrayList<String>> mAccountTypeToAuthorities = new HashMap<>();
55d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler
56d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler    private final UserHandle mUserHandle;
57d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler    private final Context mContext;
58d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler    private final OnAccountsUpdateListener mListener;
59d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler    private boolean mListeningToAccountUpdates;
60d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler
61d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler    public interface OnAccountsUpdateListener {
62d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler        void onAccountsUpdate(UserHandle userHandle);
63d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler    }
64d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler
65d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler    public AuthenticatorHelper(Context context, UserHandle userHandle,
66d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler            OnAccountsUpdateListener listener) {
67d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler        mContext = context;
68d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler        mUserHandle = userHandle;
69d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler        mListener = listener;
70d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler        // This guarantees that the helper is ready to use once constructed: the account types and
71d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler        // authorities are initialized
72d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler        onAccountsUpdated(null);
73d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler    }
74d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler
75d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler    public String[] getEnabledAccountTypes() {
76d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler        return mEnabledAccountTypes.toArray(new String[mEnabledAccountTypes.size()]);
77d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler    }
78d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler
79d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler    public void preloadDrawableForType(final Context context, final String accountType) {
80d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler        new AsyncTask<Void, Void, Void>() {
81d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler            @Override
82d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler            protected Void doInBackground(Void... params) {
83d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler                getDrawableForType(context, accountType);
84d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler                return null;
85d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler            }
86d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler        }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[]) null);
87d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler    }
88d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler
89d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler    /**
90d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler     * Gets an icon associated with a particular account type. If none found, return null.
91d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler     * @param accountType the type of account
92d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler     * @return a drawable for the icon or a default icon returned by
93d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler     * {@link PackageManager#getDefaultActivityIcon} if one cannot be found.
94d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler     */
95d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler    public Drawable getDrawableForType(Context context, final String accountType) {
96d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler        Drawable icon = null;
97d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler        synchronized (mAccTypeIconCache) {
98d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler            if (mAccTypeIconCache.containsKey(accountType)) {
99d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler                return mAccTypeIconCache.get(accountType);
100d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler            }
101d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler        }
102d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler        if (mTypeToAuthDescription.containsKey(accountType)) {
103d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler            try {
104d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler                AuthenticatorDescription desc = mTypeToAuthDescription.get(accountType);
105d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler                Context authContext = context.createPackageContextAsUser(desc.packageName, 0,
106d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler                        mUserHandle);
107d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler                icon = mContext.getPackageManager().getUserBadgedIcon(
108d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler                        authContext.getDrawable(desc.iconId), mUserHandle);
109d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler                synchronized (mAccTypeIconCache) {
110d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler                    mAccTypeIconCache.put(accountType, icon);
111d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler                }
112d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler            } catch (PackageManager.NameNotFoundException|Resources.NotFoundException e) {
113d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler                // Ignore
114d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler            }
115d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler        }
116d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler        if (icon == null) {
117d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler            icon = context.getPackageManager().getDefaultActivityIcon();
118d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler        }
119d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler        return icon;
120d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler    }
121d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler
122d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler    /**
123d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler     * Gets the label associated with a particular account type. If none found, return null.
124d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler     * @param accountType the type of account
125d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler     * @return a CharSequence for the label or null if one cannot be found.
126d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler     */
127d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler    public CharSequence getLabelForType(Context context, final String accountType) {
128d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler        CharSequence label = null;
129d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler        if (mTypeToAuthDescription.containsKey(accountType)) {
130d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler            try {
131d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler                AuthenticatorDescription desc = mTypeToAuthDescription.get(accountType);
132d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler                Context authContext = context.createPackageContextAsUser(desc.packageName, 0,
133d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler                        mUserHandle);
134d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler                label = authContext.getResources().getText(desc.labelId);
135d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler            } catch (PackageManager.NameNotFoundException e) {
136d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler                Log.w(TAG, "No label name for account type " + accountType);
137d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler            } catch (Resources.NotFoundException e) {
138d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler                Log.w(TAG, "No label icon for account type " + accountType);
139d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler            }
140d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler        }
141d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler        return label;
142d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler    }
143d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler
144d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler    /**
145d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler     * Gets the package associated with a particular account type. If none found, return null.
146d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler     * @param accountType the type of account
147d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler     * @return the package name or null if one cannot be found.
148d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler     */
149d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler    public String getPackageForType(final String accountType) {
150d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler        if (mTypeToAuthDescription.containsKey(accountType)) {
151d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler            AuthenticatorDescription desc = mTypeToAuthDescription.get(accountType);
152d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler            return desc.packageName;
153d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler        }
154d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler        return null;
155d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler    }
156d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler
157d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler    /**
158d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler     * Gets the resource id of the label associated with a particular account type. If none found,
159d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler     * return -1.
160d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler     * @param accountType the type of account
161d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler     * @return a resource id for the label or -1 if none found;
162d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler     */
163d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler    public int getLabelIdForType(final String accountType) {
164d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler        if (mTypeToAuthDescription.containsKey(accountType)) {
165d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler            AuthenticatorDescription desc = mTypeToAuthDescription.get(accountType);
166d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler            return desc.labelId;
167d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler        }
168d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler        return -1;
169d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler    }
170d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler
171d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler    /**
172d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler     * Updates provider icons. Subclasses should call this in onCreate()
173d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler     * and update any UI that depends on AuthenticatorDescriptions in onAuthDescriptionsUpdated().
174d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler     */
175d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler    public void updateAuthDescriptions(Context context) {
176d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler        AuthenticatorDescription[] authDescs = AccountManager.get(context)
177d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler                .getAuthenticatorTypesAsUser(mUserHandle.getIdentifier());
178d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler        for (int i = 0; i < authDescs.length; i++) {
179d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler            mTypeToAuthDescription.put(authDescs[i].type, authDescs[i]);
180d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler        }
181d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler    }
182d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler
183d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler    public boolean containsAccountType(String accountType) {
184d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler        return mTypeToAuthDescription.containsKey(accountType);
185d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler    }
186d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler
187d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler    public AuthenticatorDescription getAccountTypeDescription(String accountType) {
188d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler        return mTypeToAuthDescription.get(accountType);
189d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler    }
190d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler
191d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler    public boolean hasAccountPreferences(final String accountType) {
192d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler        if (containsAccountType(accountType)) {
193d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler            AuthenticatorDescription desc = getAccountTypeDescription(accountType);
194d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler            if (desc != null && desc.accountPreferencesId != 0) {
195d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler                return true;
196d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler            }
197d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler        }
198d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler        return false;
199d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler    }
200d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler
201d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler    void onAccountsUpdated(Account[] accounts) {
202d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler        updateAuthDescriptions(mContext);
203d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler        if (accounts == null) {
204d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler            accounts = AccountManager.get(mContext).getAccountsAsUser(mUserHandle.getIdentifier());
205d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler        }
206d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler        mEnabledAccountTypes.clear();
207d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler        mAccTypeIconCache.clear();
208d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler        for (int i = 0; i < accounts.length; i++) {
209d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler            final Account account = accounts[i];
210d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler            if (!mEnabledAccountTypes.contains(account.type)) {
211d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler                mEnabledAccountTypes.add(account.type);
212d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler            }
213d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler        }
214d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler        buildAccountTypeToAuthoritiesMap();
215d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler        if (mListeningToAccountUpdates) {
216d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler            mListener.onAccountsUpdate(mUserHandle);
217d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler        }
218d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler    }
219d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler
220d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler    @Override
221d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler    public void onReceive(final Context context, final Intent intent) {
222d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler        // TODO: watch for package upgrades to invalidate cache; see http://b/7206643
223d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler        final Account[] accounts = AccountManager.get(mContext)
224d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler                .getAccountsAsUser(mUserHandle.getIdentifier());
225d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler        onAccountsUpdated(accounts);
226d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler    }
227d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler
228d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler    public void listenToAccountUpdates() {
229d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler        if (!mListeningToAccountUpdates) {
230d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler            IntentFilter intentFilter = new IntentFilter();
231d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler            intentFilter.addAction(AccountManager.LOGIN_ACCOUNTS_CHANGED_ACTION);
232d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler            // At disk full, certain actions are blocked (such as writing the accounts to storage).
233d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler            // It is useful to also listen for recovery from disk full to avoid bugs.
234d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler            intentFilter.addAction(Intent.ACTION_DEVICE_STORAGE_OK);
235d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler            mContext.registerReceiverAsUser(this, mUserHandle, intentFilter, null, null);
236d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler            mListeningToAccountUpdates = true;
237d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler        }
238d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler    }
239d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler
240d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler    public void stopListeningToAccountUpdates() {
241d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler        if (mListeningToAccountUpdates) {
242d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler            mContext.unregisterReceiver(this);
243d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler            mListeningToAccountUpdates = false;
244d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler        }
245d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler    }
246d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler
247d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler    public ArrayList<String> getAuthoritiesForAccountType(String type) {
248d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler        return mAccountTypeToAuthorities.get(type);
249d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler    }
250d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler
251d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler    private void buildAccountTypeToAuthoritiesMap() {
252d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler        mAccountTypeToAuthorities.clear();
253d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler        SyncAdapterType[] syncAdapters = ContentResolver.getSyncAdapterTypesAsUser(
254d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler                mUserHandle.getIdentifier());
255d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler        for (int i = 0, n = syncAdapters.length; i < n; i++) {
256d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler            final SyncAdapterType sa = syncAdapters[i];
257d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler            ArrayList<String> authorities = mAccountTypeToAuthorities.get(sa.accountType);
258d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler            if (authorities == null) {
259d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler                authorities = new ArrayList<String>();
260d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler                mAccountTypeToAuthorities.put(sa.accountType, authorities);
261d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler            }
262d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler            if (Log.isLoggable(TAG, Log.VERBOSE)) {
263d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler                Log.v(TAG, "Added authority " + sa.authority + " to accountType "
264d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler                        + sa.accountType);
265d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler            }
266d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler            authorities.add(sa.authority);
267d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler        }
268d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler    }
269d1e32720441dd28a2ceed6a0d058f367e71421ecTony Mantler}
270