1/*
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.util.Log;
26import android.view.LayoutInflater;
27import android.view.View;
28import android.view.ViewGroup;
29import android.widget.AdapterView;
30import android.widget.ArrayAdapter;
31import android.widget.ImageView;
32import android.widget.ListView;
33import android.widget.TextView;
34import com.android.internal.R;
35
36import java.util.ArrayList;
37import java.util.HashMap;
38import java.util.HashSet;
39import java.util.Map;
40import java.util.Set;
41
42/**
43 * @hide
44 */
45public class ChooseAccountTypeActivity extends Activity {
46    private static final String TAG = "AccountChooser";
47
48    private HashMap<String, AuthInfo> mTypeToAuthenticatorInfo = new HashMap<String, AuthInfo>();
49    private ArrayList<AuthInfo> mAuthenticatorInfosToDisplay;
50
51    @Override
52    public void onCreate(Bundle savedInstanceState) {
53        super.onCreate(savedInstanceState);
54
55        if (Log.isLoggable(TAG, Log.VERBOSE)) {
56            Log.v(TAG, "ChooseAccountTypeActivity.onCreate(savedInstanceState="
57                    + savedInstanceState + ")");
58        }
59
60        // Read the validAccountTypes, if present, and add them to the setOfAllowableAccountTypes
61        Set<String> setOfAllowableAccountTypes = null;
62        String[] validAccountTypes = getIntent().getStringArrayExtra(
63                ChooseTypeAndAccountActivity.EXTRA_ALLOWABLE_ACCOUNT_TYPES_STRING_ARRAY);
64        if (validAccountTypes != null) {
65            setOfAllowableAccountTypes = new HashSet<String>(validAccountTypes.length);
66            for (String type : validAccountTypes) {
67                setOfAllowableAccountTypes.add(type);
68            }
69        }
70
71        // create a map of account authenticators
72        buildTypeToAuthDescriptionMap();
73
74        // Create a list of authenticators that are allowable. Filter out those that
75        // don't match the allowable account types, if provided.
76        mAuthenticatorInfosToDisplay = new ArrayList<AuthInfo>(mTypeToAuthenticatorInfo.size());
77        for (Map.Entry<String, AuthInfo> entry: mTypeToAuthenticatorInfo.entrySet()) {
78            final String type = entry.getKey();
79            final AuthInfo info = entry.getValue();
80            if (setOfAllowableAccountTypes != null
81                    && !setOfAllowableAccountTypes.contains(type)) {
82                continue;
83            }
84            mAuthenticatorInfosToDisplay.add(info);
85        }
86
87        if (mAuthenticatorInfosToDisplay.isEmpty()) {
88            Bundle bundle = new Bundle();
89            bundle.putString(AccountManager.KEY_ERROR_MESSAGE, "no allowable account types");
90            setResult(Activity.RESULT_OK, new Intent().putExtras(bundle));
91            finish();
92            return;
93        }
94
95        if (mAuthenticatorInfosToDisplay.size() == 1) {
96            setResultAndFinish(mAuthenticatorInfosToDisplay.get(0).desc.type);
97            return;
98        }
99
100        setContentView(R.layout.choose_account_type);
101        // Setup the list
102        ListView list = findViewById(android.R.id.list);
103        // Use an existing ListAdapter that will map an array of strings to TextViews
104        list.setAdapter(new AccountArrayAdapter(this,
105                android.R.layout.simple_list_item_1, mAuthenticatorInfosToDisplay));
106        list.setChoiceMode(ListView.CHOICE_MODE_NONE);
107        list.setTextFilterEnabled(false);
108        list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
109            public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
110                setResultAndFinish(mAuthenticatorInfosToDisplay.get(position).desc.type);
111            }
112        });
113    }
114
115    private void setResultAndFinish(final String type) {
116        Bundle bundle = new Bundle();
117        bundle.putString(AccountManager.KEY_ACCOUNT_TYPE, type);
118        setResult(Activity.RESULT_OK, new Intent().putExtras(bundle));
119        if (Log.isLoggable(TAG, Log.VERBOSE)) {
120            Log.v(TAG, "ChooseAccountTypeActivity.setResultAndFinish: "
121                    + "selected account type " + type);
122        }
123        finish();
124    }
125
126    private void buildTypeToAuthDescriptionMap() {
127        for(AuthenticatorDescription desc : AccountManager.get(this).getAuthenticatorTypes()) {
128            String name = null;
129            Drawable icon = null;
130            try {
131                Context authContext = createPackageContext(desc.packageName, 0);
132                icon = authContext.getDrawable(desc.iconId);
133                final CharSequence sequence = authContext.getResources().getText(desc.labelId);
134                if (sequence != null) {
135                    name = sequence.toString();
136                }
137                name = sequence.toString();
138            } catch (PackageManager.NameNotFoundException e) {
139                // Nothing we can do much here, just log
140                if (Log.isLoggable(TAG, Log.WARN)) {
141                    Log.w(TAG, "No icon name for account type " + desc.type);
142                }
143            } catch (Resources.NotFoundException e) {
144                // Nothing we can do much here, just log
145                if (Log.isLoggable(TAG, Log.WARN)) {
146                    Log.w(TAG, "No icon resource for account type " + desc.type);
147                }
148            }
149            AuthInfo authInfo = new AuthInfo(desc, name, icon);
150            mTypeToAuthenticatorInfo.put(desc.type, authInfo);
151        }
152    }
153
154    private static class AuthInfo {
155        final AuthenticatorDescription desc;
156        final String name;
157        final Drawable drawable;
158
159        AuthInfo(AuthenticatorDescription desc, String name, Drawable drawable) {
160            this.desc = desc;
161            this.name = name;
162            this.drawable = drawable;
163        }
164    }
165
166    private static class ViewHolder {
167        ImageView icon;
168        TextView text;
169    }
170
171    private static class AccountArrayAdapter extends ArrayAdapter<AuthInfo> {
172        private LayoutInflater mLayoutInflater;
173        private ArrayList<AuthInfo> mInfos;
174
175        public AccountArrayAdapter(Context context, int textViewResourceId,
176                ArrayList<AuthInfo> infos) {
177            super(context, textViewResourceId, infos);
178            mInfos = infos;
179            mLayoutInflater = (LayoutInflater) context.getSystemService(
180                    Context.LAYOUT_INFLATER_SERVICE);
181        }
182
183        @Override
184        public View getView(int position, View convertView, ViewGroup parent) {
185            ViewHolder holder;
186
187            if (convertView == null) {
188                convertView = mLayoutInflater.inflate(R.layout.choose_account_row, null);
189                holder = new ViewHolder();
190                holder.text = (TextView) convertView.findViewById(R.id.account_row_text);
191                holder.icon = (ImageView) convertView.findViewById(R.id.account_row_icon);
192                convertView.setTag(holder);
193            } else {
194                holder = (ViewHolder) convertView.getTag();
195            }
196
197            holder.text.setText(mInfos.get(position).name);
198            holder.icon.setImageDrawable(mInfos.get(position).drawable);
199
200            return convertView;
201        }
202    }
203}
204