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