Update Trusted Credentials screen in settings
Trusted credentials for both the primary user and its managed profiles are shown on the Trusted Credentials fragment. All functionalities (e.g. disabling/enabling of certificates) remain available. Bug: 16029580 Change-Id: Id6335d12ec5fbeed0e254f3ded1e715def3e8e04
This commit is contained in:
@@ -59,6 +59,16 @@
|
|||||||
android:visibility="gone">
|
android:visibility="gone">
|
||||||
</ListView>
|
</ListView>
|
||||||
|
|
||||||
|
<ExpandableListView
|
||||||
|
android:id="@+id/system_expandable_list"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="fill_parent"
|
||||||
|
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
|
||||||
|
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
|
||||||
|
android:scrollbarStyle="outsideOverlay"
|
||||||
|
android:visibility="gone">
|
||||||
|
</ExpandableListView>
|
||||||
|
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
|
|
||||||
<FrameLayout
|
<FrameLayout
|
||||||
@@ -85,6 +95,16 @@
|
|||||||
android:visibility="gone">
|
android:visibility="gone">
|
||||||
</ListView>
|
</ListView>
|
||||||
|
|
||||||
|
<ExpandableListView
|
||||||
|
android:id="@+id/user_expandable_list"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="fill_parent"
|
||||||
|
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
|
||||||
|
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
|
||||||
|
android:scrollbarStyle="outsideOverlay"
|
||||||
|
android:visibility="gone">
|
||||||
|
</ExpandableListView>
|
||||||
|
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
|
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
|
@@ -16,21 +16,24 @@
|
|||||||
|
|
||||||
package com.android.settings;
|
package com.android.settings;
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.app.AlertDialog;
|
import android.app.AlertDialog;
|
||||||
import android.app.Dialog;
|
import android.app.Dialog;
|
||||||
import android.app.Fragment;
|
import android.app.Fragment;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
import android.content.Intent;
|
import android.content.pm.UserInfo;
|
||||||
|
import android.content.res.TypedArray;
|
||||||
import android.net.http.SslCertificate;
|
import android.net.http.SslCertificate;
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
|
import android.os.UserHandle;
|
||||||
import android.os.UserManager;
|
import android.os.UserManager;
|
||||||
import android.security.IKeyChainService;
|
import android.security.IKeyChainService;
|
||||||
import android.security.KeyChain;
|
import android.security.KeyChain;
|
||||||
import android.security.KeyChain.KeyChainConnection;
|
import android.security.KeyChain.KeyChainConnection;
|
||||||
|
import android.util.SparseArray;
|
||||||
|
import android.util.Log;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
@@ -38,9 +41,10 @@ import android.widget.AdapterView;
|
|||||||
import android.widget.AdapterView.OnItemSelectedListener;
|
import android.widget.AdapterView.OnItemSelectedListener;
|
||||||
import android.widget.ArrayAdapter;
|
import android.widget.ArrayAdapter;
|
||||||
import android.widget.BaseAdapter;
|
import android.widget.BaseAdapter;
|
||||||
|
import android.widget.BaseExpandableListAdapter;
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
import android.widget.CheckBox;
|
import android.widget.CheckBox;
|
||||||
import android.widget.FrameLayout;
|
import android.widget.ExpandableListView;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
import android.widget.ListView;
|
import android.widget.ListView;
|
||||||
import android.widget.ProgressBar;
|
import android.widget.ProgressBar;
|
||||||
@@ -48,15 +52,13 @@ import android.widget.Spinner;
|
|||||||
import android.widget.TabHost;
|
import android.widget.TabHost;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import com.android.internal.util.ParcelableString;
|
||||||
|
|
||||||
import java.security.cert.CertificateEncodingException;
|
import java.security.cert.CertificateEncodingException;
|
||||||
import java.security.cert.CertificateException;
|
|
||||||
import java.security.cert.X509Certificate;
|
import java.security.cert.X509Certificate;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import com.android.org.conscrypt.TrustedCertificateStore;
|
|
||||||
|
|
||||||
public class TrustedCredentialsSettings extends Fragment {
|
public class TrustedCredentialsSettings extends Fragment {
|
||||||
|
|
||||||
@@ -72,12 +74,14 @@ public class TrustedCredentialsSettings extends Fragment {
|
|||||||
R.id.system_tab,
|
R.id.system_tab,
|
||||||
R.id.system_progress,
|
R.id.system_progress,
|
||||||
R.id.system_list,
|
R.id.system_list,
|
||||||
|
R.id.system_expandable_list,
|
||||||
true),
|
true),
|
||||||
USER("user",
|
USER("user",
|
||||||
R.string.trusted_credentials_user_tab,
|
R.string.trusted_credentials_user_tab,
|
||||||
R.id.user_tab,
|
R.id.user_tab,
|
||||||
R.id.user_progress,
|
R.id.user_progress,
|
||||||
R.id.user_list,
|
R.id.user_list,
|
||||||
|
R.id.user_expandable_list,
|
||||||
false);
|
false);
|
||||||
|
|
||||||
private final String mTag;
|
private final String mTag;
|
||||||
@@ -85,28 +89,34 @@ public class TrustedCredentialsSettings extends Fragment {
|
|||||||
private final int mView;
|
private final int mView;
|
||||||
private final int mProgress;
|
private final int mProgress;
|
||||||
private final int mList;
|
private final int mList;
|
||||||
|
private final int mExpandableList;
|
||||||
private final boolean mCheckbox;
|
private final boolean mCheckbox;
|
||||||
private Tab(String tag, int label, int view, int progress, int list, boolean checkbox) {
|
|
||||||
|
private Tab(String tag, int label, int view, int progress, int list, int expandableList,
|
||||||
|
boolean checkbox) {
|
||||||
mTag = tag;
|
mTag = tag;
|
||||||
mLabel = label;
|
mLabel = label;
|
||||||
mView = view;
|
mView = view;
|
||||||
mProgress = progress;
|
mProgress = progress;
|
||||||
mList = list;
|
mList = list;
|
||||||
|
mExpandableList = expandableList;
|
||||||
mCheckbox = checkbox;
|
mCheckbox = checkbox;
|
||||||
}
|
}
|
||||||
private Set<String> getAliases(TrustedCertificateStore store) {
|
|
||||||
|
private List<ParcelableString> getAliases(IKeyChainService service) throws RemoteException {
|
||||||
switch (this) {
|
switch (this) {
|
||||||
case SYSTEM:
|
case SYSTEM: {
|
||||||
return store.allSystemAliases();
|
return service.getSystemCaAliases().getList();
|
||||||
|
}
|
||||||
case USER:
|
case USER:
|
||||||
return store.userAliases();
|
return service.getUserCaAliases().getList();
|
||||||
}
|
}
|
||||||
throw new AssertionError();
|
throw new AssertionError();
|
||||||
}
|
}
|
||||||
private boolean deleted(TrustedCertificateStore store, String alias) {
|
private boolean deleted(IKeyChainService service, String alias) throws RemoteException {
|
||||||
switch (this) {
|
switch (this) {
|
||||||
case SYSTEM:
|
case SYSTEM:
|
||||||
return !store.containsAlias(alias);
|
return !service.containsCaAlias(alias);
|
||||||
case USER:
|
case USER:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -141,7 +151,7 @@ public class TrustedCredentialsSettings extends Fragment {
|
|||||||
if (certHolder.mTab.mCheckbox) {
|
if (certHolder.mTab.mCheckbox) {
|
||||||
certHolder.mDeleted = !certHolder.mDeleted;
|
certHolder.mDeleted = !certHolder.mDeleted;
|
||||||
} else {
|
} else {
|
||||||
certHolder.mAdapter.mCertHolders.remove(certHolder);
|
certHolder.mAdapter.remove(certHolder);
|
||||||
}
|
}
|
||||||
certHolder.mAdapter.notifyDataSetChanged();
|
certHolder.mAdapter.notifyDataSetChanged();
|
||||||
} else {
|
} else {
|
||||||
@@ -151,10 +161,9 @@ public class TrustedCredentialsSettings extends Fragment {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// be careful not to use this on the UI thread since it is does file operations
|
|
||||||
private final TrustedCertificateStore mStore = new TrustedCertificateStore();
|
|
||||||
|
|
||||||
private TabHost mTabHost;
|
private TabHost mTabHost;
|
||||||
|
private final SparseArray<KeyChainConnection>
|
||||||
|
mKeyChainConnectionByProfileId = new SparseArray<KeyChainConnection>();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
@@ -176,6 +185,19 @@ public class TrustedCredentialsSettings extends Fragment {
|
|||||||
}
|
}
|
||||||
return mTabHost;
|
return mTabHost;
|
||||||
}
|
}
|
||||||
|
@Override
|
||||||
|
public void onDestroy() {
|
||||||
|
closeKeyChainConnections();
|
||||||
|
super.onDestroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void closeKeyChainConnections() {
|
||||||
|
final int n = mKeyChainConnectionByProfileId.size();
|
||||||
|
for (int i = 0; i < n; ++i) {
|
||||||
|
mKeyChainConnectionByProfileId.valueAt(i).close();
|
||||||
|
}
|
||||||
|
mKeyChainConnectionByProfileId.clear();
|
||||||
|
}
|
||||||
|
|
||||||
private void addTab(Tab tab) {
|
private void addTab(Tab tab) {
|
||||||
TabHost.TabSpec systemSpec = mTabHost.newTabSpec(tab.mTag)
|
TabHost.TabSpec systemSpec = mTabHost.newTabSpec(tab.mTag)
|
||||||
@@ -183,86 +205,254 @@ public class TrustedCredentialsSettings extends Fragment {
|
|||||||
.setContent(tab.mView);
|
.setContent(tab.mView);
|
||||||
mTabHost.addTab(systemSpec);
|
mTabHost.addTab(systemSpec);
|
||||||
|
|
||||||
ListView lv = (ListView) mTabHost.findViewById(tab.mList);
|
if (mUserManager.getUserProfiles().size() > 1) {
|
||||||
final TrustedCertificateAdapter adapter = new TrustedCertificateAdapter(tab);
|
ExpandableListView lv = (ExpandableListView) mTabHost.findViewById(tab.mExpandableList);
|
||||||
lv.setAdapter(adapter);
|
final TrustedCertificateExpandableAdapter adapter =
|
||||||
lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
|
new TrustedCertificateExpandableAdapter(tab);
|
||||||
@Override public void onItemClick(AdapterView<?> parent, View view, int pos, long id) {
|
lv.setAdapter(adapter);
|
||||||
showCertDialog(adapter.getItem(pos));
|
lv.setOnChildClickListener(new ExpandableListView.OnChildClickListener() {
|
||||||
}
|
@Override
|
||||||
});
|
public boolean onChildClick(ExpandableListView parent, View v,
|
||||||
|
int groupPosition, int childPosition, long id) {
|
||||||
|
showCertDialog(adapter.getChild(groupPosition, childPosition));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
ListView lv = (ListView) mTabHost.findViewById(tab.mList);
|
||||||
|
final TrustedCertificateAdapter adapter = new TrustedCertificateAdapter(tab);
|
||||||
|
lv.setAdapter(adapter);
|
||||||
|
lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
|
||||||
|
@Override public void onItemClick(AdapterView<?> parent, View view,
|
||||||
|
int pos, long id) {
|
||||||
|
showCertDialog(adapter.getItem(pos));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class TrustedCertificateAdapter extends BaseAdapter {
|
/**
|
||||||
private final List<CertHolder> mCertHolders = new ArrayList<CertHolder>();
|
* Common interface for adapters of both expandable and non-expandable certificate lists.
|
||||||
private final Tab mTab;
|
*/
|
||||||
private TrustedCertificateAdapter(Tab tab) {
|
private interface TrustedCertificateAdapterCommons {
|
||||||
mTab = tab;
|
/**
|
||||||
|
* Remove a certificate from the list.
|
||||||
|
* @param certHolder the certificate to be removed.
|
||||||
|
*/
|
||||||
|
void remove(CertHolder certHolder);
|
||||||
|
/**
|
||||||
|
* Notify the adapter that the underlying data set has changed.
|
||||||
|
*/
|
||||||
|
void notifyDataSetChanged();
|
||||||
|
/**
|
||||||
|
* Load the certificates.
|
||||||
|
*/
|
||||||
|
void load();
|
||||||
|
/**
|
||||||
|
* Gets the identifier of the list view the adapter is connected to.
|
||||||
|
* @param tab the tab on which the list view resides.
|
||||||
|
* @return identifier of the list view.
|
||||||
|
*/
|
||||||
|
int getListViewId(Tab tab);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adapter for expandable list view of certificates. Groups in the view correspond to profiles
|
||||||
|
* whereas children correspond to certificates.
|
||||||
|
*/
|
||||||
|
private class TrustedCertificateExpandableAdapter extends BaseExpandableListAdapter implements
|
||||||
|
TrustedCertificateAdapterCommons {
|
||||||
|
private AdapterData mData;
|
||||||
|
|
||||||
|
private TrustedCertificateExpandableAdapter(Tab tab) {
|
||||||
|
mData = new AdapterData(tab, this);
|
||||||
load();
|
load();
|
||||||
}
|
}
|
||||||
private void load() {
|
@Override
|
||||||
new AliasLoader().execute();
|
public void remove(CertHolder certHolder) {
|
||||||
|
mData.remove(certHolder);
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public int getGroupCount() {
|
||||||
|
return mData.mCertHoldersByUserId.size();
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public int getChildrenCount(int groupPosition) {
|
||||||
|
return mData.mCertHoldersByUserId.valueAt(groupPosition).size();
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public UserHandle getGroup(int groupPosition) {
|
||||||
|
return new UserHandle(mData.mCertHoldersByUserId.keyAt(groupPosition));
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public CertHolder getChild(int groupPosition, int childPosition) {
|
||||||
|
return mData.mCertHoldersByUserId.valueAt(groupPosition).get(childPosition);
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public long getGroupId(int groupPosition) {
|
||||||
|
return mData.mCertHoldersByUserId.keyAt(groupPosition);
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public long getChildId(int groupPosition, int childPosition) {
|
||||||
|
return childPosition;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public boolean hasStableIds() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public View getGroupView(int groupPosition, boolean isExpanded, View convertView,
|
||||||
|
ViewGroup parent) {
|
||||||
|
if (convertView == null) {
|
||||||
|
LayoutInflater inflater = (LayoutInflater) getActivity()
|
||||||
|
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||||
|
convertView = inflateCategoryHeader(inflater, parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
final TextView title = (TextView) convertView.findViewById(android.R.id.title);
|
||||||
|
final UserHandle profile = getGroup(groupPosition);
|
||||||
|
final UserInfo userInfo = mUserManager.getUserInfo(profile.getIdentifier());
|
||||||
|
title.setText(userInfo.name);
|
||||||
|
title.setTextAlignment(View.TEXT_ALIGNMENT_VIEW_END);
|
||||||
|
|
||||||
|
return convertView;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public View getChildView(int groupPosition, int childPosition, boolean isLastChild,
|
||||||
|
View convertView, ViewGroup parent) {
|
||||||
|
return getViewForCertificate(getChild(groupPosition, childPosition), mData.mTab,
|
||||||
|
convertView, parent);
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public boolean isChildSelectable(int groupPosition, int childPosition) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void load() {
|
||||||
|
mData.new AliasLoader().execute();
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public int getListViewId(Tab tab) {
|
||||||
|
return tab.mExpandableList;
|
||||||
|
}
|
||||||
|
private View inflateCategoryHeader(LayoutInflater inflater, ViewGroup parent) {
|
||||||
|
final TypedArray a = inflater.getContext().obtainStyledAttributes(null,
|
||||||
|
com.android.internal.R.styleable.Preference,
|
||||||
|
com.android.internal.R.attr.preferenceCategoryStyle, 0);
|
||||||
|
final int resId = a.getResourceId(com.android.internal.R.styleable.Preference_layout,
|
||||||
|
0);
|
||||||
|
return inflater.inflate(resId, parent, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private class TrustedCertificateAdapter extends BaseAdapter implements
|
||||||
|
TrustedCertificateAdapterCommons {
|
||||||
|
private final AdapterData mData;
|
||||||
|
private TrustedCertificateAdapter(Tab tab) {
|
||||||
|
mData = new AdapterData(tab, this);
|
||||||
|
load();
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void remove(CertHolder certHolder) {
|
||||||
|
mData.remove(certHolder);
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public int getListViewId(Tab tab) {
|
||||||
|
return tab.mList;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void load() {
|
||||||
|
mData.new AliasLoader().execute();
|
||||||
}
|
}
|
||||||
@Override public int getCount() {
|
@Override public int getCount() {
|
||||||
return mCertHolders.size();
|
return mData.mCertHoldersByUserId.valueAt(0).size();
|
||||||
}
|
}
|
||||||
@Override public CertHolder getItem(int position) {
|
@Override public CertHolder getItem(int position) {
|
||||||
return mCertHolders.get(position);
|
return mData.mCertHoldersByUserId.valueAt(0).get(position);
|
||||||
}
|
}
|
||||||
@Override public long getItemId(int position) {
|
@Override public long getItemId(int position) {
|
||||||
return position;
|
return position;
|
||||||
}
|
}
|
||||||
@Override public View getView(int position, View view, ViewGroup parent) {
|
@Override public View getView(int position, View view, ViewGroup parent) {
|
||||||
ViewHolder holder;
|
return getViewForCertificate(getItem(position), mData.mTab, view, parent);
|
||||||
if (view == null) {
|
}
|
||||||
LayoutInflater inflater = LayoutInflater.from(getActivity());
|
}
|
||||||
view = inflater.inflate(R.layout.trusted_credential, parent, false);
|
|
||||||
holder = new ViewHolder();
|
private class AdapterData {
|
||||||
holder.mSubjectPrimaryView = (TextView)
|
private final SparseArray<List<CertHolder>> mCertHoldersByUserId =
|
||||||
view.findViewById(R.id.trusted_credential_subject_primary);
|
new SparseArray<List<CertHolder>>();
|
||||||
holder.mSubjectSecondaryView = (TextView)
|
private final Tab mTab;
|
||||||
view.findViewById(R.id.trusted_credential_subject_secondary);
|
private final TrustedCertificateAdapterCommons mAdapter;
|
||||||
holder.mCheckBox = (CheckBox) view.findViewById(R.id.trusted_credential_status);
|
|
||||||
view.setTag(holder);
|
private AdapterData(Tab tab, TrustedCertificateAdapterCommons adapter) {
|
||||||
} else {
|
mAdapter = adapter;
|
||||||
holder = (ViewHolder) view.getTag();
|
mTab = tab;
|
||||||
}
|
}
|
||||||
CertHolder certHolder = mCertHolders.get(position);
|
|
||||||
holder.mSubjectPrimaryView.setText(certHolder.mSubjectPrimary);
|
private class AliasLoader extends AsyncTask<Void, Integer, SparseArray<List<CertHolder>>> {
|
||||||
holder.mSubjectSecondaryView.setText(certHolder.mSubjectSecondary);
|
private ProgressBar mProgressBar;
|
||||||
if (mTab.mCheckbox) {
|
private View mList;
|
||||||
holder.mCheckBox.setChecked(!certHolder.mDeleted);
|
|
||||||
holder.mCheckBox.setVisibility(View.VISIBLE);
|
|
||||||
}
|
|
||||||
return view;
|
|
||||||
};
|
|
||||||
|
|
||||||
private class AliasLoader extends AsyncTask<Void, Integer, List<CertHolder>> {
|
|
||||||
ProgressBar mProgressBar;
|
|
||||||
View mList;
|
|
||||||
@Override protected void onPreExecute() {
|
@Override protected void onPreExecute() {
|
||||||
View content = mTabHost.getTabContentView();
|
View content = mTabHost.getTabContentView();
|
||||||
mProgressBar = (ProgressBar) content.findViewById(mTab.mProgress);
|
mProgressBar = (ProgressBar) content.findViewById(mTab.mProgress);
|
||||||
mList = content.findViewById(mTab.mList);
|
mList = content.findViewById(mAdapter.getListViewId(mTab));
|
||||||
mProgressBar.setVisibility(View.VISIBLE);
|
mProgressBar.setVisibility(View.VISIBLE);
|
||||||
mList.setVisibility(View.GONE);
|
mList.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
@Override protected List<CertHolder> doInBackground(Void... params) {
|
@Override protected SparseArray<List<CertHolder>> doInBackground(Void... params) {
|
||||||
Set<String> aliases = mTab.getAliases(mStore);
|
SparseArray<List<CertHolder>> certHoldersByProfile =
|
||||||
int max = aliases.size();
|
new SparseArray<List<CertHolder>>();
|
||||||
int progress = 0;
|
try {
|
||||||
List<CertHolder> certHolders = new ArrayList<CertHolder>(max);
|
List<UserHandle> profiles = mUserManager.getUserProfiles();
|
||||||
for (String alias : aliases) {
|
final int n = profiles.size();
|
||||||
X509Certificate cert = (X509Certificate) mStore.getCertificate(alias, true);
|
// First we get all aliases for all profiles in order to show progress
|
||||||
certHolders.add(new CertHolder(mStore,
|
// correctly. Otherwise this could all be in a single loop.
|
||||||
TrustedCertificateAdapter.this,
|
SparseArray<List<ParcelableString>> aliasesByProfileId = new SparseArray<
|
||||||
mTab,
|
List<ParcelableString>>(n);
|
||||||
alias,
|
int max = 0;
|
||||||
cert));
|
int progress = 0;
|
||||||
publishProgress(++progress, max);
|
for (int i = 0; i < n; ++i) {
|
||||||
|
UserHandle profile = profiles.get(i);
|
||||||
|
int profileId = profile.getIdentifier();
|
||||||
|
KeyChainConnection keyChainConnection = KeyChain.bindAsUser(getActivity(),
|
||||||
|
profile);
|
||||||
|
// Saving the connection for later use on the certificate dialog.
|
||||||
|
mKeyChainConnectionByProfileId.put(profileId, keyChainConnection);
|
||||||
|
IKeyChainService service = keyChainConnection.getService();
|
||||||
|
List<ParcelableString> aliases = mTab.getAliases(service);
|
||||||
|
max += aliases.size();
|
||||||
|
aliasesByProfileId.put(profileId, aliases);
|
||||||
|
}
|
||||||
|
for (int i = 0; i < n; ++i) {
|
||||||
|
UserHandle profile = profiles.get(i);
|
||||||
|
int profileId = profile.getIdentifier();
|
||||||
|
List<ParcelableString> aliases = aliasesByProfileId.get(profileId);
|
||||||
|
IKeyChainService service = mKeyChainConnectionByProfileId.get(profileId)
|
||||||
|
.getService();
|
||||||
|
List<CertHolder> certHolders = new ArrayList<CertHolder>(max);
|
||||||
|
final int aliasMax = aliases.size();
|
||||||
|
for (int j = 0; j < aliasMax; ++j) {
|
||||||
|
String alias = aliases.get(j).string;
|
||||||
|
byte[] encodedCertificate = service.getEncodedCaCertificate(alias,
|
||||||
|
true);
|
||||||
|
X509Certificate cert = KeyChain.toCertificate(encodedCertificate);
|
||||||
|
certHolders.add(new CertHolder(service, mAdapter,
|
||||||
|
mTab, alias, cert, profileId));
|
||||||
|
publishProgress(++progress, max);
|
||||||
|
}
|
||||||
|
Collections.sort(certHolders);
|
||||||
|
certHoldersByProfile.put(profileId, certHolders);
|
||||||
|
}
|
||||||
|
return certHoldersByProfile;
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
Log.e(TAG, "Remote exception while loading aliases.", e);
|
||||||
|
return new SparseArray<List<CertHolder>>();
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
Log.e(TAG, "InterruptedException while loading aliases.", e);
|
||||||
|
return new SparseArray<List<CertHolder>>();
|
||||||
}
|
}
|
||||||
Collections.sort(certHolders);
|
|
||||||
return certHolders;
|
|
||||||
}
|
}
|
||||||
@Override protected void onProgressUpdate(Integer... progressAndMax) {
|
@Override protected void onProgressUpdate(Integer... progressAndMax) {
|
||||||
int progress = progressAndMax[0];
|
int progress = progressAndMax[0];
|
||||||
@@ -272,21 +462,31 @@ public class TrustedCredentialsSettings extends Fragment {
|
|||||||
}
|
}
|
||||||
mProgressBar.setProgress(progress);
|
mProgressBar.setProgress(progress);
|
||||||
}
|
}
|
||||||
@Override protected void onPostExecute(List<CertHolder> certHolders) {
|
@Override protected void onPostExecute(SparseArray<List<CertHolder>> certHolders) {
|
||||||
mCertHolders.clear();
|
mCertHoldersByUserId.clear();
|
||||||
mCertHolders.addAll(certHolders);
|
final int n = certHolders.size();
|
||||||
notifyDataSetChanged();
|
for (int i = 0; i < n; ++i) {
|
||||||
View content = mTabHost.getTabContentView();
|
mCertHoldersByUserId.put(certHolders.keyAt(i), certHolders.valueAt(i));
|
||||||
|
}
|
||||||
|
mAdapter.notifyDataSetChanged();
|
||||||
mProgressBar.setVisibility(View.GONE);
|
mProgressBar.setVisibility(View.GONE);
|
||||||
mList.setVisibility(View.VISIBLE);
|
mList.setVisibility(View.VISIBLE);
|
||||||
mProgressBar.setProgress(0);
|
mProgressBar.setProgress(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void remove(CertHolder certHolder) {
|
||||||
|
final int n = mCertHoldersByUserId.size();
|
||||||
|
for (int i = 0; i < n; ++i) {
|
||||||
|
mCertHoldersByUserId.valueAt(i).remove(certHolder);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class CertHolder implements Comparable<CertHolder> {
|
private static class CertHolder implements Comparable<CertHolder> {
|
||||||
private final TrustedCertificateStore mStore;
|
public int mProfileId;
|
||||||
private final TrustedCertificateAdapter mAdapter;
|
private final IKeyChainService mService;
|
||||||
|
private final TrustedCertificateAdapterCommons mAdapter;
|
||||||
private final Tab mTab;
|
private final Tab mTab;
|
||||||
private final String mAlias;
|
private final String mAlias;
|
||||||
private final X509Certificate mX509Cert;
|
private final X509Certificate mX509Cert;
|
||||||
@@ -296,12 +496,14 @@ public class TrustedCredentialsSettings extends Fragment {
|
|||||||
private final String mSubjectSecondary;
|
private final String mSubjectSecondary;
|
||||||
private boolean mDeleted;
|
private boolean mDeleted;
|
||||||
|
|
||||||
private CertHolder(TrustedCertificateStore store,
|
private CertHolder(IKeyChainService service,
|
||||||
TrustedCertificateAdapter adapter,
|
TrustedCertificateAdapterCommons adapter,
|
||||||
Tab tab,
|
Tab tab,
|
||||||
String alias,
|
String alias,
|
||||||
X509Certificate x509Cert) {
|
X509Certificate x509Cert,
|
||||||
mStore = store;
|
int profileId) {
|
||||||
|
mProfileId = profileId;
|
||||||
|
mService = service;
|
||||||
mAdapter = adapter;
|
mAdapter = adapter;
|
||||||
mTab = tab;
|
mTab = tab;
|
||||||
mAlias = alias;
|
mAlias = alias;
|
||||||
@@ -332,7 +534,13 @@ public class TrustedCredentialsSettings extends Fragment {
|
|||||||
mSubjectSecondary = "";
|
mSubjectSecondary = "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mDeleted = mTab.deleted(mStore, mAlias);
|
try {
|
||||||
|
mDeleted = mTab.deleted(mService, mAlias);
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
Log.e(TAG, "Remote exception while checking if alias " + mAlias + " is deleted.",
|
||||||
|
e);
|
||||||
|
mDeleted = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@Override public int compareTo(CertHolder o) {
|
@Override public int compareTo(CertHolder o) {
|
||||||
int primary = this.mSubjectPrimary.compareToIgnoreCase(o.mSubjectPrimary);
|
int primary = this.mSubjectPrimary.compareToIgnoreCase(o.mSubjectPrimary);
|
||||||
@@ -353,6 +561,32 @@ public class TrustedCredentialsSettings extends Fragment {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private View getViewForCertificate(CertHolder certHolder, Tab mTab, View convertView,
|
||||||
|
ViewGroup parent) {
|
||||||
|
ViewHolder holder;
|
||||||
|
if (convertView == null) {
|
||||||
|
LayoutInflater inflater = LayoutInflater.from(getActivity());
|
||||||
|
convertView = inflater.inflate(R.layout.trusted_credential, parent, false);
|
||||||
|
holder = new ViewHolder();
|
||||||
|
holder.mSubjectPrimaryView = (TextView)
|
||||||
|
convertView.findViewById(R.id.trusted_credential_subject_primary);
|
||||||
|
holder.mSubjectSecondaryView = (TextView)
|
||||||
|
convertView.findViewById(R.id.trusted_credential_subject_secondary);
|
||||||
|
holder.mCheckBox = (CheckBox) convertView.findViewById(
|
||||||
|
R.id.trusted_credential_status);
|
||||||
|
convertView.setTag(holder);
|
||||||
|
} else {
|
||||||
|
holder = (ViewHolder) convertView.getTag();
|
||||||
|
}
|
||||||
|
holder.mSubjectPrimaryView.setText(certHolder.mSubjectPrimary);
|
||||||
|
holder.mSubjectSecondaryView.setText(certHolder.mSubjectSecondary);
|
||||||
|
if (mTab.mCheckbox) {
|
||||||
|
holder.mCheckBox.setChecked(!certHolder.mDeleted);
|
||||||
|
holder.mCheckBox.setVisibility(View.VISIBLE);
|
||||||
|
}
|
||||||
|
return convertView;
|
||||||
|
}
|
||||||
|
|
||||||
private static class ViewHolder {
|
private static class ViewHolder {
|
||||||
private TextView mSubjectPrimaryView;
|
private TextView mSubjectPrimaryView;
|
||||||
private TextView mSubjectSecondaryView;
|
private TextView mSubjectSecondaryView;
|
||||||
@@ -438,13 +672,25 @@ public class TrustedCredentialsSettings extends Fragment {
|
|||||||
certDialog.show();
|
certDialog.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addCertChain(final CertHolder certHolder, final ArrayList<View> views,
|
private void addCertChain(final CertHolder certHolder,
|
||||||
final ArrayList<String> titles) {
|
final ArrayList<View> views, final ArrayList<String> titles) {
|
||||||
|
|
||||||
List<X509Certificate> certificates = null;
|
List<X509Certificate> certificates = null;
|
||||||
try {
|
try {
|
||||||
certificates = mStore.getCertificateChain(certHolder.mX509Cert);
|
KeyChainConnection keyChainConnection = mKeyChainConnectionByProfileId.get(
|
||||||
} catch (CertificateException ex) {
|
certHolder.mProfileId);
|
||||||
|
IKeyChainService service = keyChainConnection.getService();
|
||||||
|
List<String> chain = service.getCaCertificateChainAliases(certHolder.mAlias, true);
|
||||||
|
final int n = chain.size();
|
||||||
|
certificates = new ArrayList<X509Certificate>(n);
|
||||||
|
for (int i = 0; i < n; ++i) {
|
||||||
|
byte[] encodedCertificate = service.getEncodedCaCertificate(chain.get(i), true);
|
||||||
|
X509Certificate certificate = KeyChain.toCertificate(encodedCertificate);
|
||||||
|
certificates.add(certificate);
|
||||||
|
}
|
||||||
|
} catch (RemoteException ex) {
|
||||||
|
Log.e(TAG, "RemoteException while retrieving certificate chain for root "
|
||||||
|
+ certHolder.mAlias, ex);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for (X509Certificate certificate : certificates) {
|
for (X509Certificate certificate : certificates) {
|
||||||
@@ -461,37 +707,40 @@ public class TrustedCredentialsSettings extends Fragment {
|
|||||||
|
|
||||||
private class AliasOperation extends AsyncTask<Void, Void, Boolean> {
|
private class AliasOperation extends AsyncTask<Void, Void, Boolean> {
|
||||||
private final CertHolder mCertHolder;
|
private final CertHolder mCertHolder;
|
||||||
|
|
||||||
private AliasOperation(CertHolder certHolder) {
|
private AliasOperation(CertHolder certHolder) {
|
||||||
mCertHolder = certHolder;
|
mCertHolder = certHolder;
|
||||||
}
|
}
|
||||||
@Override protected Boolean doInBackground(Void... params) {
|
|
||||||
|
@Override
|
||||||
|
protected Boolean doInBackground(Void... params) {
|
||||||
try {
|
try {
|
||||||
KeyChainConnection keyChainConnection = KeyChain.bind(getActivity());
|
KeyChainConnection keyChainConnection = mKeyChainConnectionByProfileId.get(
|
||||||
|
mCertHolder.mProfileId);
|
||||||
IKeyChainService service = keyChainConnection.getService();
|
IKeyChainService service = keyChainConnection.getService();
|
||||||
try {
|
if (mCertHolder.mDeleted) {
|
||||||
if (mCertHolder.mDeleted) {
|
byte[] bytes = mCertHolder.mX509Cert.getEncoded();
|
||||||
byte[] bytes = mCertHolder.mX509Cert.getEncoded();
|
service.installCaCertificate(bytes);
|
||||||
service.installCaCertificate(bytes);
|
return true;
|
||||||
return true;
|
} else {
|
||||||
} else {
|
return service.deleteCaCertificate(mCertHolder.mAlias);
|
||||||
return service.deleteCaCertificate(mCertHolder.mAlias);
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
keyChainConnection.close();
|
|
||||||
}
|
}
|
||||||
} catch (CertificateEncodingException e) {
|
} catch (CertificateEncodingException e) {
|
||||||
|
Log.w(TAG, "Error while toggling alias " + mCertHolder.mAlias,
|
||||||
|
e);
|
||||||
return false;
|
return false;
|
||||||
} catch (IllegalStateException e) {
|
} catch (IllegalStateException e) {
|
||||||
// used by installCaCertificate to report errors
|
// used by installCaCertificate to report errors
|
||||||
|
Log.w(TAG, "Error while toggling alias " + mCertHolder.mAlias, e);
|
||||||
return false;
|
return false;
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
return false;
|
Log.w(TAG, "Error while toggling alias " + mCertHolder.mAlias, e);
|
||||||
} catch (InterruptedException e) {
|
|
||||||
Thread.currentThread().interrupt();
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@Override protected void onPostExecute(Boolean ok) {
|
|
||||||
|
@Override
|
||||||
|
protected void onPostExecute(Boolean ok) {
|
||||||
mCertHolder.mTab.postOperationUpdate(ok, mCertHolder);
|
mCertHolder.mTab.postOperationUpdate(ok, mCertHolder);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user