• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 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.car.settings.accounts;
18 
19 import android.accounts.AccountManager;
20 import android.accounts.AuthenticatorDescription;
21 import android.app.ActivityManager;
22 import android.content.ContentResolver;
23 import android.content.Context;
24 import android.content.Intent;
25 import android.content.SyncAdapterType;
26 import android.content.pm.PackageManager;
27 import android.content.pm.UserInfo;
28 import android.content.res.Resources;
29 import android.graphics.drawable.Drawable;
30 import android.os.UserHandle;
31 import android.os.UserManager;
32 
33 import androidx.car.widget.ListItem;
34 import androidx.car.widget.ListItemProvider;
35 import androidx.car.widget.TextListItem;
36 
37 import com.android.car.settings.common.Logger;
38 import com.android.internal.util.CharSequences;
39 import com.android.settingslib.accounts.AuthenticatorHelper;
40 
41 import libcore.util.Nullable;
42 
43 import java.util.ArrayList;
44 import java.util.Collections;
45 import java.util.HashMap;
46 import java.util.List;
47 import java.util.Map;
48 
49 /**
50  * Implementation of ListItemProvider for the ChooseAccountFragment.
51  */
52 class ChooseAccountItemProvider extends ListItemProvider {
53     private static final Logger LOG = new Logger(ChooseAccountItemProvider.class);
54     private static final String AUTHORITIES_FILTER_KEY = "authorities";
55 
56     private final List<ListItem> mItems = new ArrayList<>();
57     private final Context mContext;
58     private final ChooseAccountFragment mFragment;
59     private final UserManager mUserManager;
60     private final ArrayList<ProviderEntry> mProviderList = new ArrayList<>();
61     @Nullable private AuthenticatorDescription[] mAuthDescs;
62     @Nullable private HashMap<String, ArrayList<String>> mAccountTypeToAuthorities;
63     private Map<String, AuthenticatorDescription> mTypeToAuthDescription = new HashMap<>();
64     private final AuthenticatorHelper mAuthenticatorHelper;
65 
66     // The UserHandle of the user we are choosing an account for
67     private final UserHandle mUserHandle;
68     private final String[] mAuthorities;
69 
ChooseAccountItemProvider(Context context, ChooseAccountFragment fragment)70     ChooseAccountItemProvider(Context context, ChooseAccountFragment fragment) {
71         mContext = context;
72         mFragment = fragment;
73         mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
74         mUserHandle =
75                 mUserManager.getUserInfo(ActivityManager.getCurrentUser()).getUserHandle();
76 
77         mAuthorities = fragment.getActivity().getIntent().getStringArrayExtra(
78                 AUTHORITIES_FILTER_KEY);
79 
80         // create auth helper
81         UserInfo currUserInfo = mUserManager.getUserInfo(ActivityManager.getCurrentUser());
82         mAuthenticatorHelper =
83                 new AuthenticatorHelper(mContext, currUserInfo.getUserHandle(), mFragment);
84 
85         updateAuthDescriptions();
86         refreshItems();
87     }
88 
89     @Override
get(int position)90     public ListItem get(int position) {
91         return mItems.get(position);
92     }
93 
94     @Override
size()95     public int size() {
96         return mItems.size();
97     }
98 
99     /**
100      * Clears the existing item list and rebuilds it with new data.
101      */
refreshItems()102     public void refreshItems() {
103         mItems.clear();
104 
105         for (int i = 0; i < mProviderList.size(); i++) {
106             String accountType = mProviderList.get(i).type;
107             Drawable icon = mAuthenticatorHelper.getDrawableForType(mContext, accountType);
108 
109             TextListItem item = new TextListItem(mContext);
110             item.setPrimaryActionIcon(icon, /* useLargeIcon= */ false);
111             item.setTitle(mProviderList.get(i).name.toString());
112             item.setOnClickListener(v -> onItemSelected(accountType));
113             mItems.add(item);
114         }
115     }
116 
117     // Starts a AddAccountActivity for the accountType that was clicked on.
onItemSelected(String accountType)118     private void onItemSelected(String accountType) {
119         Intent intent = new Intent(mContext, AddAccountActivity.class);
120         intent.putExtra(AddAccountActivity.EXTRA_SELECTED_ACCOUNT, accountType);
121         mContext.startActivity(intent);
122     }
123 
124     /**
125      * Updates provider icons.
126      */
updateAuthDescriptions()127     private void updateAuthDescriptions() {
128         mAuthDescs = AccountManager.get(mContext).getAuthenticatorTypesAsUser(
129                 mUserHandle.getIdentifier());
130         for (int i = 0; i < mAuthDescs.length; i++) {
131             mTypeToAuthDescription.put(mAuthDescs[i].type, mAuthDescs[i]);
132         }
133         onAuthDescriptionsUpdated();
134     }
135 
onAuthDescriptionsUpdated()136     private void onAuthDescriptionsUpdated() {
137         // Create list of providers to show on page.
138         for (int i = 0; i < mAuthDescs.length; i++) {
139             String accountType = mAuthDescs[i].type;
140             CharSequence providerName = getLabelForType(accountType);
141 
142             // Get the account authorities implemented by the account type.
143             ArrayList<String> accountAuths = getAuthoritiesForAccountType(accountType);
144 
145             // If there are specific authorities required, we need to check whether it's
146             // included in the account type.
147             if (mAuthorities != null && mAuthorities.length > 0 && accountAuths != null) {
148                 for (int k = 0; k < mAuthorities.length; k++) {
149                     if (accountAuths.contains(mAuthorities[k])) {
150                         mProviderList.add(
151                                 new ProviderEntry(providerName, accountType));
152                         break;
153                     }
154                 }
155             } else {
156                 mProviderList.add(
157                         new ProviderEntry(providerName, accountType));
158             }
159         }
160         Collections.sort(mProviderList);
161     }
162 
getAuthoritiesForAccountType(String type)163     private ArrayList<String> getAuthoritiesForAccountType(String type) {
164         if (mAccountTypeToAuthorities == null) {
165             mAccountTypeToAuthorities = new HashMap<>();
166             SyncAdapterType[] syncAdapters = ContentResolver.getSyncAdapterTypesAsUser(
167                     mUserHandle.getIdentifier());
168             for (int i = 0, n = syncAdapters.length; i < n; i++) {
169                 final SyncAdapterType adapterType = syncAdapters[i];
170                 ArrayList<String> authorities =
171                         mAccountTypeToAuthorities.get(adapterType.accountType);
172                 if (authorities == null) {
173                     authorities = new ArrayList<String>();
174                     mAccountTypeToAuthorities.put(adapterType.accountType, authorities);
175                 }
176                 LOG.v("added authority " + adapterType.authority + " to accountType "
177                         + adapterType.accountType);
178                 authorities.add(adapterType.authority);
179             }
180         }
181         return mAccountTypeToAuthorities.get(type);
182     }
183 
184     /**
185      * Gets the label associated with a particular account type. If none found, return null.
186      *
187      * @param accountType the type of account
188      * @return a CharSequence for the label or null if one cannot be found.
189      */
getLabelForType(final String accountType)190     private CharSequence getLabelForType(final String accountType) {
191         CharSequence label = null;
192         if (mTypeToAuthDescription.containsKey(accountType)) {
193             try {
194                 AuthenticatorDescription desc = mTypeToAuthDescription.get(accountType);
195                 Context authContext = mFragment.getActivity().createPackageContextAsUser(
196                         desc.packageName, 0 /* flags */, mUserHandle);
197                 label = authContext.getResources().getText(desc.labelId);
198             } catch (PackageManager.NameNotFoundException e) {
199                 LOG.w("No label name for account type " + accountType);
200             } catch (Resources.NotFoundException e) {
201                 LOG.w("No label resource for account type " + accountType);
202             }
203         }
204         return label;
205     }
206 
207     private static class ProviderEntry implements Comparable<ProviderEntry> {
208         private final CharSequence name;
209         private final String type;
ProviderEntry(CharSequence providerName, String accountType)210         ProviderEntry(CharSequence providerName, String accountType) {
211             name = providerName;
212             type = accountType;
213         }
214 
215         @Override
compareTo(ProviderEntry another)216         public int compareTo(ProviderEntry another) {
217             if (name == null) {
218                 return -1;
219             }
220             if (another.name == null) {
221                 return 1;
222             }
223             return CharSequences.compareToIgnoreCase(name, another.name);
224         }
225     }
226 }
227