AI2 Component  (Version nb184)
AccountChooser.java
Go to the documentation of this file.
1 // -*- mode: java; c-basic-offset: 2; -*-
2 // Copyright 2009-2011 Google, All Rights reserved
3 // Copyright 2011-2012 MIT, All rights reserved
4 // Released under the Apache License, Version 2.0
5 // http://www.apache.org/licenses/LICENSE-2.0
6 
7 package com.google.appinventor.components.runtime.util;
8 
9 import android.accounts.Account;
10 import android.accounts.AccountManager;
11 import android.accounts.AccountManagerFuture;
12 import android.accounts.AuthenticatorException;
13 import android.accounts.OperationCanceledException;
14 import android.app.Activity;
15 import android.app.AlertDialog;
16 import android.content.Context;
17 import android.content.DialogInterface;
18 import android.content.DialogInterface.OnCancelListener;
19 import android.content.DialogInterface.OnClickListener;
20 import android.content.SharedPreferences;
21 import android.os.Bundle;
22 import android.text.Html;
23 import android.util.Log;
24 
25 import java.io.IOException;
26 import java.util.concurrent.SynchronousQueue;
27 
41 public class AccountChooser {
42  private static final String NO_ACCOUNT = "";
43  private static final String LOG_TAG = "AccountChooser";
44  private static final String ACCOUNT_PREFERENCE = "account";
48  private static final String ACCOUNT_TYPE = "com.google";
49 
50  private AccountManager accountManager;
51  private String service;
52  private String preferencesKey;
53  private Activity activity;
54  private String chooseAccountPrompt;
55 
56  public AccountChooser(Activity activity, String service, String title, String key) {
57  this.activity = activity;
58  this.service = service;
59  this.chooseAccountPrompt = title;
60  this.preferencesKey = key;
61  this.accountManager = AccountManager.get(activity);
62  }
63 
67  public Account findAccount() {
68  Account[] accounts = accountManager.getAccountsByType(ACCOUNT_TYPE);
69 
70  // only one matching account - use it, and remember it for the next time.
71  if (accounts.length == 1) {
72  persistAccountName(accounts[0].name);
73  return accounts[0];
74  }
75 
76  // No accounts, create one and use it if created, otherwise we have no account to use
77 
78  if (accounts.length == 0) {
79  String accountName = createAccount();
80  if (accountName != null) {
81  persistAccountName(accountName);
82  return accountManager.getAccountsByType(ACCOUNT_TYPE)[0];
83  } else {
84  Log.i(LOG_TAG, "User failed to create a valid account");
85  return null;
86  }
87  }
88 
89  // Still valid previously chosen account - use it
90 
91  Account account;
92  String accountName = getPersistedAccountName();
93  if (accountName != null && (account = chooseAccount(accountName, accounts)) != null) {
94  return account;
95  }
96 
97  // Either there is no saved account name, or our saved account vanished
98  // Have the user select the account
99 
100  accountName = selectAccount(accounts);
101  if (accountName != null) {
102  persistAccountName(accountName);
103  return chooseAccount(accountName, accounts);
104  }
105 
106  // user didn't choose an account at all!
107  Log.i(LOG_TAG, "User failed to choose an account");
108  return null;
109  }
110 
111  private Account chooseAccount(String accountName, Account[] accounts) {
112  for (Account account : accounts) {
113  if (account.name.equals(accountName)) {
114  Log.i(LOG_TAG, "chose account: " + accountName);
115  return account;
116  }
117  }
118  return null;
119  }
120 
121  private String createAccount() {
122  AccountManagerFuture<Bundle> future;
123  Log.i(LOG_TAG, "Adding auth token account ...");
124  future = accountManager.addAccount(ACCOUNT_TYPE, service, null, null, activity, null, null);
125  try {
126  Bundle result = future.getResult();
127  String accountName = result.getString(AccountManager.KEY_ACCOUNT_NAME);
128  Log.i(LOG_TAG, "created: " + accountName);
129  return accountName;
130  } catch (OperationCanceledException e) {
131  e.printStackTrace();
132  } catch (AuthenticatorException e) {
133  e.printStackTrace();
134  } catch (IOException e) {
135  e.printStackTrace();
136  }
137  return null;
138  }
139 
140  private String selectAccount(Account accounts[]) {
141  final SynchronousQueue<String> queue = new SynchronousQueue<String>();
142  SelectAccount select = new SelectAccount(accounts, queue);
143  select.start();
144  Log.i(LOG_TAG, "Select: waiting for user...");
145  String account = null;
146  try {
147  account = queue.take();
148  } catch (InterruptedException e) {
149  e.printStackTrace();
150  }
151  Log.i(LOG_TAG, "Selected: " + account);
152  return NO_ACCOUNT.equals(account) ? null : account;
153  }
154 
155  private SharedPreferences getPreferences() {
156  return activity.getSharedPreferences(preferencesKey, Context.MODE_PRIVATE);
157  }
158 
159  private String getPersistedAccountName() {
160  return getPreferences().getString(ACCOUNT_PREFERENCE, null);
161  }
162 
163  private void persistAccountName(String accountName) {
164  Log.i(LOG_TAG, "persisting account: " + accountName);
165  getPreferences().edit().putString(ACCOUNT_PREFERENCE, accountName).commit();
166  }
167 
168  public void forgetAccountName() {
169  getPreferences().edit().remove(ACCOUNT_PREFERENCE).commit();
170  }
171 
177  class SelectAccount extends Thread implements OnClickListener, OnCancelListener {
178  private String[] accountNames;
179  private SynchronousQueue<String> queue;
180 
181  SelectAccount(Account[] accounts, SynchronousQueue<String> queue) {
182  this.queue = queue;
183  accountNames = new String[accounts.length];
184  for (int i = 0; i < accounts.length; i++) {
185  accountNames[i] = accounts[i].name;
186  }
187  }
188 
189  @Override
190  public void run() {
191  activity.runOnUiThread(new Runnable() {
192  @Override
193  public void run() {
194  AlertDialog.Builder ab = new AlertDialog.Builder(activity)
195  .setTitle(Html.fromHtml(chooseAccountPrompt))
196  .setOnCancelListener(SelectAccount.this)
197  .setSingleChoiceItems(accountNames, -1, SelectAccount.this);
198  ab.show();
199  Log.i(LOG_TAG, "Dialog showing!");
200  }
201  });
202  }
203 
204  @Override
205  public void onClick(DialogInterface dialog, int button) {
206  try {
207  if (button >= 0) {
208  String account = accountNames[button];
209  Log.i(LOG_TAG, "Chose: " + account);
210  queue.put(account);
211  } else {
212  queue.put(NO_ACCOUNT);
213  }
214  } catch (InterruptedException e) {
215  // This should never happen
216  }
217  dialog.dismiss();
218  }
219 
220  @Override
221  public void onCancel(DialogInterface dialog) {
222  Log.i(LOG_TAG, "Chose: canceled");
223  onClick(dialog, -1);
224  }
225  }
226 }
com.google.appinventor.components.runtime.util.AccountChooser.AccountChooser
AccountChooser(Activity activity, String service, String title, String key)
Definition: AccountChooser.java:56
com.google.appinventor.components.runtime.util.AccountChooser.forgetAccountName
void forgetAccountName()
Definition: AccountChooser.java:168
com.google.appinventor.components.runtime.util.AccountChooser.findAccount
Account findAccount()
Definition: AccountChooser.java:67
com.google.appinventor.components.runtime.util.AccountChooser
Definition: AccountChooser.java:41