Merge changes from topic 'TrustCert' into nyc-dev

* changes:
  Show trust option for multiple unapproved cert in chain
  CertDialog supports multiple certs
This commit is contained in:
Victor Chang
2016-04-13 10:12:13 +00:00
committed by Android (Google) Code Review
3 changed files with 433 additions and 126 deletions

View File

@@ -26,6 +26,7 @@ import android.content.DialogInterface.OnClickListener;
import android.content.Intent; import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.os.RemoteException; import android.os.RemoteException;
import android.os.UserHandle;
import android.view.WindowManager; import android.view.WindowManager;
import android.view.WindowManagerGlobal; import android.view.WindowManagerGlobal;
@@ -88,6 +89,8 @@ public class MonitoringCertInfoActivity extends Activity implements OnClickListe
Intent intent = Intent intent =
new Intent(android.provider.Settings.ACTION_TRUSTED_CREDENTIALS_USER); new Intent(android.provider.Settings.ACTION_TRUSTED_CREDENTIALS_USER);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.putExtra(TrustedCredentialsSettings.ARG_SHOW_NEW_FOR_USER,
UserHandle.myUserId());
startActivity(intent); startActivity(intent);
finish(); finish();
} }

View File

@@ -0,0 +1,342 @@
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings;
import android.annotation.NonNull;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.admin.DevicePolicyManager;
import android.content.DialogInterface;
import android.net.http.SslCertificate;
import android.os.UserHandle;
import android.os.UserManager;
import android.view.View;
import android.view.animation.AnimationUtils;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.Spinner;
import com.android.settings.TrustedCredentialsSettings.CertHolder;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;
class TrustedCredentialsDialogBuilder extends AlertDialog.Builder {
public interface DelegateInterface {
List<X509Certificate> getX509CertsFromCertHolder(CertHolder certHolder);
void removeOrInstallCert(CertHolder certHolder);
}
private final DialogEventHandler mDialogEventHandler;
public TrustedCredentialsDialogBuilder(Activity activity, DelegateInterface delegate) {
super(activity);
mDialogEventHandler = new DialogEventHandler(activity, delegate);
initDefaultBuilderParams();
}
public TrustedCredentialsDialogBuilder setCertHolder(CertHolder certHolder) {
return setCertHolders(certHolder == null ? new CertHolder[0]
: new CertHolder[]{certHolder});
}
public TrustedCredentialsDialogBuilder setCertHolders(@NonNull CertHolder[] certHolders) {
mDialogEventHandler.setCertHolders(certHolders);
return this;
}
@Override
public AlertDialog create() {
AlertDialog dialog = super.create();
dialog.setOnShowListener(mDialogEventHandler);
mDialogEventHandler.setDialog(dialog);
return dialog;
}
private void initDefaultBuilderParams() {
setTitle(com.android.internal.R.string.ssl_certificate);
setView(mDialogEventHandler.mRootContainer);
// Enable buttons here. The actual labels and listeners are configured in nextOrDismiss
setPositiveButton(R.string.trusted_credentials_trust_label, null);
setNegativeButton(android.R.string.ok, null);
}
private static class DialogEventHandler implements DialogInterface.OnShowListener,
View.OnClickListener {
private static final long OUT_DURATION_MS = 300;
private static final long IN_DURATION_MS = 200;
private final Activity mActivity;
private final DevicePolicyManager mDpm;
private final UserManager mUserManager;
private final DelegateInterface mDelegate;
private final LinearLayout mRootContainer;
private int mCurrentCertIndex = -1;
private AlertDialog mDialog;
private Button mPositiveButton;
private Button mNegativeButton;
private boolean mNeedsApproval;
private CertHolder[] mCertHolders = new CertHolder[0];
private View mCurrentCertLayout = null;
public DialogEventHandler(Activity activity, DelegateInterface delegate) {
mActivity = activity;
mDpm = activity.getSystemService(DevicePolicyManager.class);
mUserManager = activity.getSystemService(UserManager.class);
mDelegate = delegate;
mRootContainer = new LinearLayout(mActivity);
mRootContainer.setOrientation(LinearLayout.VERTICAL);
}
public void setDialog(AlertDialog dialog) {
mDialog = dialog;
}
public void setCertHolders(CertHolder[] certHolder) {
mCertHolders = certHolder;
}
@Override
public void onShow(DialogInterface dialogInterface) {
// Config the display content only when the dialog is shown because the
// positive/negative buttons don't exist until the dialog is shown
nextOrDismiss();
}
@Override
public void onClick(View view) {
if (view == mPositiveButton) {
if (mNeedsApproval) {
onClickTrust();
} else {
onClickOk();
}
} else if (view == mNegativeButton) {
onClickRemove();
}
}
private void onClickOk() {
nextOrDismiss();
}
private void onClickTrust() {
CertHolder certHolder = getCurrentCertInfo();
mDpm.approveCaCert(certHolder.getAlias(), certHolder.getUserId(), true);
nextOrDismiss();
}
private void onClickRemove() {
final CertHolder certHolder = getCurrentCertInfo();
new AlertDialog.Builder(mActivity)
.setMessage(getButtonConfirmation(certHolder))
.setPositiveButton(android.R.string.yes,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
mDelegate.removeOrInstallCert(certHolder);
dialog.dismiss();
nextOrDismiss();
}
})
.setNegativeButton(android.R.string.no, null)
.show();
}
private CertHolder getCurrentCertInfo() {
return mCurrentCertIndex < mCertHolders.length ? mCertHolders[mCurrentCertIndex] : null;
}
private void nextOrDismiss() {
mCurrentCertIndex++;
// find next non-null cert or dismiss
while (mCurrentCertIndex < mCertHolders.length && getCurrentCertInfo() == null) {
mCurrentCertIndex++;
}
if (mCurrentCertIndex >= mCertHolders.length) {
mDialog.dismiss();
return;
}
updateViewContainer();
updatePositiveButton();
updateNegativeButton();
}
private void updatePositiveButton() {
final CertHolder certHolder = getCurrentCertInfo();
mNeedsApproval = !certHolder.isSystemCert() &&
!mDpm.isCaCertApproved(certHolder.getAlias(), certHolder.getUserId());
// The ok button is optional. User can still dismiss the dialog by other means.
// Display it only when trust button is not displayed, because we want users to
// either remove or trust a CA cert when the cert is installed by DPC app.
CharSequence displayText = mActivity.getText(mNeedsApproval
? R.string.trusted_credentials_trust_label
: android.R.string.ok);
mPositiveButton = updateButton(DialogInterface.BUTTON_POSITIVE, displayText);
}
private void updateNegativeButton() {
final CertHolder certHolder = getCurrentCertInfo();
final boolean showRemoveButton = !mUserManager.hasUserRestriction(
UserManager.DISALLOW_CONFIG_CREDENTIALS,
new UserHandle(certHolder.getUserId()));
CharSequence displayText = mActivity.getText(getButtonLabel(certHolder));
mNegativeButton = updateButton(DialogInterface.BUTTON_NEGATIVE, displayText);
mNegativeButton.setVisibility(showRemoveButton ? View.VISIBLE : View.GONE);
}
/**
* mDialog.setButton doesn't trigger text refresh since mDialog has been shown.
* It's invoked only in case mDialog is refreshed.
* setOnClickListener is invoked to avoid dismiss dialog onClick
*/
private Button updateButton(int buttonType, CharSequence displayText) {
mDialog.setButton(buttonType, displayText, (DialogInterface.OnClickListener) null);
Button button = mDialog.getButton(buttonType);
button.setText(displayText);
button.setOnClickListener(this);
return button;
}
private void updateViewContainer() {
CertHolder certHolder = getCurrentCertInfo();
LinearLayout nextCertLayout = getCertLayout(certHolder);
// Displaying first cert doesn't require animation
if (mCurrentCertLayout == null) {
mCurrentCertLayout = nextCertLayout;
mRootContainer.addView(mCurrentCertLayout);
} else {
animateViewTransition(nextCertLayout);
}
}
private LinearLayout getCertLayout(final CertHolder certHolder) {
final ArrayList<View> views = new ArrayList<View>();
final ArrayList<String> titles = new ArrayList<String>();
List<X509Certificate> certificates = mDelegate.getX509CertsFromCertHolder(certHolder);
if (certificates != null) {
for (X509Certificate certificate : certificates) {
SslCertificate sslCert = new SslCertificate(certificate);
views.add(sslCert.inflateCertificateView(mActivity));
titles.add(sslCert.getIssuedTo().getCName());
}
}
ArrayAdapter<String> arrayAdapter = new ArrayAdapter<String>(mActivity,
android.R.layout.simple_spinner_item,
titles);
arrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
Spinner spinner = new Spinner(mActivity);
spinner.setAdapter(arrayAdapter);
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position,
long id) {
for (int i = 0; i < views.size(); i++) {
views.get(i).setVisibility(i == position ? View.VISIBLE : View.GONE);
}
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
LinearLayout certLayout = new LinearLayout(mActivity);
certLayout.setOrientation(LinearLayout.VERTICAL);
certLayout.addView(spinner);
for (int i = 0; i < views.size(); ++i) {
View certificateView = views.get(i);
// Show first cert by default
certificateView.setVisibility(i == 0 ? View.VISIBLE : View.GONE);
certLayout.addView(certificateView);
}
return certLayout;
}
private static int getButtonConfirmation(CertHolder certHolder) {
return certHolder.isSystemCert() ? ( certHolder.isDeleted()
? R.string.trusted_credentials_enable_confirmation
: R.string.trusted_credentials_disable_confirmation )
: R.string.trusted_credentials_remove_confirmation;
}
private static int getButtonLabel(CertHolder certHolder) {
return certHolder.isSystemCert() ? ( certHolder.isDeleted()
? R.string.trusted_credentials_enable_label
: R.string.trusted_credentials_disable_label )
: R.string.trusted_credentials_remove_label;
}
/* Animation code */
private void animateViewTransition(final View nextCertView) {
animateOldContent(new Runnable() {
@Override
public void run() {
addAndAnimateNewContent(nextCertView);
}
});
}
private void animateOldContent(Runnable callback) {
// Fade out
mCurrentCertLayout.animate()
.alpha(0)
.setDuration(OUT_DURATION_MS)
.setInterpolator(AnimationUtils.loadInterpolator(mActivity,
android.R.interpolator.fast_out_linear_in))
.withEndAction(callback)
.start();
}
private void addAndAnimateNewContent(View nextCertLayout) {
mCurrentCertLayout = nextCertLayout;
mRootContainer.removeAllViews();
mRootContainer.addView(nextCertLayout);
mRootContainer.addOnLayoutChangeListener( new View.OnLayoutChangeListener() {
@Override
public void onLayoutChange(View v, int left, int top, int right, int bottom,
int oldLeft, int oldTop, int oldRight, int oldBottom) {
mRootContainer.removeOnLayoutChangeListener(this);
// Animate slide in from the right
final int containerWidth = mRootContainer.getWidth();
mCurrentCertLayout.setTranslationX(containerWidth);
mCurrentCertLayout.animate()
.translationX(0)
.setInterpolator(AnimationUtils.loadInterpolator(mActivity,
android.R.interpolator.linear_out_slow_in))
.setDuration(IN_DURATION_MS)
.start();
}
});
}
}
}

View File

@@ -16,8 +16,7 @@
package com.android.settings; package com.android.settings;
import android.app.AlertDialog; import android.annotation.UiThread;
import android.app.Dialog;
import android.app.KeyguardManager; import android.app.KeyguardManager;
import android.app.admin.DevicePolicyManager; import android.app.admin.DevicePolicyManager;
import android.content.BroadcastReceiver; import android.content.BroadcastReceiver;
@@ -41,16 +40,11 @@ import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.AdapterView; import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ArrayAdapter;
import android.widget.BaseAdapter; import android.widget.BaseAdapter;
import android.widget.BaseExpandableListAdapter; import android.widget.BaseExpandableListAdapter;
import android.widget.Button;
import android.widget.ExpandableListView; import android.widget.ExpandableListView;
import android.widget.LinearLayout;
import android.widget.ListView; import android.widget.ListView;
import android.widget.ProgressBar; import android.widget.ProgressBar;
import android.widget.Spinner;
import android.widget.Switch; import android.widget.Switch;
import android.widget.TabHost; import android.widget.TabHost;
import android.widget.TextView; import android.widget.TextView;
@@ -67,12 +61,17 @@ import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
public class TrustedCredentialsSettings extends OptionsMenuFragment { public class TrustedCredentialsSettings extends OptionsMenuFragment
implements TrustedCredentialsDialogBuilder.DelegateInterface {
public static final String ARG_SHOW_NEW_FOR_USER = "ARG_SHOW_NEW_FOR_USER";
private static final String TAG = "TrustedCredentialsSettings"; private static final String TAG = "TrustedCredentialsSettings";
private UserManager mUserManager; private UserManager mUserManager;
private KeyguardManager mKeyguardManager; private KeyguardManager mKeyguardManager;
private int mTrustAllCaUserId;
private static final String USER_ACTION = "com.android.settings.TRUSTED_CREDENTIALS_USER"; private static final String USER_ACTION = "com.android.settings.TRUSTED_CREDENTIALS_USER";
@@ -135,30 +134,6 @@ public class TrustedCredentialsSettings extends OptionsMenuFragment {
} }
throw new AssertionError(); throw new AssertionError();
} }
private int getButtonLabel(CertHolder certHolder) {
switch (this) {
case SYSTEM:
if (certHolder.mDeleted) {
return R.string.trusted_credentials_enable_label;
}
return R.string.trusted_credentials_disable_label;
case USER:
return R.string.trusted_credentials_remove_label;
}
throw new AssertionError();
}
private int getButtonConfirmation(CertHolder certHolder) {
switch (this) {
case SYSTEM:
if (certHolder.mDeleted) {
return R.string.trusted_credentials_enable_confirmation;
}
return R.string.trusted_credentials_disable_confirmation;
case USER:
return R.string.trusted_credentials_remove_confirmation;
}
throw new AssertionError();
}
private void postOperationUpdate(boolean ok, CertHolder certHolder) { private void postOperationUpdate(boolean ok, CertHolder certHolder) {
if (ok) { if (ok) {
if (certHolder.mTab.mSwitch) { if (certHolder.mTab.mSwitch) {
@@ -213,6 +188,9 @@ public class TrustedCredentialsSettings extends OptionsMenuFragment {
mUserManager = (UserManager) getActivity().getSystemService(Context.USER_SERVICE); mUserManager = (UserManager) getActivity().getSystemService(Context.USER_SERVICE);
mKeyguardManager = (KeyguardManager) getActivity() mKeyguardManager = (KeyguardManager) getActivity()
.getSystemService(Context.KEYGUARD_SERVICE); .getSystemService(Context.KEYGUARD_SERVICE);
mTrustAllCaUserId = getActivity().getIntent().getIntExtra(ARG_SHOW_NEW_FOR_USER,
UserHandle.USER_NULL);
IntentFilter filter = new IntentFilter(); IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE); filter.addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE);
filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE); filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
@@ -590,6 +568,37 @@ public class TrustedCredentialsSettings extends OptionsMenuFragment {
mList.setVisibility(View.VISIBLE); mList.setVisibility(View.VISIBLE);
mProgressBar.setProgress(0); mProgressBar.setProgress(0);
mAliasLoaders.remove(mTab); mAliasLoaders.remove(mTab);
showTrustAllCaDialogIfNeeded();
}
private boolean isUserTabAndTrustAllCertMode() {
return isTrustAllCaCertModeInProgress() && mTab == Tab.USER;
}
@UiThread
private void showTrustAllCaDialogIfNeeded() {
if (!isUserTabAndTrustAllCertMode()) {
return;
}
List<CertHolder> certHolders = mCertHoldersByUserId.get(mTrustAllCaUserId);
if (certHolders == null) {
return;
}
List<CertHolder> unapprovedUserCertHolders = new ArrayList<>();
final DevicePolicyManager dpm = mContext.getSystemService(
DevicePolicyManager.class);
for (CertHolder cert : certHolders) {
if (cert != null && !dpm.isCaCertApproved(cert.mAlias, mTrustAllCaUserId)) {
unapprovedUserCertHolders.add(cert);
}
}
if (unapprovedUserCertHolders.size() == 0) {
Log.w(TAG, "no cert is pending approval for user " + mTrustAllCaUserId);
return;
}
showTrustAllCaDialog(unapprovedUserCertHolders);
} }
} }
@@ -603,7 +612,7 @@ public class TrustedCredentialsSettings extends OptionsMenuFragment {
} }
} }
private static class CertHolder implements Comparable<CertHolder> { /* package */ static class CertHolder implements Comparable<CertHolder> {
public int mProfileId; public int mProfileId;
private final IKeyChainService mService; private final IKeyChainService mService;
private final TrustedCertificateAdapterCommons mAdapter; private final TrustedCertificateAdapterCommons mAdapter;
@@ -679,6 +688,22 @@ public class TrustedCredentialsSettings extends OptionsMenuFragment {
@Override public int hashCode() { @Override public int hashCode() {
return mAlias.hashCode(); return mAlias.hashCode();
} }
public int getUserId() {
return mProfileId;
}
public String getAlias() {
return mAlias;
}
public boolean isSystemCert() {
return mTab == Tab.SYSTEM;
}
public boolean isDeleted() {
return mDeleted;
}
} }
private View getViewForCertificate(CertHolder certHolder, Tab mTab, View convertView, private View getViewForCertificate(CertHolder certHolder, Tab mTab, View convertView,
@@ -716,91 +741,34 @@ public class TrustedCredentialsSettings extends OptionsMenuFragment {
private Switch mSwitch; private Switch mSwitch;
} }
private void showCertDialog(final CertHolder certHolder) { private boolean isTrustAllCaCertModeInProgress() {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); return mTrustAllCaUserId != UserHandle.USER_NULL;
builder.setTitle(com.android.internal.R.string.ssl_certificate);
final DevicePolicyManager dpm = getActivity().getSystemService(DevicePolicyManager.class);
final ArrayList<View> views = new ArrayList<View>();
final ArrayList<String> titles = new ArrayList<String>();
addCertChain(certHolder, views, titles);
ArrayAdapter<String> arrayAdapter = new ArrayAdapter<String>(getActivity(),
android.R.layout.simple_spinner_item,
titles);
arrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
Spinner spinner = new Spinner(getActivity());
spinner.setAdapter(arrayAdapter);
spinner.setOnItemSelectedListener(new OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
for (int i = 0; i < views.size(); i++) {
views.get(i).setVisibility(i == position ? View.VISIBLE : View.GONE);
}
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
LinearLayout container = new LinearLayout(getActivity());
container.setOrientation(LinearLayout.VERTICAL);
container.addView(spinner);
for (int i = 0; i < views.size(); ++i) {
View certificateView = views.get(i);
if (i != 0) {
certificateView.setVisibility(View.GONE);
}
container.addView(certificateView);
}
builder.setView(container);
if (certHolder.mTab == Tab.USER &&
!dpm.isCaCertApproved(certHolder.mAlias, certHolder.mProfileId)) {
builder.setPositiveButton(R.string.trusted_credentials_trust_label,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
dpm.approveCaCert(certHolder.mAlias, certHolder.mProfileId, true);
}
});
} else {
// The ok button is optional. Display it only when trust button is not displayed.
// User can still dismiss the dialog by other means.
builder.setPositiveButton(android.R.string.ok, null);
}
if (!mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_CREDENTIALS,
new UserHandle(certHolder.mProfileId))) {
builder.setNegativeButton(certHolder.mTab.getButtonLabel(certHolder),
new DialogInterface.OnClickListener() {
@Override
public void onClick(final DialogInterface parentDialog, int i) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setMessage(certHolder.mTab.getButtonConfirmation(certHolder));
builder.setPositiveButton(android.R.string.yes,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
new AliasOperation(certHolder).execute();
dialog.dismiss();
parentDialog.dismiss();
}
});
builder.setNegativeButton(android.R.string.no, null);
AlertDialog alert = builder.create();
alert.show();
}
});
}
builder.show();
} }
private void addCertChain(final CertHolder certHolder, private void showTrustAllCaDialog(List<CertHolder> unapprovedCertHolders) {
final ArrayList<View> views, final ArrayList<String> titles) { final CertHolder[] arr = unapprovedCertHolders.toArray(
new CertHolder[unapprovedCertHolders.size()]);
new TrustedCredentialsDialogBuilder(getActivity(), this)
.setCertHolders(arr)
.setOnDismissListener(new DialogInterface.OnDismissListener() {
@Override
public void onDismiss(DialogInterface dialogInterface) {
// Avoid starting dialog again after Activity restart.
getActivity().getIntent().removeExtra(ARG_SHOW_NEW_FOR_USER);
mTrustAllCaUserId = UserHandle.USER_NULL;
}
})
.show();
}
private void showCertDialog(final CertHolder certHolder) {
new TrustedCredentialsDialogBuilder(getActivity(), this)
.setCertHolder(certHolder)
.show();
}
@Override
public List<X509Certificate> getX509CertsFromCertHolder(CertHolder certHolder) {
List<X509Certificate> certificates = null; List<X509Certificate> certificates = null;
try { try {
KeyChainConnection keyChainConnection = mKeyChainConnectionByProfileId.get( KeyChainConnection keyChainConnection = mKeyChainConnectionByProfileId.get(
@@ -817,18 +785,13 @@ public class TrustedCredentialsSettings extends OptionsMenuFragment {
} catch (RemoteException ex) { } catch (RemoteException ex) {
Log.e(TAG, "RemoteException while retrieving certificate chain for root " Log.e(TAG, "RemoteException while retrieving certificate chain for root "
+ certHolder.mAlias, ex); + certHolder.mAlias, ex);
return;
}
for (X509Certificate certificate : certificates) {
addCertDetails(certificate, views, titles);
} }
return certificates;
} }
private void addCertDetails(X509Certificate certificate, final ArrayList<View> views, @Override
final ArrayList<String> titles) { public void removeOrInstallCert(CertHolder certHolder) {
SslCertificate sslCert = new SslCertificate(certificate); new AliasOperation(certHolder).execute();
views.add(sslCert.inflateCertificateView(getActivity()));
titles.add(sslCert.getIssuedTo().getCName());
} }
private class AliasOperation extends AsyncTask<Void, Void, Boolean> { private class AliasOperation extends AsyncTask<Void, Void, Boolean> {
@@ -854,8 +817,7 @@ public class TrustedCredentialsSettings extends OptionsMenuFragment {
} }
} catch (CertificateEncodingException | SecurityException | IllegalStateException } catch (CertificateEncodingException | SecurityException | IllegalStateException
| RemoteException e) { | RemoteException e) {
Log.w(TAG, "Error while toggling alias " + mCertHolder.mAlias, Log.w(TAG, "Error while toggling alias " + mCertHolder.mAlias, e);
e);
return false; return false;
} }
} }