Home | History | Annotate | Download | only in accounts
      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;
     62         ProviderEntry(CharSequence providerName, String accountType) {
     63             name = providerName;
     64             type = accountType;
     65         }
     66 
     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
     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      */
    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 
    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 
    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      */
    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      */
    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
    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 
    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