Home | History | Annotate | Download | only in settings
      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  */
     16 
     17 package com.android.settings;
     18 
     19 import android.app.AlertDialog;
     20 import android.app.Dialog;
     21 import android.app.Fragment;
     22 import android.content.Context;
     23 import android.content.DialogInterface;
     24 import android.content.pm.UserInfo;
     25 import android.content.res.TypedArray;
     26 import android.net.http.SslCertificate;
     27 import android.os.AsyncTask;
     28 import android.os.Bundle;
     29 import android.os.RemoteException;
     30 import android.os.UserHandle;
     31 import android.os.UserManager;
     32 import android.security.IKeyChainService;
     33 import android.security.KeyChain;
     34 import android.security.KeyChain.KeyChainConnection;
     35 import android.util.SparseArray;
     36 import android.util.Log;
     37 import android.view.LayoutInflater;
     38 import android.view.View;
     39 import android.view.ViewGroup;
     40 import android.widget.AdapterView;
     41 import android.widget.AdapterView.OnItemSelectedListener;
     42 import android.widget.ArrayAdapter;
     43 import android.widget.BaseAdapter;
     44 import android.widget.BaseExpandableListAdapter;
     45 import android.widget.Button;
     46 import android.widget.CheckBox;
     47 import android.widget.ExpandableListView;
     48 import android.widget.LinearLayout;
     49 import android.widget.ListView;
     50 import android.widget.ProgressBar;
     51 import android.widget.Spinner;
     52 import android.widget.TabHost;
     53 import android.widget.TextView;
     54 
     55 import com.android.internal.util.ParcelableString;
     56 
     57 import java.security.cert.CertificateEncodingException;
     58 import java.security.cert.X509Certificate;
     59 import java.util.ArrayList;
     60 import java.util.Collections;
     61 import java.util.List;
     62 
     63 public class TrustedCredentialsSettings extends Fragment {
     64 
     65     private static final String TAG = "TrustedCredentialsSettings";
     66 
     67     private UserManager mUserManager;
     68 
     69     private static final String USER_ACTION = "com.android.settings.TRUSTED_CREDENTIALS_USER";
     70 
     71     private enum Tab {
     72         SYSTEM("system",
     73                R.string.trusted_credentials_system_tab,
     74                R.id.system_tab,
     75                R.id.system_progress,
     76                R.id.system_list,
     77                R.id.system_expandable_list,
     78                true),
     79         USER("user",
     80              R.string.trusted_credentials_user_tab,
     81              R.id.user_tab,
     82              R.id.user_progress,
     83              R.id.user_list,
     84              R.id.user_expandable_list,
     85              false);
     86 
     87         private final String mTag;
     88         private final int mLabel;
     89         private final int mView;
     90         private final int mProgress;
     91         private final int mList;
     92         private final int mExpandableList;
     93         private final boolean mCheckbox;
     94 
     95         private Tab(String tag, int label, int view, int progress, int list, int expandableList,
     96                 boolean checkbox) {
     97             mTag = tag;
     98             mLabel = label;
     99             mView = view;
    100             mProgress = progress;
    101             mList = list;
    102             mExpandableList = expandableList;
    103             mCheckbox = checkbox;
    104         }
    105 
    106         private List<ParcelableString> getAliases(IKeyChainService service) throws RemoteException {
    107             switch (this) {
    108                 case SYSTEM: {
    109                     return service.getSystemCaAliases().getList();
    110                 }
    111                 case USER:
    112                     return service.getUserCaAliases().getList();
    113             }
    114             throw new AssertionError();
    115         }
    116         private boolean deleted(IKeyChainService service, String alias) throws RemoteException {
    117             switch (this) {
    118                 case SYSTEM:
    119                     return !service.containsCaAlias(alias);
    120                 case USER:
    121                     return false;
    122             }
    123             throw new AssertionError();
    124         }
    125         private int getButtonLabel(CertHolder certHolder) {
    126             switch (this) {
    127                 case SYSTEM:
    128                     if (certHolder.mDeleted) {
    129                         return R.string.trusted_credentials_enable_label;
    130                     }
    131                     return R.string.trusted_credentials_disable_label;
    132                 case USER:
    133                     return R.string.trusted_credentials_remove_label;
    134             }
    135             throw new AssertionError();
    136         }
    137         private int getButtonConfirmation(CertHolder certHolder) {
    138             switch (this) {
    139                 case SYSTEM:
    140                     if (certHolder.mDeleted) {
    141                         return R.string.trusted_credentials_enable_confirmation;
    142                     }
    143                     return R.string.trusted_credentials_disable_confirmation;
    144                 case USER:
    145                     return R.string.trusted_credentials_remove_confirmation;
    146             }
    147             throw new AssertionError();
    148         }
    149         private void postOperationUpdate(boolean ok, CertHolder certHolder) {
    150             if (ok) {
    151                 if (certHolder.mTab.mCheckbox) {
    152                     certHolder.mDeleted = !certHolder.mDeleted;
    153                 } else {
    154                     certHolder.mAdapter.remove(certHolder);
    155                 }
    156                 certHolder.mAdapter.notifyDataSetChanged();
    157             } else {
    158                 // bail, reload to reset to known state
    159                 certHolder.mAdapter.load();
    160             }
    161         }
    162     }
    163 
    164     private TabHost mTabHost;
    165     private final SparseArray<KeyChainConnection>
    166             mKeyChainConnectionByProfileId = new SparseArray<KeyChainConnection>();
    167 
    168     @Override
    169     public void onCreate(Bundle savedInstanceState) {
    170         super.onCreate(savedInstanceState);
    171         mUserManager = (UserManager) getActivity().getSystemService(Context.USER_SERVICE);
    172     }
    173 
    174 
    175     @Override public View onCreateView(
    176             LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {
    177         mTabHost = (TabHost) inflater.inflate(R.layout.trusted_credentials, parent, false);
    178         mTabHost.setup();
    179         addTab(Tab.SYSTEM);
    180         // TODO add Install button on Tab.USER to go to CertInstaller like KeyChainActivity
    181         addTab(Tab.USER);
    182         if (getActivity().getIntent() != null &&
    183                 USER_ACTION.equals(getActivity().getIntent().getAction())) {
    184             mTabHost.setCurrentTabByTag(Tab.USER.mTag);
    185         }
    186         return mTabHost;
    187     }
    188     @Override
    189     public void onDestroy() {
    190         closeKeyChainConnections();
    191         super.onDestroy();
    192     }
    193 
    194     private void closeKeyChainConnections() {
    195         final int n = mKeyChainConnectionByProfileId.size();
    196         for (int i = 0; i < n; ++i) {
    197             mKeyChainConnectionByProfileId.valueAt(i).close();
    198         }
    199         mKeyChainConnectionByProfileId.clear();
    200     }
    201 
    202     private void addTab(Tab tab) {
    203         TabHost.TabSpec systemSpec = mTabHost.newTabSpec(tab.mTag)
    204                 .setIndicator(getActivity().getString(tab.mLabel))
    205                 .setContent(tab.mView);
    206         mTabHost.addTab(systemSpec);
    207 
    208         if (mUserManager.getUserProfiles().size() > 1) {
    209             ExpandableListView lv = (ExpandableListView) mTabHost.findViewById(tab.mExpandableList);
    210             final TrustedCertificateExpandableAdapter adapter =
    211                     new TrustedCertificateExpandableAdapter(tab);
    212             lv.setAdapter(adapter);
    213             lv.setOnChildClickListener(new ExpandableListView.OnChildClickListener() {
    214                     @Override
    215                 public boolean onChildClick(ExpandableListView parent, View v,
    216                         int groupPosition, int childPosition, long id) {
    217                     showCertDialog(adapter.getChild(groupPosition, childPosition));
    218                     return true;
    219                 }
    220             });
    221         } else {
    222             ListView lv = (ListView) mTabHost.findViewById(tab.mList);
    223             final TrustedCertificateAdapter adapter = new TrustedCertificateAdapter(tab);
    224             lv.setAdapter(adapter);
    225             lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
    226                 @Override public void onItemClick(AdapterView<?> parent, View view,
    227                         int pos, long id) {
    228                     showCertDialog(adapter.getItem(pos));
    229                 }
    230             });
    231         }
    232     }
    233 
    234     /**
    235      * Common interface for adapters of both expandable and non-expandable certificate lists.
    236      */
    237     private interface TrustedCertificateAdapterCommons {
    238         /**
    239          * Remove a certificate from the list.
    240          * @param certHolder the certificate to be removed.
    241          */
    242         void remove(CertHolder certHolder);
    243         /**
    244          * Notify the adapter that the underlying data set has changed.
    245          */
    246         void notifyDataSetChanged();
    247         /**
    248          * Load the certificates.
    249          */
    250         void load();
    251         /**
    252          * Gets the identifier of the list view the adapter is connected to.
    253          * @param tab the tab on which the list view resides.
    254          * @return identifier of the list view.
    255          */
    256         int getListViewId(Tab tab);
    257     }
    258 
    259     /**
    260      * Adapter for expandable list view of certificates. Groups in the view correspond to profiles
    261      * whereas children correspond to certificates.
    262      */
    263     private class TrustedCertificateExpandableAdapter extends BaseExpandableListAdapter implements
    264             TrustedCertificateAdapterCommons {
    265         private AdapterData mData;
    266 
    267         private TrustedCertificateExpandableAdapter(Tab tab) {
    268             mData = new AdapterData(tab, this);
    269             load();
    270         }
    271         @Override
    272         public void remove(CertHolder certHolder) {
    273             mData.remove(certHolder);
    274         }
    275         @Override
    276         public int getGroupCount() {
    277             return mData.mCertHoldersByUserId.size();
    278         }
    279         @Override
    280         public int getChildrenCount(int groupPosition) {
    281             List<CertHolder> certHolders = mData.mCertHoldersByUserId.valueAt(groupPosition);
    282             if (certHolders != null) {
    283                 return certHolders.size();
    284             }
    285             return 0;
    286         }
    287         @Override
    288         public UserHandle getGroup(int groupPosition) {
    289             return new UserHandle(mData.mCertHoldersByUserId.keyAt(groupPosition));
    290         }
    291         @Override
    292         public CertHolder getChild(int groupPosition, int childPosition) {
    293             return mData.mCertHoldersByUserId.valueAt(groupPosition).get(childPosition);
    294         }
    295         @Override
    296         public long getGroupId(int groupPosition) {
    297             return mData.mCertHoldersByUserId.keyAt(groupPosition);
    298         }
    299         @Override
    300         public long getChildId(int groupPosition, int childPosition) {
    301             return childPosition;
    302         }
    303         @Override
    304         public boolean hasStableIds() {
    305             return false;
    306         }
    307         @Override
    308         public View getGroupView(int groupPosition, boolean isExpanded, View convertView,
    309                 ViewGroup parent) {
    310             if (convertView == null) {
    311                 LayoutInflater inflater = (LayoutInflater) getActivity()
    312                         .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    313                 convertView = inflateCategoryHeader(inflater, parent);
    314             }
    315 
    316             final TextView title = (TextView) convertView.findViewById(android.R.id.title);
    317             final UserHandle profile = getGroup(groupPosition);
    318             final UserInfo userInfo = mUserManager.getUserInfo(profile.getIdentifier());
    319             if (userInfo.isManagedProfile()) {
    320                 title.setText(R.string.category_work);
    321             } else {
    322                 title.setText(R.string.category_personal);
    323             }
    324             title.setTextAlignment(View.TEXT_ALIGNMENT_VIEW_END);
    325 
    326             return convertView;
    327         }
    328         @Override
    329         public View getChildView(int groupPosition, int childPosition, boolean isLastChild,
    330                 View convertView, ViewGroup parent) {
    331             return getViewForCertificate(getChild(groupPosition, childPosition), mData.mTab,
    332                     convertView, parent);
    333         }
    334         @Override
    335         public boolean isChildSelectable(int groupPosition, int childPosition) {
    336             return true;
    337         }
    338         @Override
    339         public void load() {
    340             mData.new AliasLoader().execute();
    341         }
    342         @Override
    343         public int getListViewId(Tab tab) {
    344             return tab.mExpandableList;
    345         }
    346         private View inflateCategoryHeader(LayoutInflater inflater, ViewGroup parent) {
    347             final TypedArray a = inflater.getContext().obtainStyledAttributes(null,
    348                     com.android.internal.R.styleable.Preference,
    349                     com.android.internal.R.attr.preferenceCategoryStyle, 0);
    350             final int resId = a.getResourceId(com.android.internal.R.styleable.Preference_layout,
    351                     0);
    352             return inflater.inflate(resId, parent, false);
    353         }
    354 
    355     }
    356 
    357     private class TrustedCertificateAdapter extends BaseAdapter implements
    358             TrustedCertificateAdapterCommons {
    359         private final AdapterData mData;
    360         private TrustedCertificateAdapter(Tab tab) {
    361             mData = new AdapterData(tab, this);
    362             load();
    363         }
    364         @Override
    365         public void remove(CertHolder certHolder) {
    366             mData.remove(certHolder);
    367         }
    368         @Override
    369         public int getListViewId(Tab tab) {
    370             return tab.mList;
    371         }
    372         @Override
    373         public void load() {
    374             mData.new AliasLoader().execute();
    375         }
    376         @Override public int getCount() {
    377             List<CertHolder> certHolders = mData.mCertHoldersByUserId.valueAt(0);
    378             if (certHolders != null) {
    379                 return certHolders.size();
    380             }
    381             return 0;
    382         }
    383         @Override public CertHolder getItem(int position) {
    384             return mData.mCertHoldersByUserId.valueAt(0).get(position);
    385         }
    386         @Override public long getItemId(int position) {
    387             return position;
    388         }
    389         @Override public View getView(int position, View view, ViewGroup parent) {
    390             return getViewForCertificate(getItem(position), mData.mTab, view, parent);
    391         }
    392     }
    393 
    394     private class AdapterData {
    395         private final SparseArray<List<CertHolder>> mCertHoldersByUserId =
    396                 new SparseArray<List<CertHolder>>();
    397         private final Tab mTab;
    398         private final TrustedCertificateAdapterCommons mAdapter;
    399 
    400         private AdapterData(Tab tab, TrustedCertificateAdapterCommons adapter) {
    401             mAdapter = adapter;
    402             mTab = tab;
    403         }
    404 
    405         private class AliasLoader extends AsyncTask<Void, Integer, SparseArray<List<CertHolder>>> {
    406             private ProgressBar mProgressBar;
    407             private View mList;
    408 
    409             @Override protected void onPreExecute() {
    410                 View content = mTabHost.getTabContentView();
    411                 mProgressBar = (ProgressBar) content.findViewById(mTab.mProgress);
    412                 mList = content.findViewById(mAdapter.getListViewId(mTab));
    413                 mProgressBar.setVisibility(View.VISIBLE);
    414                 mList.setVisibility(View.GONE);
    415             }
    416             @Override protected SparseArray<List<CertHolder>> doInBackground(Void... params) {
    417                 SparseArray<List<CertHolder>> certHoldersByProfile =
    418                         new SparseArray<List<CertHolder>>();
    419                 try {
    420                     List<UserHandle> profiles = mUserManager.getUserProfiles();
    421                     final int n = profiles.size();
    422                     // First we get all aliases for all profiles in order to show progress
    423                     // correctly. Otherwise this could all be in a single loop.
    424                     SparseArray<List<ParcelableString>> aliasesByProfileId = new SparseArray<
    425                             List<ParcelableString>>(n);
    426                     int max = 0;
    427                     int progress = 0;
    428                     for (int i = 0; i < n; ++i) {
    429                         UserHandle profile = profiles.get(i);
    430                         int profileId = profile.getIdentifier();
    431                         KeyChainConnection keyChainConnection = KeyChain.bindAsUser(getActivity(),
    432                                 profile);
    433                         // Saving the connection for later use on the certificate dialog.
    434                         mKeyChainConnectionByProfileId.put(profileId, keyChainConnection);
    435                         IKeyChainService service = keyChainConnection.getService();
    436                         List<ParcelableString> aliases = mTab.getAliases(service);
    437                         max += aliases.size();
    438                         aliasesByProfileId.put(profileId, aliases);
    439                     }
    440                     for (int i = 0; i < n; ++i) {
    441                         UserHandle profile = profiles.get(i);
    442                         int profileId = profile.getIdentifier();
    443                         List<ParcelableString> aliases = aliasesByProfileId.get(profileId);
    444                         IKeyChainService service = mKeyChainConnectionByProfileId.get(profileId)
    445                                 .getService();
    446                         List<CertHolder> certHolders = new ArrayList<CertHolder>(max);
    447                         final int aliasMax = aliases.size();
    448                         for (int j = 0; j < aliasMax; ++j) {
    449                             String alias = aliases.get(j).string;
    450                             byte[] encodedCertificate = service.getEncodedCaCertificate(alias,
    451                                     true);
    452                             X509Certificate cert = KeyChain.toCertificate(encodedCertificate);
    453                             certHolders.add(new CertHolder(service, mAdapter,
    454                                     mTab, alias, cert, profileId));
    455                             publishProgress(++progress, max);
    456                         }
    457                         Collections.sort(certHolders);
    458                         certHoldersByProfile.put(profileId, certHolders);
    459                     }
    460                     return certHoldersByProfile;
    461                 } catch (RemoteException e) {
    462                     Log.e(TAG, "Remote exception while loading aliases.", e);
    463                     return new SparseArray<List<CertHolder>>();
    464                 } catch (InterruptedException e) {
    465                     Log.e(TAG, "InterruptedException while loading aliases.", e);
    466                     return new SparseArray<List<CertHolder>>();
    467                 }
    468             }
    469             @Override protected void onProgressUpdate(Integer... progressAndMax) {
    470                 int progress = progressAndMax[0];
    471                 int max = progressAndMax[1];
    472                 if (max != mProgressBar.getMax()) {
    473                     mProgressBar.setMax(max);
    474                 }
    475                 mProgressBar.setProgress(progress);
    476             }
    477             @Override protected void onPostExecute(SparseArray<List<CertHolder>> certHolders) {
    478                 mCertHoldersByUserId.clear();
    479                 final int n = certHolders.size();
    480                 for (int i = 0; i < n; ++i) {
    481                     mCertHoldersByUserId.put(certHolders.keyAt(i), certHolders.valueAt(i));
    482                 }
    483                 mAdapter.notifyDataSetChanged();
    484                 mProgressBar.setVisibility(View.GONE);
    485                 mList.setVisibility(View.VISIBLE);
    486                 mProgressBar.setProgress(0);
    487             }
    488         }
    489 
    490         public void remove(CertHolder certHolder) {
    491             if (mCertHoldersByUserId != null) {
    492                 final List<CertHolder> certs = mCertHoldersByUserId.get(certHolder.mProfileId);
    493                 if (certs != null) {
    494                     certs.remove(certHolder);
    495                 }
    496             }
    497         }
    498     }
    499 
    500     private static class CertHolder implements Comparable<CertHolder> {
    501         public int mProfileId;
    502         private final IKeyChainService mService;
    503         private final TrustedCertificateAdapterCommons mAdapter;
    504         private final Tab mTab;
    505         private final String mAlias;
    506         private final X509Certificate mX509Cert;
    507 
    508         private final SslCertificate mSslCert;
    509         private final String mSubjectPrimary;
    510         private final String mSubjectSecondary;
    511         private boolean mDeleted;
    512 
    513         private CertHolder(IKeyChainService service,
    514                            TrustedCertificateAdapterCommons adapter,
    515                            Tab tab,
    516                            String alias,
    517                            X509Certificate x509Cert,
    518                            int profileId) {
    519             mProfileId = profileId;
    520             mService = service;
    521             mAdapter = adapter;
    522             mTab = tab;
    523             mAlias = alias;
    524             mX509Cert = x509Cert;
    525 
    526             mSslCert = new SslCertificate(x509Cert);
    527 
    528             String cn = mSslCert.getIssuedTo().getCName();
    529             String o = mSslCert.getIssuedTo().getOName();
    530             String ou = mSslCert.getIssuedTo().getUName();
    531             // if we have a O, use O as primary subject, secondary prefer CN over OU
    532             // if we don't have an O, use CN as primary, empty secondary
    533             // if we don't have O or CN, use DName as primary, empty secondary
    534             if (!o.isEmpty()) {
    535                 if (!cn.isEmpty()) {
    536                     mSubjectPrimary = o;
    537                     mSubjectSecondary = cn;
    538                 } else {
    539                     mSubjectPrimary = o;
    540                     mSubjectSecondary = ou;
    541                 }
    542             } else {
    543                 if (!cn.isEmpty()) {
    544                     mSubjectPrimary = cn;
    545                     mSubjectSecondary = "";
    546                 } else {
    547                     mSubjectPrimary = mSslCert.getIssuedTo().getDName();
    548                     mSubjectSecondary = "";
    549                 }
    550             }
    551             try {
    552                 mDeleted = mTab.deleted(mService, mAlias);
    553             } catch (RemoteException e) {
    554                 Log.e(TAG, "Remote exception while checking if alias " + mAlias + " is deleted.",
    555                         e);
    556                 mDeleted = false;
    557             }
    558         }
    559         @Override public int compareTo(CertHolder o) {
    560             int primary = this.mSubjectPrimary.compareToIgnoreCase(o.mSubjectPrimary);
    561             if (primary != 0) {
    562                 return primary;
    563             }
    564             return this.mSubjectSecondary.compareToIgnoreCase(o.mSubjectSecondary);
    565         }
    566         @Override public boolean equals(Object o) {
    567             if (!(o instanceof CertHolder)) {
    568                 return false;
    569             }
    570             CertHolder other = (CertHolder) o;
    571             return mAlias.equals(other.mAlias);
    572         }
    573         @Override public int hashCode() {
    574             return mAlias.hashCode();
    575         }
    576     }
    577 
    578     private View getViewForCertificate(CertHolder certHolder, Tab mTab, View convertView,
    579             ViewGroup parent) {
    580         ViewHolder holder;
    581         if (convertView == null) {
    582             LayoutInflater inflater = LayoutInflater.from(getActivity());
    583             convertView = inflater.inflate(R.layout.trusted_credential, parent, false);
    584             holder = new ViewHolder();
    585             holder.mSubjectPrimaryView = (TextView)
    586                     convertView.findViewById(R.id.trusted_credential_subject_primary);
    587             holder.mSubjectSecondaryView = (TextView)
    588                     convertView.findViewById(R.id.trusted_credential_subject_secondary);
    589             holder.mCheckBox = (CheckBox) convertView.findViewById(
    590                     R.id.trusted_credential_status);
    591             convertView.setTag(holder);
    592         } else {
    593             holder = (ViewHolder) convertView.getTag();
    594         }
    595         holder.mSubjectPrimaryView.setText(certHolder.mSubjectPrimary);
    596         holder.mSubjectSecondaryView.setText(certHolder.mSubjectSecondary);
    597         if (mTab.mCheckbox) {
    598             holder.mCheckBox.setChecked(!certHolder.mDeleted);
    599             holder.mCheckBox.setVisibility(View.VISIBLE);
    600         }
    601         return convertView;
    602     }
    603 
    604     private static class ViewHolder {
    605         private TextView mSubjectPrimaryView;
    606         private TextView mSubjectSecondaryView;
    607         private CheckBox mCheckBox;
    608     }
    609 
    610     private void showCertDialog(final CertHolder certHolder) {
    611         AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
    612         builder.setTitle(com.android.internal.R.string.ssl_certificate);
    613 
    614         final ArrayList<View> views =  new ArrayList<View>();
    615         final ArrayList<String> titles = new ArrayList<String>();
    616         addCertChain(certHolder, views, titles);
    617 
    618         ArrayAdapter<String> arrayAdapter = new ArrayAdapter<String>(getActivity(),
    619                 android.R.layout.simple_spinner_item,
    620                 titles);
    621         arrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
    622         Spinner spinner = new Spinner(getActivity());
    623         spinner.setAdapter(arrayAdapter);
    624         spinner.setOnItemSelectedListener(new OnItemSelectedListener() {
    625                 @Override
    626                 public void onItemSelected(AdapterView<?> parent, View view, int position,
    627                         long id) {
    628                     for(int i = 0; i < views.size(); i++) {
    629                         views.get(i).setVisibility(i == position ? View.VISIBLE : View.GONE);
    630                     }
    631                 }
    632                @Override
    633                public void onNothingSelected(AdapterView<?> parent) { }
    634             });
    635 
    636         LinearLayout container = new LinearLayout(getActivity());
    637         container.setOrientation(LinearLayout.VERTICAL);
    638         container.addView(spinner);
    639         for (int i = 0; i < views.size(); ++i) {
    640             View certificateView = views.get(i);
    641             if (i != 0) {
    642                 certificateView.setVisibility(View.GONE);
    643             }
    644             container.addView(certificateView);
    645         }
    646         builder.setView(container);
    647         builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
    648             @Override public void onClick(DialogInterface dialog, int id) {
    649                 dialog.dismiss();
    650             }
    651         });
    652         final Dialog certDialog = builder.create();
    653 
    654         ViewGroup body = (ViewGroup) container.findViewById(com.android.internal.R.id.body);
    655         LayoutInflater inflater = LayoutInflater.from(getActivity());
    656         Button removeButton = (Button) inflater.inflate(R.layout.trusted_credential_details,
    657                                                         body,
    658                                                         false);
    659         if (!mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_CREDENTIALS)) {
    660             body.addView(removeButton);
    661         }
    662         removeButton.setText(certHolder.mTab.getButtonLabel(certHolder));
    663         removeButton.setOnClickListener(new View.OnClickListener() {
    664             @Override public void onClick(View v) {
    665                 AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
    666                 builder.setMessage(certHolder.mTab.getButtonConfirmation(certHolder));
    667                 builder.setPositiveButton(
    668                         android.R.string.yes, new DialogInterface.OnClickListener() {
    669                     @Override public void onClick(DialogInterface dialog, int id) {
    670                         new AliasOperation(certHolder).execute();
    671                         dialog.dismiss();
    672                         certDialog.dismiss();
    673                     }
    674                 });
    675                 builder.setNegativeButton(
    676                         android.R.string.no, new DialogInterface.OnClickListener() {
    677                     @Override public void onClick(DialogInterface dialog, int id) {
    678                         dialog.cancel();
    679                     }
    680                 });
    681                 AlertDialog alert = builder.create();
    682                 alert.show();
    683             }
    684         });
    685 
    686         certDialog.show();
    687     }
    688 
    689     private void addCertChain(final CertHolder certHolder,
    690             final ArrayList<View> views, final ArrayList<String> titles) {
    691 
    692         List<X509Certificate> certificates = null;
    693         try {
    694             KeyChainConnection keyChainConnection = mKeyChainConnectionByProfileId.get(
    695                     certHolder.mProfileId);
    696             IKeyChainService service = keyChainConnection.getService();
    697             List<String> chain = service.getCaCertificateChainAliases(certHolder.mAlias, true);
    698             final int n = chain.size();
    699             certificates = new ArrayList<X509Certificate>(n);
    700             for (int i = 0; i < n; ++i) {
    701                 byte[] encodedCertificate = service.getEncodedCaCertificate(chain.get(i), true);
    702                 X509Certificate certificate = KeyChain.toCertificate(encodedCertificate);
    703                 certificates.add(certificate);
    704             }
    705         } catch (RemoteException ex) {
    706             Log.e(TAG, "RemoteException while retrieving certificate chain for root "
    707                     + certHolder.mAlias, ex);
    708             return;
    709         }
    710         for (X509Certificate certificate : certificates) {
    711             addCertDetails(certificate, views, titles);
    712         }
    713     }
    714 
    715     private void addCertDetails(X509Certificate certificate, final ArrayList<View> views,
    716             final ArrayList<String> titles) {
    717         SslCertificate sslCert = new SslCertificate(certificate);
    718         views.add(sslCert.inflateCertificateView(getActivity()));
    719         titles.add(sslCert.getIssuedTo().getCName());
    720     }
    721 
    722     private class AliasOperation extends AsyncTask<Void, Void, Boolean> {
    723         private final CertHolder mCertHolder;
    724 
    725         private AliasOperation(CertHolder certHolder) {
    726             mCertHolder = certHolder;
    727         }
    728 
    729         @Override
    730         protected Boolean doInBackground(Void... params) {
    731             try {
    732                 KeyChainConnection keyChainConnection = mKeyChainConnectionByProfileId.get(
    733                         mCertHolder.mProfileId);
    734                 IKeyChainService service = keyChainConnection.getService();
    735                 if (mCertHolder.mDeleted) {
    736                     byte[] bytes = mCertHolder.mX509Cert.getEncoded();
    737                     service.installCaCertificate(bytes);
    738                     return true;
    739                 } else {
    740                     return service.deleteCaCertificate(mCertHolder.mAlias);
    741                 }
    742             } catch (CertificateEncodingException e) {
    743                 Log.w(TAG, "Error while toggling alias " + mCertHolder.mAlias,
    744                         e);
    745                 return false;
    746             } catch (IllegalStateException e) {
    747                 // used by installCaCertificate to report errors
    748                 Log.w(TAG, "Error while toggling alias " + mCertHolder.mAlias, e);
    749                 return false;
    750             } catch (RemoteException e) {
    751                 Log.w(TAG, "Error while toggling alias " + mCertHolder.mAlias, e);
    752                 return false;
    753             }
    754         }
    755 
    756         @Override
    757         protected void onPostExecute(Boolean ok) {
    758             mCertHolder.mTab.postOperationUpdate(ok, mCertHolder);
    759         }
    760     }
    761 }
    762