1 /*
2  * Copyright (C) 2009 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 package android.accounts;
17 
18 import android.app.Activity;
19 import android.app.ActivityManager;
20 import android.app.ActivityTaskManager;
21 import android.content.Context;
22 import android.content.pm.PackageManager;
23 import android.content.res.Resources;
24 import android.graphics.drawable.Drawable;
25 import android.os.Bundle;
26 import android.os.IBinder;
27 import android.os.Parcelable;
28 import android.os.RemoteException;
29 import android.os.Process;
30 import android.os.UserHandle;
31 import android.util.Log;
32 import android.view.LayoutInflater;
33 import android.view.View;
34 import android.view.ViewGroup;
35 import android.widget.AdapterView;
36 import android.widget.ArrayAdapter;
37 import android.widget.ImageView;
38 import android.widget.ListView;
39 import android.widget.TextView;
40 import com.android.internal.R;
41 
42 import java.util.HashMap;
43 
44 /**
45  * @hide
46  */
47 public class ChooseAccountActivity extends Activity {
48 
49     private static final String TAG = "AccountManager";
50 
51     private Parcelable[] mAccounts = null;
52     private AccountManagerResponse mAccountManagerResponse = null;
53     private Bundle mResult;
54     private int mCallingUid;
55     private String mCallingPackage;
56 
57     private HashMap<String, AuthenticatorDescription> mTypeToAuthDescription
58             = new HashMap<String, AuthenticatorDescription>();
59 
60     @Override
onCreate(Bundle savedInstanceState)61     public void onCreate(Bundle savedInstanceState) {
62         super.onCreate(savedInstanceState);
63         mAccounts = getIntent().getParcelableArrayExtra(AccountManager.KEY_ACCOUNTS);
64         mAccountManagerResponse =
65                 getIntent().getParcelableExtra(AccountManager.KEY_ACCOUNT_MANAGER_RESPONSE);
66 
67         // KEY_ACCOUNTS is a required parameter
68         if (mAccounts == null) {
69             setResult(RESULT_CANCELED);
70             finish();
71             return;
72         }
73 
74         try {
75             IBinder activityToken = getActivityToken();
76             mCallingUid = ActivityTaskManager.getService().getLaunchedFromUid(activityToken);
77             mCallingPackage = ActivityTaskManager.getService().getLaunchedFromPackage(
78                     activityToken);
79         } catch (RemoteException re) {
80             // Couldn't figure out caller details
81             Log.w(getClass().getSimpleName(), "Unable to get caller identity \n" + re);
82         }
83 
84         if (UserHandle.isSameApp(mCallingUid, Process.SYSTEM_UID) &&
85             getIntent().getStringExtra(AccountManager.KEY_ANDROID_PACKAGE_NAME) != null) {
86             mCallingPackage = getIntent().getStringExtra(
87                 AccountManager.KEY_ANDROID_PACKAGE_NAME);
88         }
89 
90         if (!UserHandle.isSameApp(mCallingUid, Process.SYSTEM_UID) &&
91                 getIntent().getStringExtra(AccountManager.KEY_ANDROID_PACKAGE_NAME) != null) {
92             Log.w(getClass().getSimpleName(),
93                 "Non-system Uid: " + mCallingUid + " tried to override packageName \n");
94         }
95 
96         getAuthDescriptions();
97 
98         AccountInfo[] mAccountInfos = new AccountInfo[mAccounts.length];
99         for (int i = 0; i < mAccounts.length; i++) {
100             mAccountInfos[i] = new AccountInfo(((Account) mAccounts[i]).name,
101                     getDrawableForType(((Account) mAccounts[i]).type));
102         }
103 
104         setContentView(R.layout.choose_account);
105 
106         // Setup the list
107         ListView list = findViewById(android.R.id.list);
108         // Use an existing ListAdapter that will map an array of strings to TextViews
109         list.setAdapter(new AccountArrayAdapter(this,
110                 android.R.layout.simple_list_item_1, mAccountInfos));
111         list.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
112         list.setTextFilterEnabled(true);
113         list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
114             public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
115                 onListItemClick((ListView)parent, v, position, id);
116             }
117         });
118     }
119 
getAuthDescriptions()120     private void getAuthDescriptions() {
121         for(AuthenticatorDescription desc : AccountManager.get(this).getAuthenticatorTypes()) {
122             mTypeToAuthDescription.put(desc.type, desc);
123         }
124     }
125 
getDrawableForType(String accountType)126     private Drawable getDrawableForType(String accountType) {
127         Drawable icon = null;
128         if(mTypeToAuthDescription.containsKey(accountType)) {
129             try {
130                 AuthenticatorDescription desc = mTypeToAuthDescription.get(accountType);
131                 Context authContext = createPackageContext(desc.packageName, 0);
132                 icon = authContext.getDrawable(desc.iconId);
133             } catch (PackageManager.NameNotFoundException e) {
134                 // Nothing we can do much here, just log
135                 if (Log.isLoggable(TAG, Log.WARN)) {
136                     Log.w(TAG, "No icon name for account type " + accountType);
137                 }
138             } catch (Resources.NotFoundException e) {
139                 // Nothing we can do much here, just log
140                 if (Log.isLoggable(TAG, Log.WARN)) {
141                     Log.w(TAG, "No icon resource for account type " + accountType);
142                 }
143             }
144         }
145         return icon;
146     }
147 
onListItemClick(ListView l, View v, int position, long id)148     protected void onListItemClick(ListView l, View v, int position, long id) {
149         Account account = (Account) mAccounts[position];
150         // Mark account as visible since user chose it.
151         AccountManager am = AccountManager.get(this);
152         Integer oldVisibility = am.getAccountVisibility(account, mCallingPackage);
153         if (oldVisibility != null
154                 && oldVisibility == AccountManager.VISIBILITY_USER_MANAGED_NOT_VISIBLE) {
155             am.setAccountVisibility(account, mCallingPackage,
156                 AccountManager.VISIBILITY_USER_MANAGED_VISIBLE);
157         }
158         Log.d(TAG, "selected account " + account);
159         Bundle bundle = new Bundle();
160         bundle.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
161         bundle.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type);
162         mResult = bundle;
163         finish();
164     }
165 
finish()166     public void finish() {
167         if (mAccountManagerResponse != null) {
168             if (mResult != null) {
169                 mAccountManagerResponse.onResult(mResult);
170             } else {
171                 mAccountManagerResponse.onError(AccountManager.ERROR_CODE_CANCELED, "canceled");
172             }
173         }
174         super.finish();
175     }
176 
177     private static class AccountInfo {
178         final String name;
179         final Drawable drawable;
180 
AccountInfo(String name, Drawable drawable)181         AccountInfo(String name, Drawable drawable) {
182             this.name = name;
183             this.drawable = drawable;
184         }
185     }
186 
187     private static class ViewHolder {
188         ImageView icon;
189         TextView text;
190     }
191 
192     private static class AccountArrayAdapter extends ArrayAdapter<AccountInfo> {
193         private LayoutInflater mLayoutInflater;
194         private AccountInfo[] mInfos;
195 
AccountArrayAdapter(Context context, int textViewResourceId, AccountInfo[] infos)196         public AccountArrayAdapter(Context context, int textViewResourceId, AccountInfo[] infos) {
197             super(context, textViewResourceId, infos);
198             mInfos = infos;
199             mLayoutInflater = (LayoutInflater) context.getSystemService(
200                     Context.LAYOUT_INFLATER_SERVICE);
201         }
202 
203         @Override
getView(int position, View convertView, ViewGroup parent)204         public View getView(int position, View convertView, ViewGroup parent) {
205             ViewHolder holder;
206 
207             if (convertView == null) {
208                 convertView = mLayoutInflater.inflate(R.layout.choose_account_row, null);
209                 holder = new ViewHolder();
210                 holder.text = (TextView) convertView.findViewById(R.id.account_row_text);
211                 holder.icon = (ImageView) convertView.findViewById(R.id.account_row_icon);
212                 convertView.setTag(holder);
213             } else {
214                 holder = (ViewHolder) convertView.getTag();
215             }
216 
217             holder.text.setText(mInfos[position].name);
218             holder.icon.setImageDrawable(mInfos[position].drawable);
219 
220             return convertView;
221         }
222     }
223 }
224