blob: f10bb09fbe31bd81f4d5ac3d9ceb9742d3ecfa58 [file] [log] [blame]
Robin Leebaefdcf2015-08-26 10:57:44 +01001/*
2 * Copyright (C) 2015 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
17package com.android.settings;
18
19import android.app.AlertDialog;
20import android.app.Dialog;
21import android.app.Fragment;
22import android.content.Context;
23import android.content.DialogInterface;
24import android.os.AsyncTask;
25import android.os.Bundle;
26import android.security.Credentials;
27import android.security.KeyStore;
28import android.view.LayoutInflater;
29import android.view.View;
30import android.view.ViewGroup;
31import android.widget.Adapter;
32import android.widget.AdapterView;
33import android.widget.AdapterView.OnItemClickListener;
34import android.widget.ArrayAdapter;
35import android.widget.ListAdapter;
36import android.widget.Button;
37import android.widget.ListView;
38import android.widget.TextView;
39
40import java.util.EnumSet;
41import java.util.List;
42import java.util.Set;
43import java.util.SortedMap;
44import java.util.TreeMap;
45
46import static android.view.View.VISIBLE;
47import static android.view.View.GONE;
48
49public class UserCredentialsSettings extends InstrumentedFragment implements OnItemClickListener {
50 private static final String TAG = "UserCredentialsSettings";
51
52 private View mRootView;
53 private ListView mListView;
54
55 @Override
56 protected int getMetricsCategory() {
57 // TODO (rgl): Declare a metrics category for user credentials.
58 return UNDECLARED;
59 }
60
61 @Override
62 public void onResume() {
63 super.onResume();
64 new AliasLoader().execute();
65 }
66
67 @Override
68 public View onCreateView(
69 LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {
70 mRootView = inflater.inflate(R.layout.user_credentials, parent, false);
71
72 // Set up an OnItemClickListener for the credential list.
73 mListView = (ListView) mRootView.findViewById(R.id.credential_list);
74 mListView.setOnItemClickListener(this);
75
76 return mRootView;
77 }
78
79 @Override
80 public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
81 final Credential item = (Credential) parent.getItemAtPosition(position);
82
83 View root = getActivity().getLayoutInflater()
84 .inflate(R.layout.user_credential_dialog, null);
85 ViewGroup infoContainer = (ViewGroup) root.findViewById(R.id.credential_container);
86 infoContainer.addView(parent.getAdapter().getView(position, null, null));
87
88 new AlertDialog.Builder(getActivity())
89 .setView(root)
90 .setTitle(R.string.user_credential_title)
91 .setPositiveButton(R.string.done, null)
92 .setNegativeButton(R.string.trusted_credentials_remove_label,
93 new DialogInterface.OnClickListener() {
94 @Override public void onClick(DialogInterface dialog, int id) {
95 final KeyStore ks = KeyStore.getInstance();
96 Credentials.deleteAllTypesForAlias(ks, item.alias);
97 new AliasLoader().execute();
98 dialog.dismiss();
99 }
100 })
101 .show();
102 }
103
104 /**
105 * Opens a background connection to KeyStore to list user credentials.
106 * The credentials are stored in a {@link CredentialAdapter} attached to the main
107 * {@link ListView} in the fragment.
108 */
109 private class AliasLoader extends AsyncTask<Void, Void, ListAdapter> {
110 @Override
111 protected ListAdapter doInBackground(Void... params) {
112 // Create a list of names for credential sets, ordered by name.
113 SortedMap<String, Credential> credentials = new TreeMap<>();
114 KeyStore keyStore = KeyStore.getInstance();
115 for (final Credential.Type type : Credential.Type.values()) {
116 for (final String alias : keyStore.list(type.prefix)) {
117 Credential c = credentials.get(alias);
118 if (c == null) {
119 credentials.put(alias, (c = new Credential(alias)));
120 }
121 c.storedTypes.add(type);
122 }
123 }
124
125 // Flatten to array so that the list can be presented via ArrayAdapter.
126 Credential[] results = credentials.values().toArray(new Credential[0]);
127 return new CredentialAdapter(getActivity(), R.layout.user_credential, results);
128 }
129
130 @Override
131 protected void onPostExecute(ListAdapter credentials) {
132 mListView.setAdapter(credentials);
133 }
134 }
135
136 /**
137 * Helper class to display {@link Credential}s in a list.
138 */
139 private static class CredentialAdapter extends ArrayAdapter<Credential> {
140 public CredentialAdapter(Context context, int resource, Credential[] objects) {
141 super(context, resource, objects);
142 }
143
144 @Override
145 public View getView(int position, View view, ViewGroup parent) {
146 if (view == null) {
147 view = LayoutInflater.from(getContext())
148 .inflate(R.layout.user_credential, parent, false);
149 }
150 Credential item = getItem(position);
151 ((TextView) view.findViewById(R.id.alias)).setText(item.alias);
152 view.findViewById(R.id.contents_userkey).setVisibility(
153 item.storedTypes.contains(Credential.Type.USER_PRIVATE_KEY) ? VISIBLE : GONE);
154 view.findViewById(R.id.contents_usercrt).setVisibility(
155 item.storedTypes.contains(Credential.Type.USER_CERTIFICATE) ? VISIBLE : GONE);
156 view.findViewById(R.id.contents_cacrt).setVisibility(
157 item.storedTypes.contains(Credential.Type.CA_CERTIFICATE) ? VISIBLE : GONE);
158 return view;
159 }
160 }
161
162 private static class Credential {
163 private static enum Type {
164 CA_CERTIFICATE (Credentials.CA_CERTIFICATE),
165 USER_CERTIFICATE (Credentials.USER_CERTIFICATE),
166 USER_PRIVATE_KEY (Credentials.USER_PRIVATE_KEY),
167 USER_SECRET_KEY (Credentials.USER_SECRET_KEY);
168
169 final String prefix;
170
171 Type(String prefix) {
172 this.prefix = prefix;
173 }
174 }
175
176 /**
177 * Main part of the credential's alias. To fetch an item from KeyStore, prepend one of the
178 * prefixes from {@link CredentialItem.storedTypes}.
179 */
180 final String alias;
181
182 /**
183 * Should contain some non-empty subset of:
184 * <ul>
185 * <li>{@link Credentials.CA_CERTIFICATE}</li>
186 * <li>{@link Credentials.USER_CERTIFICATE}</li>
187 * <li>{@link Credentials.USER_PRIVATE_KEY}</li>
188 * <li>{@link Credentials.USER_SECRET_KEY}</li>
189 * </ul>
190 */
191 final Set<Type> storedTypes = EnumSet.noneOf(Type.class);
192
193 Credential(final String alias) {
194 this.alias = alias;
195 }
196 }
197}