1baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Lee/*
2baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Lee * Copyright (C) 2015 The Android Open Source Project
3baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Lee *
4baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Lee * Licensed under the Apache License, Version 2.0 (the "License");
5baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Lee * you may not use this file except in compliance with the License.
6baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Lee * You may obtain a copy of the License at
7baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Lee *
8baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Lee *      http://www.apache.org/licenses/LICENSE-2.0
9baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Lee *
10baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Lee * Unless required by applicable law or agreed to in writing, software
11baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Lee * distributed under the License is distributed on an "AS IS" BASIS,
12baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Lee * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Lee * See the License for the specific language governing permissions and
14baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Lee * limitations under the License.
15baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Lee */
16baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Lee
17baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Leepackage com.android.settings;
18baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Lee
19e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Leeimport android.annotation.LayoutRes;
20e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Leeimport android.annotation.Nullable;
21baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Leeimport android.app.AlertDialog;
2204046a1976a049a0450ab3be9b6725d440a4b122Robin Leeimport android.app.Dialog;
2304046a1976a049a0450ab3be9b6725d440a4b122Robin Leeimport android.app.DialogFragment;
2404046a1976a049a0450ab3be9b6725d440a4b122Robin Leeimport android.app.Fragment;
25baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Leeimport android.content.Context;
26baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Leeimport android.content.DialogInterface;
27baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Leeimport android.os.AsyncTask;
28baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Leeimport android.os.Bundle;
2904046a1976a049a0450ab3be9b6725d440a4b122Robin Leeimport android.os.Parcel;
3004046a1976a049a0450ab3be9b6725d440a4b122Robin Leeimport android.os.Parcelable;
31e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Leeimport android.os.Process;
32da7bc51615000469cda841637538476edbb7502fRobin Leeimport android.os.RemoteException;
33c421db78f0e49efdc7923b7df62743ac73ecfd0cRobin Leeimport android.os.UserHandle;
34c421db78f0e49efdc7923b7df62743ac73ecfd0cRobin Leeimport android.os.UserManager;
35baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Leeimport android.security.Credentials;
36da7bc51615000469cda841637538476edbb7502fRobin Leeimport android.security.IKeyChainService;
37da7bc51615000469cda841637538476edbb7502fRobin Leeimport android.security.KeyChain;
38da7bc51615000469cda841637538476edbb7502fRobin Leeimport android.security.KeyChain.KeyChainConnection;
39baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Leeimport android.security.KeyStore;
40ccaf9c91fc6765c202ae31c197d03eb064f23c6cRobin Leeimport android.support.v7.widget.RecyclerView;
41da7bc51615000469cda841637538476edbb7502fRobin Leeimport android.util.Log;
42e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Leeimport android.util.SparseArray;
43baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Leeimport android.view.LayoutInflater;
44baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Leeimport android.view.View;
45baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Leeimport android.view.ViewGroup;
46baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Leeimport android.widget.TextView;
47baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Lee
48265d3c2a0c36251bf8a9f571d7239b6dd404d942Tamas Berghammerimport com.android.internal.logging.nano.MetricsProto.MetricsEvent;
499579274cda38c552b43febe0980f0ec6bd07277dRicky Waiimport com.android.internal.widget.LockPatternUtils;
501e516287bd0c910f83d2ead28bf67e26dfbead86Fan Zhangimport com.android.settings.core.instrumentation.InstrumentedDialogFragment;
51ccaf9c91fc6765c202ae31c197d03eb064f23c6cRobin Leeimport com.android.settings.SettingsPreferenceFragment;
52c421db78f0e49efdc7923b7df62743ac73ecfd0cRobin Leeimport com.android.settingslib.RestrictedLockUtils;
53c421db78f0e49efdc7923b7df62743ac73ecfd0cRobin Leeimport com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
54b70b3d86c96357c55e62386030cfe6634971ff7fRobin Lee
55e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Leeimport java.util.ArrayList;
56baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Leeimport java.util.EnumSet;
57e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Leeimport java.util.List;
58baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Leeimport java.util.SortedMap;
59baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Leeimport java.util.TreeMap;
60baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Lee
61baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Leeimport static android.view.View.GONE;
6239b467482d1bf256a111c757e9b7621c6f523271Jason Monkimport static android.view.View.VISIBLE;
63baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Lee
64ccaf9c91fc6765c202ae31c197d03eb064f23c6cRobin Leepublic class UserCredentialsSettings extends SettingsPreferenceFragment
65ccaf9c91fc6765c202ae31c197d03eb064f23c6cRobin Lee        implements View.OnClickListener {
66baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Lee    private static final String TAG = "UserCredentialsSettings";
67baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Lee
68baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Lee    @Override
696507613ebcd22e4691c2af92a5c161bd327db336Fan Zhang    public int getMetricsCategory() {
70b70b3d86c96357c55e62386030cfe6634971ff7fRobin Lee        return MetricsEvent.USER_CREDENTIALS;
71baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Lee    }
72baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Lee
73baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Lee    @Override
74baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Lee    public void onResume() {
75baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Lee        super.onResume();
7604046a1976a049a0450ab3be9b6725d440a4b122Robin Lee        refreshItems();
77baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Lee    }
78baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Lee
79baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Lee    @Override
80ccaf9c91fc6765c202ae31c197d03eb064f23c6cRobin Lee    public void onClick(final View view) {
81ccaf9c91fc6765c202ae31c197d03eb064f23c6cRobin Lee        final Credential item = (Credential) view.getTag();
82ccaf9c91fc6765c202ae31c197d03eb064f23c6cRobin Lee        if (item != null) {
83ccaf9c91fc6765c202ae31c197d03eb064f23c6cRobin Lee            CredentialDialogFragment.show(this, item);
84ccaf9c91fc6765c202ae31c197d03eb064f23c6cRobin Lee        }
8504046a1976a049a0450ab3be9b6725d440a4b122Robin Lee    }
8604046a1976a049a0450ab3be9b6725d440a4b122Robin Lee
8711fd5506ae9906b08cfa205914b21268cde91de6Robin Lee    protected void announceRemoval(String alias) {
88ccaf9c91fc6765c202ae31c197d03eb064f23c6cRobin Lee        if (!isAdded()) {
89ccaf9c91fc6765c202ae31c197d03eb064f23c6cRobin Lee            return;
9011fd5506ae9906b08cfa205914b21268cde91de6Robin Lee        }
91ccaf9c91fc6765c202ae31c197d03eb064f23c6cRobin Lee        getListView().announceForAccessibility(getString(R.string.user_credential_removed, alias));
9211fd5506ae9906b08cfa205914b21268cde91de6Robin Lee    }
9311fd5506ae9906b08cfa205914b21268cde91de6Robin Lee
9404046a1976a049a0450ab3be9b6725d440a4b122Robin Lee    protected void refreshItems() {
9504046a1976a049a0450ab3be9b6725d440a4b122Robin Lee        if (isAdded()) {
9604046a1976a049a0450ab3be9b6725d440a4b122Robin Lee            new AliasLoader().execute();
9704046a1976a049a0450ab3be9b6725d440a4b122Robin Lee        }
9804046a1976a049a0450ab3be9b6725d440a4b122Robin Lee    }
9904046a1976a049a0450ab3be9b6725d440a4b122Robin Lee
1001e516287bd0c910f83d2ead28bf67e26dfbead86Fan Zhang    public static class CredentialDialogFragment extends InstrumentedDialogFragment {
10104046a1976a049a0450ab3be9b6725d440a4b122Robin Lee        private static final String TAG = "CredentialDialogFragment";
10204046a1976a049a0450ab3be9b6725d440a4b122Robin Lee        private static final String ARG_CREDENTIAL = "credential";
10304046a1976a049a0450ab3be9b6725d440a4b122Robin Lee
10404046a1976a049a0450ab3be9b6725d440a4b122Robin Lee        public static void show(Fragment target, Credential item) {
10504046a1976a049a0450ab3be9b6725d440a4b122Robin Lee            final Bundle args = new Bundle();
10604046a1976a049a0450ab3be9b6725d440a4b122Robin Lee            args.putParcelable(ARG_CREDENTIAL, item);
10704046a1976a049a0450ab3be9b6725d440a4b122Robin Lee
108f8e2dbf2d2590cdee3ff69f13b102b97620125f0Robin Lee            if (target.getFragmentManager().findFragmentByTag(TAG) == null) {
109f8e2dbf2d2590cdee3ff69f13b102b97620125f0Robin Lee                final DialogFragment frag = new CredentialDialogFragment();
110f8e2dbf2d2590cdee3ff69f13b102b97620125f0Robin Lee                frag.setTargetFragment(target, /* requestCode */ -1);
111f8e2dbf2d2590cdee3ff69f13b102b97620125f0Robin Lee                frag.setArguments(args);
112f8e2dbf2d2590cdee3ff69f13b102b97620125f0Robin Lee                frag.show(target.getFragmentManager(), TAG);
113f8e2dbf2d2590cdee3ff69f13b102b97620125f0Robin Lee            }
11404046a1976a049a0450ab3be9b6725d440a4b122Robin Lee        }
115baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Lee
11604046a1976a049a0450ab3be9b6725d440a4b122Robin Lee        @Override
11704046a1976a049a0450ab3be9b6725d440a4b122Robin Lee        public Dialog onCreateDialog(Bundle savedInstanceState) {
11804046a1976a049a0450ab3be9b6725d440a4b122Robin Lee            final Credential item = (Credential) getArguments().getParcelable(ARG_CREDENTIAL);
119e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee
12004046a1976a049a0450ab3be9b6725d440a4b122Robin Lee            View root = getActivity().getLayoutInflater()
12104046a1976a049a0450ab3be9b6725d440a4b122Robin Lee                    .inflate(R.layout.user_credential_dialog, null);
12204046a1976a049a0450ab3be9b6725d440a4b122Robin Lee            ViewGroup infoContainer = (ViewGroup) root.findViewById(R.id.credential_container);
123e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee            View contentView = getCredentialView(item, R.layout.user_credential, null,
124e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee                    infoContainer, /* expanded */ true);
125e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee            infoContainer.addView(contentView);
126c421db78f0e49efdc7923b7df62743ac73ecfd0cRobin Lee
127c421db78f0e49efdc7923b7df62743ac73ecfd0cRobin Lee            AlertDialog.Builder builder = new AlertDialog.Builder(getActivity())
12804046a1976a049a0450ab3be9b6725d440a4b122Robin Lee                    .setView(root)
12904046a1976a049a0450ab3be9b6725d440a4b122Robin Lee                    .setTitle(R.string.user_credential_title)
130c421db78f0e49efdc7923b7df62743ac73ecfd0cRobin Lee                    .setPositiveButton(R.string.done, null);
131c421db78f0e49efdc7923b7df62743ac73ecfd0cRobin Lee
132c421db78f0e49efdc7923b7df62743ac73ecfd0cRobin Lee            final String restriction = UserManager.DISALLOW_CONFIG_CREDENTIALS;
133c421db78f0e49efdc7923b7df62743ac73ecfd0cRobin Lee            final int myUserId = UserHandle.myUserId();
134c421db78f0e49efdc7923b7df62743ac73ecfd0cRobin Lee            if (!RestrictedLockUtils.hasBaseUserRestriction(getContext(), restriction, myUserId)) {
135c421db78f0e49efdc7923b7df62743ac73ecfd0cRobin Lee                DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() {
136c421db78f0e49efdc7923b7df62743ac73ecfd0cRobin Lee                    @Override public void onClick(DialogInterface dialog, int id) {
137c421db78f0e49efdc7923b7df62743ac73ecfd0cRobin Lee                        final EnforcedAdmin admin = RestrictedLockUtils.checkIfRestrictionEnforced(
138c421db78f0e49efdc7923b7df62743ac73ecfd0cRobin Lee                                getContext(), restriction, myUserId);
139c421db78f0e49efdc7923b7df62743ac73ecfd0cRobin Lee                        if (admin != null) {
140c421db78f0e49efdc7923b7df62743ac73ecfd0cRobin Lee                            RestrictedLockUtils.sendShowAdminSupportDetailsIntent(getContext(),
141c421db78f0e49efdc7923b7df62743ac73ecfd0cRobin Lee                                    admin);
142c421db78f0e49efdc7923b7df62743ac73ecfd0cRobin Lee                        } else {
143e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee                            new RemoveCredentialsTask(getContext(), getTargetFragment())
144e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee                                    .execute(item);
145c421db78f0e49efdc7923b7df62743ac73ecfd0cRobin Lee                        }
146c421db78f0e49efdc7923b7df62743ac73ecfd0cRobin Lee                        dialog.dismiss();
147c421db78f0e49efdc7923b7df62743ac73ecfd0cRobin Lee                    }
148c421db78f0e49efdc7923b7df62743ac73ecfd0cRobin Lee                };
149e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee                if (item.isSystem()) {
150e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee                    // TODO: a safe means of clearing wifi certificates. Configs refer to aliases
151e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee                    //       directly so deleting certs will break dependent access points.
152e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee                    builder.setNegativeButton(R.string.trusted_credentials_remove_label, listener);
153e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee                }
154c421db78f0e49efdc7923b7df62743ac73ecfd0cRobin Lee            }
155c421db78f0e49efdc7923b7df62743ac73ecfd0cRobin Lee            return builder.create();
15604046a1976a049a0450ab3be9b6725d440a4b122Robin Lee        }
15704046a1976a049a0450ab3be9b6725d440a4b122Robin Lee
1581e516287bd0c910f83d2ead28bf67e26dfbead86Fan Zhang        @Override
1591e516287bd0c910f83d2ead28bf67e26dfbead86Fan Zhang        public int getMetricsCategory() {
1601e516287bd0c910f83d2ead28bf67e26dfbead86Fan Zhang            return MetricsEvent.DIALOG_USER_CREDENTIAL;
1611e516287bd0c910f83d2ead28bf67e26dfbead86Fan Zhang        }
1621e516287bd0c910f83d2ead28bf67e26dfbead86Fan Zhang
163e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee        /**
164e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee         * Deletes all certificates and keys under a given alias.
165e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee         *
166e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee         * If the {@link Credential} is for a system alias, all active grants to the alias will be
167e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee         * removed using {@link KeyChain}.
168e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee         */
169e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee        private class RemoveCredentialsTask extends AsyncTask<Credential, Void, Credential[]> {
170e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee            private Context context;
171da7bc51615000469cda841637538476edbb7502fRobin Lee            private Fragment targetFragment;
172da7bc51615000469cda841637538476edbb7502fRobin Lee
173e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee            public RemoveCredentialsTask(Context context, Fragment targetFragment) {
174e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee                this.context = context;
175da7bc51615000469cda841637538476edbb7502fRobin Lee                this.targetFragment = targetFragment;
176da7bc51615000469cda841637538476edbb7502fRobin Lee            }
177da7bc51615000469cda841637538476edbb7502fRobin Lee
178da7bc51615000469cda841637538476edbb7502fRobin Lee            @Override
179e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee            protected Credential[] doInBackground(Credential... credentials) {
180e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee                for (final Credential credential : credentials) {
181e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee                    if (credential.isSystem()) {
182e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee                        removeGrantsAndDelete(credential);
183e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee                        continue;
184da7bc51615000469cda841637538476edbb7502fRobin Lee                    }
185e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee                    throw new UnsupportedOperationException(
186e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee                            "Not implemented for wifi certificates. This should not be reachable.");
187e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee                }
188e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee                return credentials;
189e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee            }
190e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee
191e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee            private void removeGrantsAndDelete(final Credential credential) {
192e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee                final KeyChainConnection conn;
193e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee                try {
194e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee                    conn = KeyChain.bind(getContext());
195da7bc51615000469cda841637538476edbb7502fRobin Lee                } catch (InterruptedException e) {
196e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee                    Log.w(TAG, "Connecting to KeyChain", e);
197e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee                    return;
198e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee                }
199e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee
200e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee                try {
201e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee                    IKeyChainService keyChain = conn.getService();
202e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee                    keyChain.removeKeyPair(credential.alias);
203e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee                } catch (RemoteException e) {
204e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee                    Log.w(TAG, "Removing credentials", e);
205e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee                } finally {
206e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee                    conn.close();
207da7bc51615000469cda841637538476edbb7502fRobin Lee                }
208da7bc51615000469cda841637538476edbb7502fRobin Lee            }
209da7bc51615000469cda841637538476edbb7502fRobin Lee
210da7bc51615000469cda841637538476edbb7502fRobin Lee            @Override
211e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee            protected void onPostExecute(Credential... credentials) {
21211fd5506ae9906b08cfa205914b21268cde91de6Robin Lee                if (targetFragment instanceof UserCredentialsSettings && targetFragment.isAdded()) {
21311fd5506ae9906b08cfa205914b21268cde91de6Robin Lee                    final UserCredentialsSettings target = (UserCredentialsSettings) targetFragment;
214e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee                    for (final Credential credential : credentials) {
215e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee                        target.announceRemoval(credential.alias);
21611fd5506ae9906b08cfa205914b21268cde91de6Robin Lee                    }
21711fd5506ae9906b08cfa205914b21268cde91de6Robin Lee                    target.refreshItems();
218da7bc51615000469cda841637538476edbb7502fRobin Lee                }
21904046a1976a049a0450ab3be9b6725d440a4b122Robin Lee            }
22004046a1976a049a0450ab3be9b6725d440a4b122Robin Lee        }
221baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Lee    }
222baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Lee
223baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Lee    /**
224baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Lee     * Opens a background connection to KeyStore to list user credentials.
225baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Lee     * The credentials are stored in a {@link CredentialAdapter} attached to the main
226baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Lee     * {@link ListView} in the fragment.
227baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Lee     */
228e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee    private class AliasLoader extends AsyncTask<Void, Void, List<Credential>> {
229e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee        /**
230e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee         * @return a list of credentials ordered:
231e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee         * <ol>
232e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee         *   <li>first by purpose;</li>
233e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee         *   <li>then by alias.</li>
234e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee         * </ol>
235e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee         */
236baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Lee        @Override
237e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee        protected List<Credential> doInBackground(Void... params) {
238e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee            final KeyStore keyStore = KeyStore.getInstance();
239e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee
240e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee            // Certificates can be installed into SYSTEM_UID or WIFI_UID through CertInstaller.
241e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee            final int myUserId = UserHandle.myUserId();
242e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee            final int systemUid = UserHandle.getUid(myUserId, Process.SYSTEM_UID);
243e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee            final int wifiUid = UserHandle.getUid(myUserId, Process.WIFI_UID);
244e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee
245e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee            List<Credential> credentials = new ArrayList<>();
246e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee            credentials.addAll(getCredentialsForUid(keyStore, systemUid).values());
247e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee            credentials.addAll(getCredentialsForUid(keyStore, wifiUid).values());
248e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee            return credentials;
249e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee        }
250e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee
251e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee        private SortedMap<String, Credential> getCredentialsForUid(KeyStore keyStore, int uid) {
252e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee            final SortedMap<String, Credential> aliasMap = new TreeMap<>();
253baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Lee            for (final Credential.Type type : Credential.Type.values()) {
254e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee                for (final String alias : keyStore.list(type.prefix, uid)) {
25552221d80d20a3148f6b7d1e760f0ae00f0862180Rubin Xu                    if (UserHandle.getAppId(uid) == Process.SYSTEM_UID) {
25652221d80d20a3148f6b7d1e760f0ae00f0862180Rubin Xu                        // Do not show work profile keys in user credentials
25752221d80d20a3148f6b7d1e760f0ae00f0862180Rubin Xu                        if (alias.startsWith(LockPatternUtils.PROFILE_KEY_NAME_ENCRYPT) ||
25852221d80d20a3148f6b7d1e760f0ae00f0862180Rubin Xu                                alias.startsWith(LockPatternUtils.PROFILE_KEY_NAME_DECRYPT)) {
25952221d80d20a3148f6b7d1e760f0ae00f0862180Rubin Xu                            continue;
26052221d80d20a3148f6b7d1e760f0ae00f0862180Rubin Xu                        }
26152221d80d20a3148f6b7d1e760f0ae00f0862180Rubin Xu                        // Do not show synthetic password keys in user credential
26252221d80d20a3148f6b7d1e760f0ae00f0862180Rubin Xu                        if (alias.startsWith(LockPatternUtils.SYNTHETIC_PASSWORD_KEY_PREFIX)) {
26352221d80d20a3148f6b7d1e760f0ae00f0862180Rubin Xu                            continue;
26452221d80d20a3148f6b7d1e760f0ae00f0862180Rubin Xu                        }
2659579274cda38c552b43febe0980f0ec6bd07277dRicky Wai                    }
266e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee                    Credential c = aliasMap.get(alias);
267baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Lee                    if (c == null) {
268e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee                        c = new Credential(alias, uid);
269e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee                        aliasMap.put(alias, c);
270baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Lee                    }
271baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Lee                    c.storedTypes.add(type);
272baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Lee                }
273baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Lee            }
274e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee            return aliasMap;
275baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Lee        }
276baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Lee
277baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Lee        @Override
278e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee        protected void onPostExecute(List<Credential> credentials) {
279ccaf9c91fc6765c202ae31c197d03eb064f23c6cRobin Lee            if (!isAdded()) {
280ccaf9c91fc6765c202ae31c197d03eb064f23c6cRobin Lee                return;
281ccaf9c91fc6765c202ae31c197d03eb064f23c6cRobin Lee            }
282ccaf9c91fc6765c202ae31c197d03eb064f23c6cRobin Lee
283ccaf9c91fc6765c202ae31c197d03eb064f23c6cRobin Lee            if (credentials == null || credentials.size() == 0) {
284ccaf9c91fc6765c202ae31c197d03eb064f23c6cRobin Lee                // Create a "no credentials installed" message for the empty case.
285ccaf9c91fc6765c202ae31c197d03eb064f23c6cRobin Lee                TextView emptyTextView = (TextView) getActivity().findViewById(android.R.id.empty);
286ccaf9c91fc6765c202ae31c197d03eb064f23c6cRobin Lee                emptyTextView.setText(R.string.user_credential_none_installed);
287ccaf9c91fc6765c202ae31c197d03eb064f23c6cRobin Lee                setEmptyView(emptyTextView);
288ccaf9c91fc6765c202ae31c197d03eb064f23c6cRobin Lee            } else {
289ccaf9c91fc6765c202ae31c197d03eb064f23c6cRobin Lee                setEmptyView(null);
290ccaf9c91fc6765c202ae31c197d03eb064f23c6cRobin Lee            }
291ccaf9c91fc6765c202ae31c197d03eb064f23c6cRobin Lee
292ccaf9c91fc6765c202ae31c197d03eb064f23c6cRobin Lee            getListView().setAdapter(
293ccaf9c91fc6765c202ae31c197d03eb064f23c6cRobin Lee                    new CredentialAdapter(credentials, UserCredentialsSettings.this));
294baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Lee        }
295baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Lee    }
296baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Lee
297baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Lee    /**
298baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Lee     * Helper class to display {@link Credential}s in a list.
299baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Lee     */
300ccaf9c91fc6765c202ae31c197d03eb064f23c6cRobin Lee    private static class CredentialAdapter extends RecyclerView.Adapter<ViewHolder> {
301e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee        private static final int LAYOUT_RESOURCE = R.layout.user_credential_preference;
302e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee
303ccaf9c91fc6765c202ae31c197d03eb064f23c6cRobin Lee        private final List<Credential> mItems;
304ccaf9c91fc6765c202ae31c197d03eb064f23c6cRobin Lee        private final View.OnClickListener mListener;
305ccaf9c91fc6765c202ae31c197d03eb064f23c6cRobin Lee
306ccaf9c91fc6765c202ae31c197d03eb064f23c6cRobin Lee        public CredentialAdapter(List<Credential> items, @Nullable View.OnClickListener listener) {
307ccaf9c91fc6765c202ae31c197d03eb064f23c6cRobin Lee            mItems = items;
308ccaf9c91fc6765c202ae31c197d03eb064f23c6cRobin Lee            mListener = listener;
309ccaf9c91fc6765c202ae31c197d03eb064f23c6cRobin Lee        }
310ccaf9c91fc6765c202ae31c197d03eb064f23c6cRobin Lee
311ccaf9c91fc6765c202ae31c197d03eb064f23c6cRobin Lee        @Override
312ccaf9c91fc6765c202ae31c197d03eb064f23c6cRobin Lee        public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
313ccaf9c91fc6765c202ae31c197d03eb064f23c6cRobin Lee            final LayoutInflater inflater = LayoutInflater.from(parent.getContext());
314ccaf9c91fc6765c202ae31c197d03eb064f23c6cRobin Lee            return new ViewHolder(inflater.inflate(LAYOUT_RESOURCE, parent, false));
315baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Lee        }
316baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Lee
317baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Lee        @Override
318ccaf9c91fc6765c202ae31c197d03eb064f23c6cRobin Lee        public void onBindViewHolder(ViewHolder h, int position) {
319ccaf9c91fc6765c202ae31c197d03eb064f23c6cRobin Lee            getCredentialView(mItems.get(position), LAYOUT_RESOURCE, h.itemView, null, false);
320ccaf9c91fc6765c202ae31c197d03eb064f23c6cRobin Lee            h.itemView.setTag(mItems.get(position));
321ccaf9c91fc6765c202ae31c197d03eb064f23c6cRobin Lee            h.itemView.setOnClickListener(mListener);
322ccaf9c91fc6765c202ae31c197d03eb064f23c6cRobin Lee        }
323ccaf9c91fc6765c202ae31c197d03eb064f23c6cRobin Lee
324ccaf9c91fc6765c202ae31c197d03eb064f23c6cRobin Lee        @Override
325ccaf9c91fc6765c202ae31c197d03eb064f23c6cRobin Lee        public int getItemCount() {
326ccaf9c91fc6765c202ae31c197d03eb064f23c6cRobin Lee            return mItems.size();
327ccaf9c91fc6765c202ae31c197d03eb064f23c6cRobin Lee        }
328ccaf9c91fc6765c202ae31c197d03eb064f23c6cRobin Lee    }
329ccaf9c91fc6765c202ae31c197d03eb064f23c6cRobin Lee
330ccaf9c91fc6765c202ae31c197d03eb064f23c6cRobin Lee    private static class ViewHolder extends RecyclerView.ViewHolder {
331ccaf9c91fc6765c202ae31c197d03eb064f23c6cRobin Lee        public ViewHolder(View item) {
332ccaf9c91fc6765c202ae31c197d03eb064f23c6cRobin Lee            super(item);
333e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee        }
334e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee    }
335e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee
336e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee    /**
337e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee     * Mapping from View IDs in {@link R} to the types of credentials they describe.
338e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee     */
339e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee    private static final SparseArray<Credential.Type> credentialViewTypes = new SparseArray<>();
340e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee    static {
341e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee        credentialViewTypes.put(R.id.contents_userkey, Credential.Type.USER_PRIVATE_KEY);
342e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee        credentialViewTypes.put(R.id.contents_usercrt, Credential.Type.USER_CERTIFICATE);
343e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee        credentialViewTypes.put(R.id.contents_cacrt, Credential.Type.CA_CERTIFICATE);
344e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee    }
345e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee
346e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee    protected static View getCredentialView(Credential item, @LayoutRes int layoutResource,
347e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee            @Nullable View view, ViewGroup parent, boolean expanded) {
348e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee        if (view == null) {
349e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee            view = LayoutInflater.from(parent.getContext()).inflate(layoutResource, parent, false);
350e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee        }
351e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee
352e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee        ((TextView) view.findViewById(R.id.alias)).setText(item.alias);
353e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee        ((TextView) view.findViewById(R.id.purpose)).setText(item.isSystem()
354e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee                ? R.string.credential_for_vpn_and_apps
355e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee                : R.string.credential_for_wifi);
356e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee
357e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee        view.findViewById(R.id.contents).setVisibility(expanded ? View.VISIBLE : View.GONE);
358e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee        if (expanded) {
359e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee            for (int i = 0; i < credentialViewTypes.size(); i++) {
360e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee                final View detail = view.findViewById(credentialViewTypes.keyAt(i));
361e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee                detail.setVisibility(item.storedTypes.contains(credentialViewTypes.valueAt(i))
362e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee                        ? View.VISIBLE : View.GONE);
363baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Lee            }
364baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Lee        }
365e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee        return view;
366e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee    }
367e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee
368e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee    static class AliasEntry {
369e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee        public String alias;
370e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee        public int uid;
371baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Lee    }
372baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Lee
373e26804208ce22e6118333c7f39f9d21adc1d702bRobin Lee    static class Credential implements Parcelable {
374e26804208ce22e6118333c7f39f9d21adc1d702bRobin Lee        static enum Type {
375baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Lee            CA_CERTIFICATE (Credentials.CA_CERTIFICATE),
376baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Lee            USER_CERTIFICATE (Credentials.USER_CERTIFICATE),
377baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Lee            USER_PRIVATE_KEY (Credentials.USER_PRIVATE_KEY),
378baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Lee            USER_SECRET_KEY (Credentials.USER_SECRET_KEY);
379baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Lee
380baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Lee            final String prefix;
381baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Lee
382baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Lee            Type(String prefix) {
383baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Lee                this.prefix = prefix;
384baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Lee            }
385baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Lee        }
386baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Lee
387baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Lee        /**
388baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Lee         * Main part of the credential's alias. To fetch an item from KeyStore, prepend one of the
389baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Lee         * prefixes from {@link CredentialItem.storedTypes}.
390baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Lee         */
391baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Lee        final String alias;
392baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Lee
393baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Lee        /**
394e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee         * UID under which this credential is stored. Typically {@link Process#SYSTEM_UID} but can
395e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee         * also be {@link Process#WIFI_UID} for credentials installed as wifi certificates.
396e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee         */
397e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee        final int uid;
398e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee
399e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee        /**
400baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Lee         * Should contain some non-empty subset of:
401baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Lee         * <ul>
402baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Lee         *   <li>{@link Credentials.CA_CERTIFICATE}</li>
403baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Lee         *   <li>{@link Credentials.USER_CERTIFICATE}</li>
404baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Lee         *   <li>{@link Credentials.USER_PRIVATE_KEY}</li>
405baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Lee         *   <li>{@link Credentials.USER_SECRET_KEY}</li>
406baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Lee         * </ul>
407baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Lee         */
40804046a1976a049a0450ab3be9b6725d440a4b122Robin Lee        final EnumSet<Type> storedTypes = EnumSet.noneOf(Type.class);
409baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Lee
410e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee        Credential(final String alias, final int uid) {
411baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Lee            this.alias = alias;
412e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee            this.uid = uid;
413baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Lee        }
41404046a1976a049a0450ab3be9b6725d440a4b122Robin Lee
41504046a1976a049a0450ab3be9b6725d440a4b122Robin Lee        Credential(Parcel in) {
416e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee            this(in.readString(), in.readInt());
41704046a1976a049a0450ab3be9b6725d440a4b122Robin Lee
41804046a1976a049a0450ab3be9b6725d440a4b122Robin Lee            long typeBits = in.readLong();
41904046a1976a049a0450ab3be9b6725d440a4b122Robin Lee            for (Type i : Type.values()) {
42004046a1976a049a0450ab3be9b6725d440a4b122Robin Lee                if ((typeBits & (1L << i.ordinal())) != 0L) {
42104046a1976a049a0450ab3be9b6725d440a4b122Robin Lee                    storedTypes.add(i);
42204046a1976a049a0450ab3be9b6725d440a4b122Robin Lee                }
42304046a1976a049a0450ab3be9b6725d440a4b122Robin Lee            }
42404046a1976a049a0450ab3be9b6725d440a4b122Robin Lee        }
42504046a1976a049a0450ab3be9b6725d440a4b122Robin Lee
42604046a1976a049a0450ab3be9b6725d440a4b122Robin Lee        public void writeToParcel(Parcel out, int flags) {
42704046a1976a049a0450ab3be9b6725d440a4b122Robin Lee            out.writeString(alias);
428e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee            out.writeInt(uid);
42904046a1976a049a0450ab3be9b6725d440a4b122Robin Lee
43004046a1976a049a0450ab3be9b6725d440a4b122Robin Lee            long typeBits = 0;
43104046a1976a049a0450ab3be9b6725d440a4b122Robin Lee            for (Type i : storedTypes) {
43204046a1976a049a0450ab3be9b6725d440a4b122Robin Lee                typeBits |= 1L << i.ordinal();
43304046a1976a049a0450ab3be9b6725d440a4b122Robin Lee            }
43404046a1976a049a0450ab3be9b6725d440a4b122Robin Lee            out.writeLong(typeBits);
43504046a1976a049a0450ab3be9b6725d440a4b122Robin Lee        }
43604046a1976a049a0450ab3be9b6725d440a4b122Robin Lee
43704046a1976a049a0450ab3be9b6725d440a4b122Robin Lee        public int describeContents() {
43804046a1976a049a0450ab3be9b6725d440a4b122Robin Lee            return 0;
43904046a1976a049a0450ab3be9b6725d440a4b122Robin Lee        }
44004046a1976a049a0450ab3be9b6725d440a4b122Robin Lee
44104046a1976a049a0450ab3be9b6725d440a4b122Robin Lee        public static final Parcelable.Creator<Credential> CREATOR
44204046a1976a049a0450ab3be9b6725d440a4b122Robin Lee                = new Parcelable.Creator<Credential>() {
44304046a1976a049a0450ab3be9b6725d440a4b122Robin Lee            public Credential createFromParcel(Parcel in) {
44404046a1976a049a0450ab3be9b6725d440a4b122Robin Lee                return new Credential(in);
44504046a1976a049a0450ab3be9b6725d440a4b122Robin Lee            }
44604046a1976a049a0450ab3be9b6725d440a4b122Robin Lee
44704046a1976a049a0450ab3be9b6725d440a4b122Robin Lee            public Credential[] newArray(int size) {
44804046a1976a049a0450ab3be9b6725d440a4b122Robin Lee                return new Credential[size];
44904046a1976a049a0450ab3be9b6725d440a4b122Robin Lee            }
45004046a1976a049a0450ab3be9b6725d440a4b122Robin Lee        };
451e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee
452e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee        public boolean isSystem() {
453e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee            return UserHandle.getAppId(uid) == Process.SYSTEM_UID;
454e68d9577772d312a4a8e7f47d6f2a74e0a5c2615Robin Lee        }
455baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Lee    }
456baefdcf9eb6f1ee9bf45b65b5e319be174e60735Robin Lee}
457