• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2010 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.settings.accounts;
18 
19 import static android.app.Activity.RESULT_CANCELED;
20 import static android.app.Activity.RESULT_OK;
21 import static android.content.Intent.EXTRA_USER;
22 
23 import android.accounts.AccountManager;
24 import android.accounts.AuthenticatorDescription;
25 import android.app.Activity;
26 import android.content.ContentResolver;
27 import android.content.Context;
28 import android.content.Intent;
29 import android.content.SyncAdapterType;
30 import android.content.pm.PackageManager;
31 import android.content.res.Resources;
32 import android.graphics.drawable.Drawable;
33 import android.os.Bundle;
34 import android.os.UserHandle;
35 import android.os.UserManager;
36 import android.support.v7.preference.Preference;
37 import android.support.v7.preference.PreferenceGroup;
38 import android.util.Log;
39 
40 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
41 import com.android.internal.util.CharSequences;
42 import com.android.settings.R;
43 import com.android.settings.SettingsPreferenceFragment;
44 import com.android.settings.Utils;
45 import com.android.settings.enterprise.EnterprisePrivacyFeatureProvider;
46 import com.android.settings.overlay.FeatureFactory;
47 import com.android.settings.widget.FooterPreference;
48 import com.android.settings.widget.FooterPreferenceMixin;
49 import com.android.settingslib.RestrictedLockUtils;
50 import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
51 
52 import com.google.android.collect.Maps;
53 
54 import java.util.ArrayList;
55 import java.util.Collections;
56 import java.util.HashMap;
57 import java.util.HashSet;
58 import java.util.Map;
59 
60 /**
61  * Activity asking a user to select an account to be set up.
62  *
63  * An extra {@link UserHandle} can be specified in the intent as {@link EXTRA_USER}, if the user for
64  * which the action needs to be performed is different to the one the Settings App will run in.
65  */
66 public class ChooseAccountActivity extends SettingsPreferenceFragment {
67 
68     private static final String TAG = "ChooseAccountActivity";
69 
70     private EnterprisePrivacyFeatureProvider mFeatureProvider;
71     private FooterPreference mEnterpriseDisclosurePreference = null;
72 
73     private String[] mAuthorities;
74     private PreferenceGroup mAddAccountGroup;
75     private final ArrayList<ProviderEntry> mProviderList = new ArrayList<ProviderEntry>();
76     public HashSet<String> mAccountTypesFilter;
77     private AuthenticatorDescription[] mAuthDescs;
78     private HashMap<String, ArrayList<String>> mAccountTypeToAuthorities = null;
79     private Map<String, AuthenticatorDescription> mTypeToAuthDescription
80             = new HashMap<String, AuthenticatorDescription>();
81     // The UserHandle of the user we are choosing an account for
82     private UserHandle mUserHandle;
83     private UserManager mUm;
84 
85     private static class ProviderEntry implements Comparable<ProviderEntry> {
86         private final CharSequence name;
87         private final String type;
ProviderEntry(CharSequence providerName, String accountType)88         ProviderEntry(CharSequence providerName, String accountType) {
89             name = providerName;
90             type = accountType;
91         }
92 
compareTo(ProviderEntry another)93         public int compareTo(ProviderEntry another) {
94             if (name == null) {
95                 return -1;
96             }
97             if (another.name == null) {
98                 return +1;
99             }
100             return CharSequences.compareToIgnoreCase(name, another.name);
101         }
102     }
103 
104     @Override
getMetricsCategory()105     public int getMetricsCategory() {
106         return MetricsEvent.ACCOUNTS_CHOOSE_ACCOUNT_ACTIVITY;
107     }
108 
109     @Override
onCreate(Bundle icicle)110     public void onCreate(Bundle icicle) {
111         super.onCreate(icicle);
112 
113         final Activity activity = getActivity();
114         mFeatureProvider = FeatureFactory.getFactory(activity)
115                 .getEnterprisePrivacyFeatureProvider(activity);
116 
117         addPreferencesFromResource(R.xml.add_account_settings);
118         mAuthorities = getIntent().getStringArrayExtra(
119                 AccountPreferenceBase.AUTHORITIES_FILTER_KEY);
120         String[] accountTypesFilter = getIntent().getStringArrayExtra(
121                 AccountPreferenceBase.ACCOUNT_TYPES_FILTER_KEY);
122         if (accountTypesFilter != null) {
123             mAccountTypesFilter = new HashSet<String>();
124             for (String accountType : accountTypesFilter) {
125                 mAccountTypesFilter.add(accountType);
126             }
127         }
128         mAddAccountGroup = getPreferenceScreen();
129         mUm = UserManager.get(getContext());
130         mUserHandle = Utils.getSecureTargetUser(getActivity().getActivityToken(), mUm,
131                 null /* arguments */, getIntent().getExtras());
132         updateAuthDescriptions();
133     }
134 
135     /**
136      * Updates provider icons. Subclasses should call this in onCreate()
137      * and update any UI that depends on AuthenticatorDescriptions in onAuthDescriptionsUpdated().
138      */
updateAuthDescriptions()139     private void updateAuthDescriptions() {
140         mAuthDescs = AccountManager.get(getContext()).getAuthenticatorTypesAsUser(
141                 mUserHandle.getIdentifier());
142         for (int i = 0; i < mAuthDescs.length; i++) {
143             mTypeToAuthDescription.put(mAuthDescs[i].type, mAuthDescs[i]);
144         }
145         onAuthDescriptionsUpdated();
146     }
147 
onAuthDescriptionsUpdated()148     private void onAuthDescriptionsUpdated() {
149         // Create list of providers to show on preference screen
150         for (int i = 0; i < mAuthDescs.length; i++) {
151             String accountType = mAuthDescs[i].type;
152             CharSequence providerName = getLabelForType(accountType);
153 
154             // Skip preferences for authorities not specified. If no authorities specified,
155             // then include them all.
156             ArrayList<String> accountAuths = getAuthoritiesForAccountType(accountType);
157             boolean addAccountPref = true;
158             if (mAuthorities != null && mAuthorities.length > 0 && accountAuths != null) {
159                 addAccountPref = false;
160                 for (int k = 0; k < mAuthorities.length; k++) {
161                     if (accountAuths.contains(mAuthorities[k])) {
162                         addAccountPref = true;
163                         break;
164                     }
165                 }
166             }
167             if (addAccountPref && mAccountTypesFilter != null
168                     && !mAccountTypesFilter.contains(accountType)) {
169                 addAccountPref = false;
170             }
171             if (addAccountPref) {
172                 mProviderList.add(new ProviderEntry(providerName, accountType));
173             } else {
174                 if (Log.isLoggable(TAG, Log.VERBOSE)) {
175                     Log.v(TAG, "Skipped pref " + providerName + ": has no authority we need");
176                 }
177             }
178         }
179 
180         final Context context = getPreferenceScreen().getContext();
181         if (mProviderList.size() == 1) {
182             // There's only one provider that matches. If it is disabled by admin show the
183             // support dialog otherwise run it.
184             EnforcedAdmin admin = RestrictedLockUtils.checkIfAccountManagementDisabled(
185                     context, mProviderList.get(0).type, mUserHandle.getIdentifier());
186             if (admin != null) {
187                 setResult(RESULT_CANCELED, RestrictedLockUtils.getShowAdminSupportDetailsIntent(
188                         context, admin));
189                 finish();
190             } else {
191                 finishWithAccountType(mProviderList.get(0).type);
192             }
193         } else if (mProviderList.size() > 0) {
194             Collections.sort(mProviderList);
195             mAddAccountGroup.removeAll();
196             for (ProviderEntry pref : mProviderList) {
197                 Drawable drawable = getDrawableForType(pref.type);
198                 ProviderPreference p = new ProviderPreference(getPreferenceScreen().getContext(),
199                         pref.type, drawable, pref.name);
200                 p.checkAccountManagementAndSetDisabled(mUserHandle.getIdentifier());
201                 mAddAccountGroup.addPreference(p);
202             }
203             addEnterpriseDisclosure();
204         } else {
205             if (Log.isLoggable(TAG, Log.VERBOSE)) {
206                 final StringBuilder auths = new StringBuilder();
207                 for (String a : mAuthorities) {
208                     auths.append(a);
209                     auths.append(' ');
210                 }
211                 Log.v(TAG, "No providers found for authorities: " + auths);
212             }
213             setResult(RESULT_CANCELED);
214             finish();
215         }
216     }
217 
addEnterpriseDisclosure()218     private void addEnterpriseDisclosure() {
219         final CharSequence disclosure = mFeatureProvider.getDeviceOwnerDisclosure();
220         if (disclosure == null) {
221             return;
222         }
223         if (mEnterpriseDisclosurePreference == null) {
224             mEnterpriseDisclosurePreference = mFooterPreferenceMixin.createFooterPreference();
225             mEnterpriseDisclosurePreference.setSelectable(false);
226         }
227         mEnterpriseDisclosurePreference.setTitle(disclosure);
228         mAddAccountGroup.addPreference(mEnterpriseDisclosurePreference);
229     }
230 
getAuthoritiesForAccountType(String type)231     public ArrayList<String> getAuthoritiesForAccountType(String type) {
232         if (mAccountTypeToAuthorities == null) {
233             mAccountTypeToAuthorities = Maps.newHashMap();
234             SyncAdapterType[] syncAdapters = ContentResolver.getSyncAdapterTypesAsUser(
235                     mUserHandle.getIdentifier());
236             for (int i = 0, n = syncAdapters.length; i < n; i++) {
237                 final SyncAdapterType sa = syncAdapters[i];
238                 ArrayList<String> authorities = mAccountTypeToAuthorities.get(sa.accountType);
239                 if (authorities == null) {
240                     authorities = new ArrayList<String>();
241                     mAccountTypeToAuthorities.put(sa.accountType, authorities);
242                 }
243                 if (Log.isLoggable(TAG, Log.VERBOSE)) {
244                     Log.d(TAG, "added authority " + sa.authority + " to accountType "
245                             + sa.accountType);
246                 }
247                 authorities.add(sa.authority);
248             }
249         }
250         return mAccountTypeToAuthorities.get(type);
251     }
252 
253     /**
254      * Gets an icon associated with a particular account type. If none found, return null.
255      * @param accountType the type of account
256      * @return a drawable for the icon or a default icon returned by
257      * {@link PackageManager#getDefaultActivityIcon} if one cannot be found.
258      */
getDrawableForType(final String accountType)259     protected Drawable getDrawableForType(final String accountType) {
260         Drawable icon = null;
261         if (mTypeToAuthDescription.containsKey(accountType)) {
262             try {
263                 AuthenticatorDescription desc = mTypeToAuthDescription.get(accountType);
264                 Context authContext = getActivity()
265                         .createPackageContextAsUser(desc.packageName, 0, mUserHandle);
266                 icon = getPackageManager().getUserBadgedIcon(
267                         authContext.getDrawable(desc.iconId), mUserHandle);
268             } catch (PackageManager.NameNotFoundException e) {
269                 Log.w(TAG, "No icon name for account type " + accountType);
270             } catch (Resources.NotFoundException e) {
271                 Log.w(TAG, "No icon resource for account type " + accountType);
272             }
273         }
274         if (icon != null) {
275             return icon;
276         } else {
277             return getPackageManager().getDefaultActivityIcon();
278         }
279     }
280 
281     /**
282      * Gets the label associated with a particular account type. If none found, return null.
283      * @param accountType the type of account
284      * @return a CharSequence for the label or null if one cannot be found.
285      */
getLabelForType(final String accountType)286     protected CharSequence getLabelForType(final String accountType) {
287         CharSequence label = null;
288         if (mTypeToAuthDescription.containsKey(accountType)) {
289             try {
290                 AuthenticatorDescription desc = mTypeToAuthDescription.get(accountType);
291                 Context authContext = getActivity()
292                         .createPackageContextAsUser(desc.packageName, 0, mUserHandle);
293                 label = authContext.getResources().getText(desc.labelId);
294             } catch (PackageManager.NameNotFoundException e) {
295                 Log.w(TAG, "No label name for account type " + accountType);
296             } catch (Resources.NotFoundException e) {
297                 Log.w(TAG, "No label resource for account type " + accountType);
298             }
299         }
300         return label;
301     }
302 
303     @Override
onPreferenceTreeClick(Preference preference)304     public boolean onPreferenceTreeClick(Preference preference) {
305         if (preference instanceof ProviderPreference) {
306             ProviderPreference pref = (ProviderPreference) preference;
307             if (Log.isLoggable(TAG, Log.VERBOSE)) {
308                 Log.v(TAG, "Attempting to add account of type " + pref.getAccountType());
309             }
310             finishWithAccountType(pref.getAccountType());
311         }
312         return true;
313     }
314 
finishWithAccountType(String accountType)315     private void finishWithAccountType(String accountType) {
316         Intent intent = new Intent();
317         intent.putExtra(AddAccountSettings.EXTRA_SELECTED_ACCOUNT, accountType);
318         intent.putExtra(EXTRA_USER, mUserHandle);
319         setResult(RESULT_OK, intent);
320         finish();
321     }
322 }
323