blob: b4030b9cbfae830f098ef01556c6a801824433f9 [file] [log] [blame]
Fred Quintana1121bb52011-09-14 23:19:35 -07001/*
2 * Copyright (C) 2011 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 */
16package android.accounts;
17
18import android.app.Activity;
19import android.content.Context;
20import android.content.Intent;
21import android.content.pm.PackageManager;
22import android.content.res.Resources;
23import android.graphics.drawable.Drawable;
24import android.os.Bundle;
25import android.os.Parcelable;
Fred Quintanab04fe4e2011-09-16 21:17:21 -070026import android.text.TextUtils;
Fred Quintana1121bb52011-09-14 23:19:35 -070027import android.util.Log;
28import android.view.LayoutInflater;
29import android.view.View;
30import android.view.ViewGroup;
31import android.widget.AdapterView;
32import android.widget.ArrayAdapter;
33import android.widget.Button;
34import android.widget.ImageView;
35import android.widget.ListView;
36import android.widget.TextView;
37import com.android.internal.R;
38
39import java.util.ArrayList;
40import java.util.HashMap;
41import java.util.HashSet;
42import java.util.Set;
43
44/**
45 * @hide
46 */
47public class ChooseTypeAndAccountActivity extends Activity {
48 private static final String TAG = "AccountManager";
49
50 /**
51 * A Parcelable ArrayList of Account objects that limits the choosable accounts to those
52 * in this list, if this parameter is supplied.
53 */
54 public static final String EXTRA_ALLOWABLE_ACCOUNTS_ARRAYLIST = "allowableAccounts";
55
56 /**
57 * A Parcelable ArrayList of String objects that limits the accounts to choose to those
58 * that match the types in this list, if this parameter is supplied. This list is also
59 * used to filter the allowable account types if add account is selected.
60 */
Fred Quintanab04fe4e2011-09-16 21:17:21 -070061 public static final String EXTRA_ALLOWABLE_ACCOUNT_TYPES_STRING_ARRAY = "allowableAccountTypes";
Fred Quintana1121bb52011-09-14 23:19:35 -070062
63 /**
Fred Quintanab04fe4e2011-09-16 21:17:21 -070064 * This is passed as the addAccountOptions parameter in AccountManager.addAccount()
65 * if it is called.
Fred Quintana1121bb52011-09-14 23:19:35 -070066 */
67 public static final String EXTRA_ADD_ACCOUNT_OPTIONS_BUNDLE = "addAccountOptions";
68
69 /**
Fred Quintanab04fe4e2011-09-16 21:17:21 -070070 * This is passed as the requiredFeatures parameter in AccountManager.addAccount()
71 * if it is called.
72 */
73 public static final String EXTRA_ADD_ACCOUNT_REQUIRED_FEATURES_STRING_ARRAY =
74 "addAccountRequiredFeatures";
75
76 /**
77 * This is passed as the authTokenType string in AccountManager.addAccount()
78 * if it is called.
79 */
80 public static final String EXTRA_ADD_ACCOUNT_AUTH_TOKEN_TYPE_STRING = "authTokenType";
81
82 /**
Fred Quintana1121bb52011-09-14 23:19:35 -070083 * If set then the specified account is already "selected".
84 */
85 public static final String EXTRA_SELECTED_ACCOUNT = "selectedAccount";
86
Fred Quintanab04fe4e2011-09-16 21:17:21 -070087 /**
88 * If true then display the account selection list even if there is just
89 * one account to choose from. boolean.
90 */
91 public static final String EXTRA_ALWAYS_PROMPT_FOR_ACCOUNT =
92 "alwaysPromptForAccount";
93
94 /**
95 * If set then this string willb e used as the description rather than
96 * the default.
97 */
98 public static final String EXTRA_DESCRIPTION_TEXT_OVERRIDE =
99 "descriptionTextOverride";
100
Fred Quintana1121bb52011-09-14 23:19:35 -0700101 private ArrayList<AccountInfo> mAccountInfos;
102
103 @Override
104 public void onCreate(Bundle savedInstanceState) {
105 super.onCreate(savedInstanceState);
106 setContentView(R.layout.choose_type_and_account);
Fred Quintanab04fe4e2011-09-16 21:17:21 -0700107
108 // save some items we use frequently
Fred Quintana1121bb52011-09-14 23:19:35 -0700109 final AccountManager accountManager = AccountManager.get(this);
Fred Quintanab04fe4e2011-09-16 21:17:21 -0700110 final Intent intent = getIntent();
111
112 // override the description text if supplied
113 final String descriptionOverride =
114 intent.getStringExtra(EXTRA_DESCRIPTION_TEXT_OVERRIDE);
115 if (!TextUtils.isEmpty(descriptionOverride)) {
116 ((TextView)findViewById(R.id.description)).setText(descriptionOverride);
117 }
118
119 // If the selected account matches one in the list we will place a
120 // checkmark next to it.
121 final Account selectedAccount =
122 (Account)intent.getParcelableExtra(EXTRA_SELECTED_ACCOUNT);
Fred Quintana1121bb52011-09-14 23:19:35 -0700123
124 // build an efficiently queryable map of account types to authenticator descriptions
125 final HashMap<String, AuthenticatorDescription> typeToAuthDescription =
126 new HashMap<String, AuthenticatorDescription>();
127 for(AuthenticatorDescription desc : accountManager.getAuthenticatorTypes()) {
128 typeToAuthDescription.put(desc.type, desc);
129 }
130
131 // Read the validAccounts, if present, and add them to the setOfAllowableAccounts
132 Set<Account> setOfAllowableAccounts = null;
133 final ArrayList<Parcelable> validAccounts =
Fred Quintanab04fe4e2011-09-16 21:17:21 -0700134 intent.getParcelableArrayListExtra(EXTRA_ALLOWABLE_ACCOUNTS_ARRAYLIST);
Fred Quintana1121bb52011-09-14 23:19:35 -0700135 if (validAccounts != null) {
136 setOfAllowableAccounts = new HashSet<Account>(validAccounts.size());
137 for (Parcelable parcelable : validAccounts) {
138 setOfAllowableAccounts.add((Account)parcelable);
139 }
140 }
141
142 // Read the validAccountTypes, if present, and add them to the setOfAllowableAccountTypes
143 Set<String> setOfAllowableAccountTypes = null;
144 final ArrayList<String> validAccountTypes =
Fred Quintanab04fe4e2011-09-16 21:17:21 -0700145 intent.getStringArrayListExtra(EXTRA_ALLOWABLE_ACCOUNT_TYPES_STRING_ARRAY);
Fred Quintana1121bb52011-09-14 23:19:35 -0700146 if (validAccountTypes != null) {
147 setOfAllowableAccountTypes = new HashSet<String>(validAccountTypes.size());
148 for (String type : validAccountTypes) {
149 setOfAllowableAccountTypes.add(type);
150 }
151 }
152
153 // Create a list of AccountInfo objects for each account that is allowable. Filter out
154 // accounts that don't match the allowable types, if provided, or that don't match the
155 // allowable accounts, if provided.
156 final Account[] accounts = accountManager.getAccounts();
157 mAccountInfos = new ArrayList<AccountInfo>(accounts.length);
158 for (Account account : accounts) {
159 if (setOfAllowableAccounts != null
160 && !setOfAllowableAccounts.contains(account)) {
161 continue;
162 }
163 if (setOfAllowableAccountTypes != null
164 && !setOfAllowableAccountTypes.contains(account.type)) {
165 continue;
166 }
167 mAccountInfos.add(new AccountInfo(account,
Fred Quintanab04fe4e2011-09-16 21:17:21 -0700168 getDrawableForType(typeToAuthDescription, account.type),
169 account.equals(selectedAccount)));
Fred Quintana1121bb52011-09-14 23:19:35 -0700170 }
171
172 // If there are no allowable accounts go directly to add account
173 if (mAccountInfos.isEmpty()) {
174 startChooseAccountTypeActivity();
175 return;
176 }
177
178 // if there is only one allowable account return it
Fred Quintanab04fe4e2011-09-16 21:17:21 -0700179 if (!intent.getBooleanExtra(EXTRA_ALWAYS_PROMPT_FOR_ACCOUNT, false)
180 && mAccountInfos.size() == 1) {
Fred Quintana1121bb52011-09-14 23:19:35 -0700181 Account account = mAccountInfos.get(0).account;
182 setResultAndFinish(account.name, account.type);
183 return;
184 }
185
186 // there is more than one allowable account. initialize the list adapter to allow
187 // the user to select an account.
188 ListView list = (ListView) findViewById(android.R.id.list);
189 list.setAdapter(new AccountArrayAdapter(this,
190 android.R.layout.simple_list_item_1, mAccountInfos));
191 list.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
Fred Quintana1121bb52011-09-14 23:19:35 -0700192 list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
193 public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
194 onListItemClick((ListView)parent, v, position, id);
195 }
196 });
197
198 // set the listener for the addAccount button
199 Button addAccountButton = (Button) findViewById(R.id.addAccount);
200 addAccountButton.setOnClickListener(new View.OnClickListener() {
201 public void onClick(final View v) {
202 startChooseAccountTypeActivity();
203 }
204 });
205 }
206
207 // Called when the choose account type activity (for adding an account) returns.
208 // If it was a success read the account and set it in the result. In all cases
209 // return the result and finish this activity.
210 @Override
211 protected void onActivityResult(final int requestCode, final int resultCode,
212 final Intent data) {
213 if (resultCode == RESULT_OK && data != null) {
214 String accountName = data.getStringExtra(AccountManager.KEY_ACCOUNT_NAME);
215 String accountType = data.getStringExtra(AccountManager.KEY_ACCOUNT_TYPE);
216 if (accountName != null && accountType != null) {
217 setResultAndFinish(accountName, accountType);
218 return;
219 }
220 }
Fred Quintanab04fe4e2011-09-16 21:17:21 -0700221 Log.d(TAG, "ChooseTypeAndAccountActivity.onActivityResult: canceled");
Fred Quintana1121bb52011-09-14 23:19:35 -0700222 setResult(Activity.RESULT_CANCELED);
223 finish();
224 }
225
Fred Quintanab04fe4e2011-09-16 21:17:21 -0700226
Fred Quintana1121bb52011-09-14 23:19:35 -0700227 private Drawable getDrawableForType(
228 final HashMap<String, AuthenticatorDescription> typeToAuthDescription,
229 String accountType) {
230 Drawable icon = null;
231 if (typeToAuthDescription.containsKey(accountType)) {
232 try {
233 AuthenticatorDescription desc = typeToAuthDescription.get(accountType);
234 Context authContext = createPackageContext(desc.packageName, 0);
235 icon = authContext.getResources().getDrawable(desc.iconId);
236 } catch (PackageManager.NameNotFoundException e) {
237 // Nothing we can do much here, just log
238 if (Log.isLoggable(TAG, Log.WARN)) {
239 Log.w(TAG, "No icon name for account type " + accountType);
240 }
241 } catch (Resources.NotFoundException e) {
242 // Nothing we can do much here, just log
243 if (Log.isLoggable(TAG, Log.WARN)) {
244 Log.w(TAG, "No icon resource for account type " + accountType);
245 }
246 }
247 }
248 return icon;
249 }
250
251 protected void onListItemClick(ListView l, View v, int position, long id) {
252 AccountInfo accountInfo = mAccountInfos.get(position);
253 Log.d(TAG, "selected account " + accountInfo.account);
254 setResultAndFinish(accountInfo.account.name, accountInfo.account.type);
255 }
256
257 private void setResultAndFinish(final String accountName, final String accountType) {
258 Bundle bundle = new Bundle();
259 bundle.putString(AccountManager.KEY_ACCOUNT_NAME, accountName);
260 bundle.putString(AccountManager.KEY_ACCOUNT_TYPE, accountType);
261 setResult(Activity.RESULT_OK, new Intent().putExtras(bundle));
Fred Quintanab04fe4e2011-09-16 21:17:21 -0700262 Log.d(TAG, "ChooseTypeAndAccountActivity.setResultAndFinish: "
263 + "selected account " + accountName + ", " + accountType);
Fred Quintana1121bb52011-09-14 23:19:35 -0700264 finish();
265 }
266
267 private void startChooseAccountTypeActivity() {
268 final Intent intent = new Intent(this, ChooseAccountTypeActivity.class);
Fred Quintanab04fe4e2011-09-16 21:17:21 -0700269 intent.putStringArrayListExtra(EXTRA_ALLOWABLE_ACCOUNT_TYPES_STRING_ARRAY,
270 getIntent().getStringArrayListExtra(EXTRA_ALLOWABLE_ACCOUNT_TYPES_STRING_ARRAY));
Fred Quintana1121bb52011-09-14 23:19:35 -0700271 intent.putExtra(EXTRA_ADD_ACCOUNT_OPTIONS_BUNDLE,
Fred Quintanab04fe4e2011-09-16 21:17:21 -0700272 getIntent().getBundleExtra(EXTRA_ADD_ACCOUNT_OPTIONS_BUNDLE));
273 intent.putExtra(EXTRA_ADD_ACCOUNT_REQUIRED_FEATURES_STRING_ARRAY,
274 getIntent().getStringArrayExtra(EXTRA_ADD_ACCOUNT_REQUIRED_FEATURES_STRING_ARRAY));
275 intent.putExtra(EXTRA_ADD_ACCOUNT_AUTH_TOKEN_TYPE_STRING,
276 getIntent().getStringArrayExtra(EXTRA_ADD_ACCOUNT_AUTH_TOKEN_TYPE_STRING));
Fred Quintana1121bb52011-09-14 23:19:35 -0700277 startActivityForResult(intent, 0);
278 }
279
280 private static class AccountInfo {
281 final Account account;
282 final Drawable drawable;
Fred Quintanab04fe4e2011-09-16 21:17:21 -0700283 private final boolean checked;
Fred Quintana1121bb52011-09-14 23:19:35 -0700284
Fred Quintanab04fe4e2011-09-16 21:17:21 -0700285 AccountInfo(Account account, Drawable drawable, boolean checked) {
Fred Quintana1121bb52011-09-14 23:19:35 -0700286 this.account = account;
287 this.drawable = drawable;
Fred Quintanab04fe4e2011-09-16 21:17:21 -0700288 this.checked = checked;
Fred Quintana1121bb52011-09-14 23:19:35 -0700289 }
290 }
291
292 private static class ViewHolder {
293 ImageView icon;
294 TextView text;
Fred Quintanab04fe4e2011-09-16 21:17:21 -0700295 ImageView checkmark;
Fred Quintana1121bb52011-09-14 23:19:35 -0700296 }
297
298 private static class AccountArrayAdapter extends ArrayAdapter<AccountInfo> {
299 private LayoutInflater mLayoutInflater;
300 private ArrayList<AccountInfo> mInfos;
301
302 public AccountArrayAdapter(Context context, int textViewResourceId,
303 ArrayList<AccountInfo> infos) {
304 super(context, textViewResourceId, infos);
305 mInfos = infos;
306 mLayoutInflater = (LayoutInflater) context.getSystemService(
307 Context.LAYOUT_INFLATER_SERVICE);
308 }
309
310 @Override
311 public View getView(int position, View convertView, ViewGroup parent) {
312 ViewHolder holder;
313
314 if (convertView == null) {
Fred Quintanab04fe4e2011-09-16 21:17:21 -0700315 convertView = mLayoutInflater.inflate(R.layout.choose_selected_account_row, null);
Fred Quintana1121bb52011-09-14 23:19:35 -0700316 holder = new ViewHolder();
317 holder.text = (TextView) convertView.findViewById(R.id.account_row_text);
318 holder.icon = (ImageView) convertView.findViewById(R.id.account_row_icon);
Fred Quintanab04fe4e2011-09-16 21:17:21 -0700319 holder.checkmark = (ImageView) convertView.findViewById(R.id.account_row_checkmark);
Fred Quintana1121bb52011-09-14 23:19:35 -0700320 convertView.setTag(holder);
321 } else {
322 holder = (ViewHolder) convertView.getTag();
323 }
324
325 holder.text.setText(mInfos.get(position).account.name);
326 holder.icon.setImageDrawable(mInfos.get(position).drawable);
Fred Quintanab04fe4e2011-09-16 21:17:21 -0700327 final int displayCheckmark =
328 mInfos.get(position).checked ? View.VISIBLE : View.INVISIBLE;
329 holder.checkmark.setVisibility(displayCheckmark);
Fred Quintana1121bb52011-09-14 23:19:35 -0700330 return convertView;
331 }
332 }
333}