• 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 android.accounts.AccountManager;
20 import android.accounts.AuthenticatorDescription;
21 import android.content.ContentResolver;
22 import android.content.Context;
23 import android.content.Intent;
24 import android.content.SyncAdapterType;
25 import android.content.pm.PackageManager;
26 import android.content.res.Resources;
27 import android.graphics.drawable.Drawable;
28 import android.os.Bundle;
29 import android.preference.Preference;
30 import android.preference.PreferenceActivity;
31 import android.preference.PreferenceGroup;
32 import android.preference.PreferenceScreen;
33 import android.util.Log;
34 import com.android.internal.util.CharSequences;
35 import com.android.settings.R;
36 import com.google.android.collect.Maps;
37 
38 import java.util.ArrayList;
39 import java.util.Collections;
40 import java.util.HashMap;
41 import java.util.HashSet;
42 import java.util.Map;
43 
44 /**
45  * Activity asking a user to select an account to be set up.
46  */
47 public class ChooseAccountActivity extends PreferenceActivity {
48 
49     private static final String TAG = "ChooseAccountActivity";
50     private String[] mAuthorities;
51     private PreferenceGroup mAddAccountGroup;
52     private final ArrayList<ProviderEntry> mProviderList = new ArrayList<ProviderEntry>();
53     public HashSet<String> mAccountTypesFilter;
54     private AuthenticatorDescription[] mAuthDescs;
55     private HashMap<String, ArrayList<String>> mAccountTypeToAuthorities = null;
56     private Map<String, AuthenticatorDescription> mTypeToAuthDescription
57             = new HashMap<String, AuthenticatorDescription>();
58 
59     private static class ProviderEntry implements Comparable<ProviderEntry> {
60         private final CharSequence name;
61         private final String type;
ProviderEntry(CharSequence providerName, String accountType)62         ProviderEntry(CharSequence providerName, String accountType) {
63             name = providerName;
64             type = accountType;
65         }
66 
compareTo(ProviderEntry another)67         public int compareTo(ProviderEntry another) {
68             if (name == null) {
69                 return -1;
70             }
71             if (another.name == null) {
72                 return +1;
73             }
74             return CharSequences.compareToIgnoreCase(name, another.name);
75         }
76     }
77 
78     @Override
onCreate(Bundle icicle)79     protected void onCreate(Bundle icicle) {
80         super.onCreate(icicle);
81 
82         setContentView(R.layout.add_account_screen);
83         addPreferencesFromResource(R.xml.add_account_settings);
84         mAuthorities = getIntent().getStringArrayExtra(
85                 AccountPreferenceBase.AUTHORITIES_FILTER_KEY);
86         String[] accountTypesFilter = getIntent().getStringArrayExtra(
87                 AccountPreferenceBase.ACCOUNT_TYPES_FILTER_KEY);
88         if (accountTypesFilter != null) {
89             mAccountTypesFilter = new HashSet<String>();
90             for (String accountType : accountTypesFilter) {
91                 mAccountTypesFilter.add(accountType);
92             }
93         }
94         mAddAccountGroup = getPreferenceScreen();
95         updateAuthDescriptions();
96     }
97 
98     /**
99      * Updates provider icons. Subclasses should call this in onCreate()
100      * and update any UI that depends on AuthenticatorDescriptions in onAuthDescriptionsUpdated().
101      */
updateAuthDescriptions()102     private void updateAuthDescriptions() {
103         mAuthDescs = AccountManager.get(this).getAuthenticatorTypes();
104         for (int i = 0; i < mAuthDescs.length; i++) {
105             mTypeToAuthDescription.put(mAuthDescs[i].type, mAuthDescs[i]);
106         }
107         onAuthDescriptionsUpdated();
108     }
109 
onAuthDescriptionsUpdated()110     private void onAuthDescriptionsUpdated() {
111         // Create list of providers to show on preference screen
112         for (int i = 0; i < mAuthDescs.length; i++) {
113             String accountType = mAuthDescs[i].type;
114             CharSequence providerName = getLabelForType(accountType);
115 
116             // Skip preferences for authorities not specified. If no authorities specified,
117             // then include them all.
118             ArrayList<String> accountAuths = getAuthoritiesForAccountType(accountType);
119             boolean addAccountPref = true;
120             if (mAuthorities != null && mAuthorities.length > 0 && accountAuths != null) {
121                 addAccountPref = false;
122                 for (int k = 0; k < mAuthorities.length; k++) {
123                     if (accountAuths.contains(mAuthorities[k])) {
124                         addAccountPref = true;
125                         break;
126                     }
127                 }
128             }
129             if (addAccountPref && mAccountTypesFilter != null
130                     && !mAccountTypesFilter.contains(accountType)) {
131                 addAccountPref = false;
132             }
133             if (addAccountPref) {
134                 mProviderList.add(new ProviderEntry(providerName, accountType));
135             } else {
136                 if (Log.isLoggable(TAG, Log.VERBOSE)) {
137                     Log.v(TAG, "Skipped pref " + providerName + ": has no authority we need");
138                 }
139             }
140         }
141 
142         if (mProviderList.size() == 1) {
143             // If there's only one provider that matches, just run it.
144             finishWithAccountType(mProviderList.get(0).type);
145         } else if (mProviderList.size() > 0) {
146             Collections.sort(mProviderList);
147             mAddAccountGroup.removeAll();
148             for (ProviderEntry pref : mProviderList) {
149                 Drawable drawable = getDrawableForType(pref.type);
150                 ProviderPreference p =
151                         new ProviderPreference(this, pref.type, drawable, pref.name);
152                 mAddAccountGroup.addPreference(p);
153             }
154         } else {
155             if (Log.isLoggable(TAG, Log.VERBOSE)) {
156                 final StringBuilder auths = new StringBuilder();
157                 for (String a : mAuthorities) {
158                     auths.append(a);
159                     auths.append(' ');
160                 }
161                 Log.v(TAG, "No providers found for authorities: " + auths);
162             }
163             setResult(RESULT_CANCELED);
164             finish();
165         }
166     }
167 
getAuthoritiesForAccountType(String type)168     public ArrayList<String> getAuthoritiesForAccountType(String type) {
169         if (mAccountTypeToAuthorities == null) {
170             mAccountTypeToAuthorities = Maps.newHashMap();
171             SyncAdapterType[] syncAdapters = ContentResolver.getSyncAdapterTypes();
172             for (int i = 0, n = syncAdapters.length; i < n; i++) {
173                 final SyncAdapterType sa = syncAdapters[i];
174                 ArrayList<String> authorities = mAccountTypeToAuthorities.get(sa.accountType);
175                 if (authorities == null) {
176                     authorities = new ArrayList<String>();
177                     mAccountTypeToAuthorities.put(sa.accountType, authorities);
178                 }
179                 if (Log.isLoggable(TAG, Log.VERBOSE)) {
180                     Log.d(TAG, "added authority " + sa.authority + " to accountType "
181                             + sa.accountType);
182                 }
183                 authorities.add(sa.authority);
184             }
185         }
186         return mAccountTypeToAuthorities.get(type);
187     }
188 
189     /**
190      * Gets an icon associated with a particular account type. If none found, return null.
191      * @param accountType the type of account
192      * @return a drawable for the icon or null if one cannot be found.
193      */
getDrawableForType(final String accountType)194     protected Drawable getDrawableForType(final String accountType) {
195         Drawable icon = null;
196         if (mTypeToAuthDescription.containsKey(accountType)) {
197             try {
198                 AuthenticatorDescription desc = mTypeToAuthDescription.get(accountType);
199                 Context authContext = createPackageContext(desc.packageName, 0);
200                 icon = authContext.getResources().getDrawable(desc.iconId);
201             } catch (PackageManager.NameNotFoundException e) {
202                 // TODO: place holder icon for missing account icons?
203                 Log.w(TAG, "No icon name for account type " + accountType);
204             } catch (Resources.NotFoundException e) {
205                 // TODO: place holder icon for missing account icons?
206                 Log.w(TAG, "No icon resource for account type " + accountType);
207             }
208         }
209         return icon;
210     }
211 
212     /**
213      * Gets the label associated with a particular account type. If none found, return null.
214      * @param accountType the type of account
215      * @return a CharSequence for the label or null if one cannot be found.
216      */
getLabelForType(final String accountType)217     protected CharSequence getLabelForType(final String accountType) {
218         CharSequence label = null;
219         if (mTypeToAuthDescription.containsKey(accountType)) {
220             try {
221                 AuthenticatorDescription desc = mTypeToAuthDescription.get(accountType);
222                 Context authContext = createPackageContext(desc.packageName, 0);
223                 label = authContext.getResources().getText(desc.labelId);
224             } catch (PackageManager.NameNotFoundException e) {
225                 Log.w(TAG, "No label name for account type " + accountType);
226             } catch (Resources.NotFoundException e) {
227                 Log.w(TAG, "No label resource for account type " + accountType);
228             }
229         }
230         return label;
231     }
232 
233     @Override
onPreferenceTreeClick(PreferenceScreen preferences, Preference preference)234     public boolean onPreferenceTreeClick(PreferenceScreen preferences, Preference preference) {
235         if (preference instanceof ProviderPreference) {
236             ProviderPreference pref = (ProviderPreference) preference;
237             if (Log.isLoggable(TAG, Log.VERBOSE)) {
238                 Log.v(TAG, "Attempting to add account of type " + pref.getAccountType());
239             }
240             finishWithAccountType(pref.getAccountType());
241         }
242         return true;
243     }
244 
finishWithAccountType(String accountType)245     private void finishWithAccountType(String accountType) {
246         Intent intent = new Intent();
247         intent.putExtra(AddAccountSettings.EXTRA_SELECTED_ACCOUNT, accountType);
248         setResult(RESULT_OK, intent);
249         finish();
250     }
251 }
252