Merge "Change "Previously connected devices" string to "Saved devices"" into tm-dev
diff --git a/res/layout/preference_expand_divider.xml b/res/layout/preference_expand_divider.xml
index ce3d2e7..9b76688 100644
--- a/res/layout/preference_expand_divider.xml
+++ b/res/layout/preference_expand_divider.xml
@@ -34,7 +34,6 @@
android:layout_height="wrap_content"
android:layout_weight="1"
android:paddingEnd="4dp"
- android:singleLine="true"
android:textAlignment="viewStart"
style="@style/PreferenceCategoryTitleTextStyle"/>
diff --git a/res/layout/trusted_credentials.xml b/res/layout/trusted_credentials.xml
index 31f5f40..3663a79 100644
--- a/res/layout/trusted_credentials.xml
+++ b/res/layout/trusted_credentials.xml
@@ -13,78 +13,26 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<TabHost
+<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
+ <ProgressBar
+ android:id="@+id/progress"
+ style="?android:attr/progressBarStyleHorizontal"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+ android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+ android:visibility="gone"/>
+
<LinearLayout
+ android:id="@+id/content"
android:orientation="vertical"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent">
-
- <TabWidget
- android:id="@android:id/tabs"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content" />
-
- <FrameLayout
- android:id="@android:id/tabcontent"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent">
-
- <FrameLayout
- android:id="@+id/system_tab"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent">
-
- <ProgressBar
- android:id="@+id/system_progress"
- style="?android:attr/progressBarStyleHorizontal"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:paddingStart="?android:attr/listPreferredItemPaddingStart"
- android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
- android:visibility="gone" />
-
- <LinearLayout
- android:id="@+id/system_content"
- android:orientation="vertical"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:visibility="gone"
- android:animateLayoutChanges="true">
- </LinearLayout>
-
- </FrameLayout>
-
- <FrameLayout
- android:id="@+id/user_tab"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent">
-
- <ProgressBar
- android:id="@+id/user_progress"
- style="?android:attr/progressBarStyleLarge"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:paddingStart="?android:attr/listPreferredItemPaddingStart"
- android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
- android:visibility="gone" />
-
- <LinearLayout
- android:id="@+id/user_content"
- android:orientation="vertical"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:visibility="gone"
- android:animateLayoutChanges="true">
- </LinearLayout>
-
- </FrameLayout>
-
- </FrameLayout>
-
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:visibility="gone">
</LinearLayout>
-</TabHost>
+</FrameLayout>
\ No newline at end of file
diff --git a/src/com/android/settings/TrustedCredentialsDialogBuilder.java b/src/com/android/settings/TrustedCredentialsDialogBuilder.java
index 806da92..0dc8c25 100644
--- a/src/com/android/settings/TrustedCredentialsDialogBuilder.java
+++ b/src/com/android/settings/TrustedCredentialsDialogBuilder.java
@@ -34,7 +34,7 @@
import androidx.appcompat.app.AlertDialog;
import com.android.internal.widget.LockPatternUtils;
-import com.android.settings.TrustedCredentialsSettings.CertHolder;
+import com.android.settings.TrustedCredentialsFragment.CertHolder;
import com.android.settingslib.RestrictedLockUtils;
import java.security.cert.X509Certificate;
diff --git a/src/com/android/settings/TrustedCredentialsFragment.java b/src/com/android/settings/TrustedCredentialsFragment.java
new file mode 100644
index 0000000..ca565a4
--- /dev/null
+++ b/src/com/android/settings/TrustedCredentialsFragment.java
@@ -0,0 +1,1030 @@
+/*
+ * Copyright (C) 2022 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 static android.app.admin.DevicePolicyResources.Strings.Settings.PERSONAL_CATEGORY_HEADER;
+import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_CATEGORY_HEADER;
+import static android.widget.LinearLayout.LayoutParams.MATCH_PARENT;
+import static android.widget.LinearLayout.LayoutParams.WRAP_CONTENT;
+
+import android.annotation.UiThread;
+import android.app.Activity;
+import android.app.KeyguardManager;
+import android.app.admin.DevicePolicyManager;
+import android.app.settings.SettingsEnums;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.UserInfo;
+import android.content.res.TypedArray;
+import android.database.DataSetObserver;
+import android.graphics.drawable.Drawable;
+import android.net.http.SslCertificate;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.os.Parcelable;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.security.IKeyChainService;
+import android.security.KeyChain;
+import android.security.KeyChain.KeyChainConnection;
+import android.util.ArraySet;
+import android.util.Log;
+import android.util.SparseArray;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.BaseAdapter;
+import android.widget.BaseExpandableListAdapter;
+import android.widget.ExpandableListView;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.ListView;
+import android.widget.ProgressBar;
+import android.widget.Switch;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.app.UnlaunchableAppActivity;
+import com.android.internal.widget.LockPatternUtils;
+import com.android.settings.TrustedCredentialsSettings.Tab;
+import com.android.settings.core.InstrumentedFragment;
+
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import java.util.function.IntConsumer;
+
+/**
+ * Fragment to display trusted credentials settings for one tab.
+ */
+public class TrustedCredentialsFragment extends InstrumentedFragment
+ implements TrustedCredentialsDialogBuilder.DelegateInterface {
+
+ public static final String ARG_POSITION = "tab";
+ public static final String ARG_SHOW_NEW_FOR_USER = "ARG_SHOW_NEW_FOR_USER";
+
+ private static final String TAG = "TrustedCredentialsFragment";
+
+ private DevicePolicyManager mDevicePolicyManager;
+ private UserManager mUserManager;
+ private KeyguardManager mKeyguardManager;
+ private int mTrustAllCaUserId;
+
+ private static final String SAVED_CONFIRMED_CREDENTIAL_USERS = "ConfirmedCredentialUsers";
+ private static final String SAVED_CONFIRMING_CREDENTIAL_USER = "ConfirmingCredentialUser";
+ private static final int REQUEST_CONFIRM_CREDENTIALS = 1;
+
+ private GroupAdapter mGroupAdapter;
+ private AliasOperation mAliasOperation;
+ private ArraySet<Integer> mConfirmedCredentialUsers;
+ private int mConfirmingCredentialUser;
+ private IntConsumer mConfirmingCredentialListener;
+ private final Set<AdapterData.AliasLoader> mAliasLoaders = new ArraySet<>(2);
+ @GuardedBy("mKeyChainConnectionByProfileId")
+ private final SparseArray<KeyChainConnection>
+ mKeyChainConnectionByProfileId = new SparseArray<>();
+ private ViewGroup mFragmentView;
+
+ private final BroadcastReceiver mWorkProfileChangedReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ if (Intent.ACTION_MANAGED_PROFILE_AVAILABLE.equals(action)
+ || Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE.equals(action)
+ || Intent.ACTION_MANAGED_PROFILE_UNLOCKED.equals(action)) {
+ mGroupAdapter.load();
+ }
+ }
+ };
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ Activity activity = getActivity();
+ mDevicePolicyManager = activity.getSystemService(DevicePolicyManager.class);
+ mUserManager = activity.getSystemService(UserManager.class);
+ mKeyguardManager = activity.getSystemService(KeyguardManager.class);
+ mTrustAllCaUserId = activity.getIntent().getIntExtra(ARG_SHOW_NEW_FOR_USER,
+ UserHandle.USER_NULL);
+ mConfirmedCredentialUsers = new ArraySet<>(2);
+ mConfirmingCredentialUser = UserHandle.USER_NULL;
+ if (savedInstanceState != null) {
+ mConfirmingCredentialUser = savedInstanceState.getInt(SAVED_CONFIRMING_CREDENTIAL_USER,
+ UserHandle.USER_NULL);
+ ArrayList<Integer> users = savedInstanceState.getIntegerArrayList(
+ SAVED_CONFIRMED_CREDENTIAL_USERS);
+ if (users != null) {
+ mConfirmedCredentialUsers.addAll(users);
+ }
+ }
+
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE);
+ filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
+ filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNLOCKED);
+ activity.registerReceiver(mWorkProfileChangedReceiver, filter);
+ }
+
+ @Override
+ public void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ outState.putIntegerArrayList(SAVED_CONFIRMED_CREDENTIAL_USERS, new ArrayList<>(
+ mConfirmedCredentialUsers));
+ outState.putInt(SAVED_CONFIRMING_CREDENTIAL_USER, mConfirmingCredentialUser);
+ mGroupAdapter.saveState(outState);
+ }
+
+ @Override
+ public View onCreateView(
+ LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {
+ mFragmentView = (ViewGroup) inflater.inflate(R.layout.trusted_credentials, parent, false);
+
+ ViewGroup contentView = mFragmentView.findViewById(R.id.content);
+
+ mGroupAdapter = new GroupAdapter(
+ requireArguments().getInt(ARG_POSITION) == 0 ? Tab.SYSTEM : Tab.USER);
+ int profilesSize = mGroupAdapter.getGroupCount();
+ for (int i = 0; i < profilesSize; i++) {
+ Bundle childState = savedInstanceState == null ? null
+ : savedInstanceState.getBundle(mGroupAdapter.getKey(i));
+ createChildView(inflater, contentView, childState, i);
+ }
+ return mFragmentView;
+ }
+
+ @Override
+ public int getMetricsCategory() {
+ return SettingsEnums.TRUSTED_CREDENTIALS;
+ }
+
+ private void createChildView(
+ LayoutInflater inflater, ViewGroup parent, Bundle childState, int i) {
+ boolean isWork = mGroupAdapter.getUserInfoByGroup(i).isManagedProfile();
+ ChildAdapter adapter = mGroupAdapter.createChildAdapter(i);
+
+ LinearLayout containerView = (LinearLayout) inflater.inflate(
+ R.layout.trusted_credential_list_container, parent, false);
+ adapter.setContainerView(containerView, childState);
+
+ int profilesSize = mGroupAdapter.getGroupCount();
+ adapter.showHeader(profilesSize > 1);
+ adapter.showDivider(isWork);
+ adapter.setExpandIfAvailable(profilesSize <= 2 || !isWork, childState);
+ if (isWork) {
+ parent.addView(containerView);
+ } else {
+ parent.addView(containerView, 0);
+ }
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ mFragmentView.requestLayout();
+ }
+
+ @Override
+ public void onDestroy() {
+ getActivity().unregisterReceiver(mWorkProfileChangedReceiver);
+ for (AdapterData.AliasLoader aliasLoader : mAliasLoaders) {
+ aliasLoader.cancel(true);
+ }
+ mAliasLoaders.clear();
+ if (mAliasOperation != null) {
+ mAliasOperation.cancel(true);
+ mAliasOperation = null;
+ }
+ closeKeyChainConnections();
+ super.onDestroy();
+ }
+
+ @Override
+ public void onActivityResult(int requestCode, int resultCode, Intent data) {
+ if (requestCode == REQUEST_CONFIRM_CREDENTIALS) {
+ int userId = mConfirmingCredentialUser;
+ IntConsumer listener = mConfirmingCredentialListener;
+ // reset them before calling the listener because the listener may call back to start
+ // activity again. (though it should never happen.)
+ mConfirmingCredentialUser = UserHandle.USER_NULL;
+ mConfirmingCredentialListener = null;
+ if (resultCode == Activity.RESULT_OK) {
+ mConfirmedCredentialUsers.add(userId);
+ if (listener != null) {
+ listener.accept(userId);
+ }
+ }
+ }
+ }
+
+ private void closeKeyChainConnections() {
+ synchronized (mKeyChainConnectionByProfileId) {
+ int n = mKeyChainConnectionByProfileId.size();
+ for (int i = 0; i < n; ++i) {
+ mKeyChainConnectionByProfileId.valueAt(i).close();
+ }
+ mKeyChainConnectionByProfileId.clear();
+ }
+ }
+
+ /**
+ * Start work challenge activity.
+ *
+ * @return true if screenlock exists
+ */
+ private boolean startConfirmCredential(int userId) {
+ Intent newIntent = mKeyguardManager.createConfirmDeviceCredentialIntent(null, null, userId);
+ if (newIntent == null) {
+ return false;
+ }
+ mConfirmingCredentialUser = userId;
+ startActivityForResult(newIntent, REQUEST_CONFIRM_CREDENTIALS);
+ return true;
+ }
+
+ /**
+ * Adapter for expandable list view of certificates. Groups in the view correspond to profiles
+ * whereas children correspond to certificates.
+ */
+ private class GroupAdapter extends BaseExpandableListAdapter implements
+ ExpandableListView.OnGroupClickListener, ExpandableListView.OnChildClickListener {
+ private final AdapterData mData;
+ private final ArrayList<ChildAdapter> mChildAdapters = new ArrayList<>();
+
+ private GroupAdapter(Tab tab) {
+ mData = new AdapterData(tab, this);
+ load();
+ }
+
+ @Override
+ public int getGroupCount() {
+ return mData.mCertHoldersByUserId.size();
+ }
+
+ @Override
+ public int getChildrenCount(int groupPosition) {
+ List<CertHolder> certHolders = mData.mCertHoldersByUserId.valueAt(groupPosition);
+ if (certHolders != null) {
+ return certHolders.size();
+ }
+ return 0;
+ }
+
+ @Override
+ public UserHandle getGroup(int groupPosition) {
+ return new UserHandle(mData.mCertHoldersByUserId.keyAt(groupPosition));
+ }
+
+ @Override
+ public CertHolder getChild(int groupPosition, int childPosition) {
+ return mData.mCertHoldersByUserId.get(getUserIdByGroup(groupPosition)).get(
+ childPosition);
+ }
+
+ @Override
+ public long getGroupId(int groupPosition) {
+ return getUserIdByGroup(groupPosition);
+ }
+
+ private int getUserIdByGroup(int groupPosition) {
+ return mData.mCertHoldersByUserId.keyAt(groupPosition);
+ }
+
+ public UserInfo getUserInfoByGroup(int groupPosition) {
+ return mUserManager.getUserInfo(getUserIdByGroup(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 = Utils.inflateCategoryHeader(inflater, parent);
+ }
+
+ TextView title = convertView.findViewById(android.R.id.title);
+ if (getUserInfoByGroup(groupPosition).isManagedProfile()) {
+ title.setText(mDevicePolicyManager.getResources().getString(WORK_CATEGORY_HEADER,
+ () -> getString(R.string.category_work)));
+ } else {
+ title.setText(mDevicePolicyManager.getResources().getString(
+ PERSONAL_CATEGORY_HEADER,
+ () -> getString(R.string.category_personal)));
+
+ }
+ 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 boolean onChildClick(ExpandableListView expandableListView, View view,
+ int groupPosition, int childPosition, long id) {
+ showCertDialog(getChild(groupPosition, childPosition));
+ return true;
+ }
+
+ @Override
+ public boolean onGroupClick(ExpandableListView expandableListView, View view,
+ int groupPosition, long id) {
+ return !checkGroupExpandableAndStartWarningActivity(groupPosition);
+ }
+
+ public void load() {
+ mData.new AliasLoader().execute();
+ }
+
+ public void remove(CertHolder certHolder) {
+ mData.remove(certHolder);
+ }
+
+ ChildAdapter createChildAdapter(int groupPosition) {
+ ChildAdapter childAdapter = new ChildAdapter(this, groupPosition);
+ mChildAdapters.add(childAdapter);
+ return childAdapter;
+ }
+
+ public boolean checkGroupExpandableAndStartWarningActivity(int groupPosition) {
+ return checkGroupExpandableAndStartWarningActivity(groupPosition, true);
+ }
+
+ public boolean checkGroupExpandableAndStartWarningActivity(int groupPosition,
+ boolean startActivity) {
+ UserHandle groupUser = getGroup(groupPosition);
+ int groupUserId = groupUser.getIdentifier();
+ if (mUserManager.isQuietModeEnabled(groupUser)) {
+ if (startActivity) {
+ Intent intent =
+ UnlaunchableAppActivity.createInQuietModeDialogIntent(groupUserId);
+ getActivity().startActivity(intent);
+ }
+ return false;
+ } else if (!mUserManager.isUserUnlocked(groupUser)) {
+ LockPatternUtils lockPatternUtils = new LockPatternUtils(getActivity());
+ if (lockPatternUtils.isSeparateProfileChallengeEnabled(groupUserId)) {
+ if (startActivity) {
+ startConfirmCredential(groupUserId);
+ }
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private View getViewForCertificate(CertHolder certHolder, Tab mTab, View convertView,
+ ViewGroup parent) {
+ ViewHolder holder;
+ if (convertView == null) {
+ holder = new ViewHolder();
+ LayoutInflater inflater = LayoutInflater.from(getActivity());
+ convertView = inflater.inflate(R.layout.trusted_credential, parent, false);
+ convertView.setTag(holder);
+ holder.mSubjectPrimaryView =
+ convertView.findViewById(R.id.trusted_credential_subject_primary);
+ holder.mSubjectSecondaryView =
+ convertView.findViewById(R.id.trusted_credential_subject_secondary);
+ holder.mSwitch = convertView.findViewById(R.id.trusted_credential_status);
+ holder.mSwitch.setOnClickListener(view -> {
+ removeOrInstallCert((CertHolder) view.getTag());
+ });
+ } else {
+ holder = (ViewHolder) convertView.getTag();
+ }
+ holder.mSubjectPrimaryView.setText(certHolder.mSubjectPrimary);
+ holder.mSubjectSecondaryView.setText(certHolder.mSubjectSecondary);
+ if (mTab.mSwitch) {
+ holder.mSwitch.setChecked(!certHolder.mDeleted);
+ holder.mSwitch.setEnabled(!mUserManager.hasUserRestriction(
+ UserManager.DISALLOW_CONFIG_CREDENTIALS,
+ new UserHandle(certHolder.mProfileId)));
+ holder.mSwitch.setVisibility(View.VISIBLE);
+ holder.mSwitch.setTag(certHolder);
+ }
+ return convertView;
+ }
+
+ private void saveState(Bundle outState) {
+ for (int groupPosition = 0, mChildAdaptersSize = mChildAdapters.size();
+ groupPosition < mChildAdaptersSize; groupPosition++) {
+ ChildAdapter childAdapter = mChildAdapters.get(groupPosition);
+ outState.putBundle(getKey(groupPosition), childAdapter.saveState());
+ }
+ }
+
+ @NonNull
+ private String getKey(int groupPosition) {
+ return "Group" + getUserIdByGroup(groupPosition);
+ }
+
+ private class ViewHolder {
+ private TextView mSubjectPrimaryView;
+ private TextView mSubjectSecondaryView;
+ private Switch mSwitch;
+ }
+ }
+
+ private class ChildAdapter extends BaseAdapter implements View.OnClickListener,
+ AdapterView.OnItemClickListener {
+ private static final String KEY_CONTAINER = "Container";
+ private static final String KEY_IS_LIST_EXPANDED = "IsListExpanded";
+ private final int[] mGroupExpandedStateSet = {com.android.internal.R.attr.state_expanded};
+ private final int[] mEmptyStateSet = {};
+ private final LinearLayout.LayoutParams mHideContainerLayoutParams =
+ new LinearLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT, 0f);
+ private final LinearLayout.LayoutParams mHideListLayoutParams =
+ new LinearLayout.LayoutParams(MATCH_PARENT, 0);
+ private final LinearLayout.LayoutParams mShowLayoutParams = new LinearLayout.LayoutParams(
+ LinearLayout.LayoutParams.MATCH_PARENT, MATCH_PARENT, 1f);
+ private final GroupAdapter mParent;
+ private final int mGroupPosition;
+ /*
+ * This class doesn't hold the actual data. Events should notify parent.
+ * When notifying DataSet events in this class, events should be forwarded to mParent.
+ * i.e. this.notifyDataSetChanged -> mParent.notifyDataSetChanged -> mObserver.onChanged
+ * -> outsideObservers.onChanged() (e.g. ListView)
+ */
+ private final DataSetObserver mObserver = new DataSetObserver() {
+ @Override
+ public void onChanged() {
+ super.onChanged();
+ TrustedCredentialsFragment.ChildAdapter.super.notifyDataSetChanged();
+ }
+
+ @Override
+ public void onInvalidated() {
+ super.onInvalidated();
+ TrustedCredentialsFragment.ChildAdapter.super.notifyDataSetInvalidated();
+ }
+ };
+
+ private boolean mIsListExpanded = true;
+ private LinearLayout mContainerView;
+ private ViewGroup mHeaderView;
+ private ListView mListView;
+ private ImageView mIndicatorView;
+
+ private ChildAdapter(GroupAdapter parent, int groupPosition) {
+ mParent = parent;
+ mGroupPosition = groupPosition;
+ mParent.registerDataSetObserver(mObserver);
+ }
+
+ @Override
+ public int getCount() {
+ return mParent.getChildrenCount(mGroupPosition);
+ }
+
+ @Override
+ public CertHolder getItem(int position) {
+ return mParent.getChild(mGroupPosition, position);
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return mParent.getChildId(mGroupPosition, position);
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ return mParent.getChildView(mGroupPosition, position, false, convertView, parent);
+ }
+
+ // DataSet events
+ @Override
+ public void notifyDataSetChanged() {
+ // Don't call super as the parent will propagate this event back later in mObserver
+ mParent.notifyDataSetChanged();
+ }
+
+ @Override
+ public void notifyDataSetInvalidated() {
+ // Don't call super as the parent will propagate this event back later in mObserver
+ mParent.notifyDataSetInvalidated();
+ }
+
+ // View related codes
+ @Override
+ public void onClick(View view) {
+ mIsListExpanded = checkGroupExpandableAndStartWarningActivity() && !mIsListExpanded;
+ refreshViews();
+ }
+
+ @Override
+ public void onItemClick(AdapterView<?> adapterView, View view, int pos, long id) {
+ showCertDialog(getItem(pos));
+ }
+
+ public void setContainerView(LinearLayout containerView, Bundle savedState) {
+ mContainerView = containerView;
+ // Handle manually because multiple groups with same id elements.
+ mContainerView.setSaveFromParentEnabled(false);
+
+ mListView = mContainerView.findViewById(R.id.cert_list);
+ mListView.setAdapter(this);
+ mListView.setOnItemClickListener(this);
+ mListView.setItemsCanFocus(true);
+
+ mHeaderView = mContainerView.findViewById(R.id.header_view);
+ mHeaderView.setOnClickListener(this);
+
+ mIndicatorView = mHeaderView.findViewById(R.id.group_indicator);
+ mIndicatorView.setImageDrawable(getGroupIndicator());
+
+ FrameLayout headerContentContainer =
+ mHeaderView.findViewById(R.id.header_content_container);
+ headerContentContainer.addView(
+ mParent.getGroupView(mGroupPosition, true /* parent ignores it */, null,
+ headerContentContainer));
+
+ if (savedState != null) {
+ SparseArray<Parcelable> containerStates =
+ savedState.getSparseParcelableArray(KEY_CONTAINER, Parcelable.class);
+ if (containerStates != null) {
+ mContainerView.restoreHierarchyState(containerStates);
+ }
+ }
+ }
+
+ public void showHeader(boolean showHeader) {
+ mHeaderView.setVisibility(showHeader ? View.VISIBLE : View.GONE);
+ }
+
+ public void showDivider(boolean showDivider) {
+ View dividerView = mHeaderView.findViewById(R.id.header_divider);
+ dividerView.setVisibility(showDivider ? View.VISIBLE : View.GONE);
+ }
+
+ public void setExpandIfAvailable(boolean expanded, Bundle savedState) {
+ if (savedState != null) {
+ expanded = savedState.getBoolean(KEY_IS_LIST_EXPANDED);
+ }
+ mIsListExpanded = expanded && mParent.checkGroupExpandableAndStartWarningActivity(
+ mGroupPosition, false /* startActivity */);
+ refreshViews();
+ }
+
+ private boolean checkGroupExpandableAndStartWarningActivity() {
+ return mParent.checkGroupExpandableAndStartWarningActivity(mGroupPosition);
+ }
+
+ private void refreshViews() {
+ mIndicatorView.setImageState(mIsListExpanded ? mGroupExpandedStateSet
+ : mEmptyStateSet, false);
+ mListView.setLayoutParams(mIsListExpanded ? mShowLayoutParams
+ : mHideListLayoutParams);
+ mContainerView.setLayoutParams(mIsListExpanded ? mShowLayoutParams
+ : mHideContainerLayoutParams);
+ }
+
+ // Get group indicator from styles of ExpandableListView
+ private Drawable getGroupIndicator() {
+ TypedArray a = getActivity().obtainStyledAttributes(null,
+ com.android.internal.R.styleable.ExpandableListView,
+ com.android.internal.R.attr.expandableListViewStyle, 0);
+ Drawable groupIndicator = a.getDrawable(
+ com.android.internal.R.styleable.ExpandableListView_groupIndicator);
+ a.recycle();
+ return groupIndicator;
+ }
+
+ private Bundle saveState() {
+ Bundle bundle = new Bundle();
+ SparseArray<Parcelable> states = new SparseArray<>();
+ mContainerView.saveHierarchyState(states);
+ bundle.putSparseParcelableArray(KEY_CONTAINER, states);
+ bundle.putBoolean(KEY_IS_LIST_EXPANDED, mIsListExpanded);
+ return bundle;
+ }
+ }
+
+ private class AdapterData {
+ private final SparseArray<List<CertHolder>> mCertHoldersByUserId =
+ new SparseArray<>();
+ private final Tab mTab;
+ private final GroupAdapter mAdapter;
+
+ private AdapterData(Tab tab, GroupAdapter adapter) {
+ mAdapter = adapter;
+ mTab = tab;
+ }
+
+ private class AliasLoader extends AsyncTask<Void, Integer, SparseArray<List<CertHolder>>> {
+ private ProgressBar mProgressBar;
+ private View mContentView;
+ private Context mContext;
+
+ AliasLoader() {
+ mContext = getActivity();
+ mAliasLoaders.add(this);
+ List<UserHandle> profiles = mUserManager.getUserProfiles();
+ for (UserHandle profile : profiles) {
+ mCertHoldersByUserId.put(profile.getIdentifier(), new ArrayList<>());
+ }
+ }
+
+ private boolean shouldSkipProfile(UserHandle userHandle) {
+ return mUserManager.isQuietModeEnabled(userHandle)
+ || !mUserManager.isUserUnlocked(userHandle.getIdentifier());
+ }
+
+ @Override
+ protected void onPreExecute() {
+ mProgressBar = mFragmentView.findViewById(R.id.progress);
+ mContentView = mFragmentView.findViewById(R.id.content);
+ mProgressBar.setVisibility(View.VISIBLE);
+ mContentView.setVisibility(View.GONE);
+ }
+
+ @Override
+ protected SparseArray<List<CertHolder>> doInBackground(Void... params) {
+ SparseArray<List<CertHolder>> certHoldersByProfile =
+ new SparseArray<>();
+ try {
+ synchronized (mKeyChainConnectionByProfileId) {
+ List<UserHandle> profiles = mUserManager.getUserProfiles();
+ // First we get all aliases for all profiles in order to show progress
+ // correctly. Otherwise this could all be in a single loop.
+ SparseArray<List<String>> aliasesByProfileId =
+ new SparseArray<>(profiles.size());
+ int max = 0;
+ int progress = 0;
+ for (UserHandle profile : profiles) {
+ int profileId = profile.getIdentifier();
+ if (shouldSkipProfile(profile)) {
+ continue;
+ }
+ KeyChainConnection keyChainConnection = KeyChain.bindAsUser(mContext,
+ profile);
+ // Saving the connection for later use on the certificate dialog.
+ mKeyChainConnectionByProfileId.put(profileId, keyChainConnection);
+ IKeyChainService service = keyChainConnection.getService();
+ List<String> aliases = mTab.getAliases(service);
+ if (isCancelled()) {
+ return new SparseArray<>();
+ }
+ max += aliases.size();
+ aliasesByProfileId.put(profileId, aliases);
+ }
+ for (UserHandle profile : profiles) {
+ int profileId = profile.getIdentifier();
+ List<String> aliases = aliasesByProfileId.get(profileId);
+ if (isCancelled()) {
+ return new SparseArray<>();
+ }
+ KeyChainConnection keyChainConnection =
+ mKeyChainConnectionByProfileId.get(
+ profileId);
+ if (shouldSkipProfile(profile) || aliases == null
+ || keyChainConnection == null) {
+ certHoldersByProfile.put(profileId, new ArrayList<>(0));
+ continue;
+ }
+ IKeyChainService service = keyChainConnection.getService();
+ List<CertHolder> certHolders = new ArrayList<>(max);
+ for (String alias : aliases) {
+ 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<>();
+ } catch (InterruptedException e) {
+ Log.e(TAG, "InterruptedException while loading aliases.", e);
+ return new SparseArray<>();
+ }
+ }
+
+ @Override
+ protected void onProgressUpdate(Integer... progressAndMax) {
+ int progress = progressAndMax[0];
+ int max = progressAndMax[1];
+ if (max != mProgressBar.getMax()) {
+ mProgressBar.setMax(max);
+ }
+ mProgressBar.setProgress(progress);
+ }
+
+ @Override
+ protected void onPostExecute(SparseArray<List<CertHolder>> certHolders) {
+ mCertHoldersByUserId.clear();
+ int n = certHolders.size();
+ for (int i = 0; i < n; ++i) {
+ mCertHoldersByUserId.put(certHolders.keyAt(i), certHolders.valueAt(i));
+ }
+ mAdapter.notifyDataSetChanged();
+ mProgressBar.setVisibility(View.GONE);
+ mContentView.setVisibility(View.VISIBLE);
+ mProgressBar.setProgress(0);
+ mAliasLoaders.remove(this);
+ 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<>();
+ 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);
+ }
+ }
+
+ public void remove(CertHolder certHolder) {
+ if (mCertHoldersByUserId != null) {
+ List<CertHolder> certs = mCertHoldersByUserId.get(certHolder.mProfileId);
+ if (certs != null) {
+ certs.remove(certHolder);
+ }
+ }
+ }
+ }
+
+ /* package */ static class CertHolder implements Comparable<CertHolder> {
+ public int mProfileId;
+ private final IKeyChainService mService;
+ private final GroupAdapter mAdapter;
+ private final Tab mTab;
+ private final String mAlias;
+ private final X509Certificate mX509Cert;
+
+ private final SslCertificate mSslCert;
+ private final String mSubjectPrimary;
+ private final String mSubjectSecondary;
+ private boolean mDeleted;
+
+ private CertHolder(IKeyChainService service,
+ GroupAdapter adapter,
+ Tab tab,
+ String alias,
+ X509Certificate x509Cert,
+ int profileId) {
+ mProfileId = profileId;
+ mService = service;
+ mAdapter = adapter;
+ mTab = tab;
+ mAlias = alias;
+ mX509Cert = x509Cert;
+
+ mSslCert = new SslCertificate(x509Cert);
+
+ String cn = mSslCert.getIssuedTo().getCName();
+ String o = mSslCert.getIssuedTo().getOName();
+ String ou = mSslCert.getIssuedTo().getUName();
+ // if we have a O, use O as primary subject, secondary prefer CN over OU
+ // if we don't have an O, use CN as primary, empty secondary
+ // if we don't have O or CN, use DName as primary, empty secondary
+ if (!o.isEmpty()) {
+ if (!cn.isEmpty()) {
+ mSubjectPrimary = o;
+ mSubjectSecondary = cn;
+ } else {
+ mSubjectPrimary = o;
+ mSubjectSecondary = ou;
+ }
+ } else {
+ if (!cn.isEmpty()) {
+ mSubjectPrimary = cn;
+ mSubjectSecondary = "";
+ } else {
+ mSubjectPrimary = mSslCert.getIssuedTo().getDName();
+ mSubjectSecondary = "";
+ }
+ }
+ 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) {
+ int primary = this.mSubjectPrimary.compareToIgnoreCase(o.mSubjectPrimary);
+ if (primary != 0) {
+ return primary;
+ }
+ return this.mSubjectSecondary.compareToIgnoreCase(o.mSubjectSecondary);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof CertHolder)) {
+ return false;
+ }
+ CertHolder other = (CertHolder) o;
+ return mAlias.equals(other.mAlias);
+ }
+
+ @Override
+ public int 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 boolean isTrustAllCaCertModeInProgress() {
+ return mTrustAllCaUserId != UserHandle.USER_NULL;
+ }
+
+ private void showTrustAllCaDialog(List<CertHolder> unapprovedCertHolders) {
+ CertHolder[] arr =
+ unapprovedCertHolders.toArray(new CertHolder[unapprovedCertHolders.size()]);
+ new TrustedCredentialsDialogBuilder(getActivity(), this)
+ .setCertHolders(arr)
+ .setOnDismissListener(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;
+ try {
+ synchronized (mKeyChainConnectionByProfileId) {
+ KeyChainConnection keyChainConnection = mKeyChainConnectionByProfileId.get(
+ certHolder.mProfileId);
+ IKeyChainService service = keyChainConnection.getService();
+ List<String> chain = service.getCaCertificateChainAliases(certHolder.mAlias, true);
+ certificates = new ArrayList<>(chain.size());
+ for (String s : chain) {
+ byte[] encodedCertificate = service.getEncodedCaCertificate(s, 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 certificates;
+ }
+
+ @Override
+ public void removeOrInstallCert(CertHolder certHolder) {
+ new AliasOperation(certHolder).execute();
+ }
+
+ @Override
+ public boolean startConfirmCredentialIfNotConfirmed(int userId,
+ IntConsumer onCredentialConfirmedListener) {
+ if (mConfirmedCredentialUsers.contains(userId)) {
+ // Credential has been confirmed. Don't start activity.
+ return false;
+ }
+
+ boolean result = startConfirmCredential(userId);
+ if (result) {
+ mConfirmingCredentialListener = onCredentialConfirmedListener;
+ }
+ return result;
+ }
+
+ private class AliasOperation extends AsyncTask<Void, Void, Boolean> {
+ private final CertHolder mCertHolder;
+
+ private AliasOperation(CertHolder certHolder) {
+ mCertHolder = certHolder;
+ mAliasOperation = this;
+ }
+
+ @Override
+ protected Boolean doInBackground(Void... params) {
+ try {
+ synchronized (mKeyChainConnectionByProfileId) {
+ KeyChainConnection keyChainConnection = mKeyChainConnectionByProfileId.get(
+ mCertHolder.mProfileId);
+ IKeyChainService service = keyChainConnection.getService();
+ if (mCertHolder.mDeleted) {
+ byte[] bytes = mCertHolder.mX509Cert.getEncoded();
+ service.installCaCertificate(bytes);
+ return true;
+ } else {
+ return service.deleteCaCertificate(mCertHolder.mAlias);
+ }
+ }
+ } catch (CertificateEncodingException | SecurityException | IllegalStateException
+ | RemoteException e) {
+ Log.w(TAG, "Error while toggling alias " + mCertHolder.mAlias, e);
+ return false;
+ }
+ }
+
+ @Override
+ protected void onPostExecute(Boolean ok) {
+ if (ok) {
+ if (mCertHolder.mTab.mSwitch) {
+ mCertHolder.mDeleted = !mCertHolder.mDeleted;
+ } else {
+ mCertHolder.mAdapter.remove(mCertHolder);
+ }
+ mCertHolder.mAdapter.notifyDataSetChanged();
+ } else {
+ // bail, reload to reset to known state
+ mCertHolder.mAdapter.load();
+ }
+ mAliasOperation = null;
+ }
+ }
+}
diff --git a/src/com/android/settings/TrustedCredentialsSettings.java b/src/com/android/settings/TrustedCredentialsSettings.java
index 735cb3b..a88019e 100644
--- a/src/com/android/settings/TrustedCredentialsSettings.java
+++ b/src/com/android/settings/TrustedCredentialsSettings.java
@@ -16,121 +16,114 @@
package com.android.settings;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.PERSONAL_CATEGORY_HEADER;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_CATEGORY_HEADER;
-import static android.widget.LinearLayout.LayoutParams.MATCH_PARENT;
-import static android.widget.LinearLayout.LayoutParams.WRAP_CONTENT;
-
-import android.animation.LayoutTransition;
-import android.annotation.UiThread;
-import android.app.Activity;
-import android.app.KeyguardManager;
-import android.app.admin.DevicePolicyManager;
import android.app.settings.SettingsEnums;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.DialogInterface;
import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.UserInfo;
-import android.content.res.TypedArray;
-import android.database.DataSetObserver;
-import android.graphics.drawable.Drawable;
-import android.net.http.SslCertificate;
-import android.os.AsyncTask;
import android.os.Bundle;
import android.os.RemoteException;
-import android.os.UserHandle;
-import android.os.UserManager;
import android.security.IKeyChainService;
-import android.security.KeyChain;
-import android.security.KeyChain.KeyChainConnection;
-import android.util.ArraySet;
-import android.util.Log;
-import android.util.SparseArray;
-import android.view.LayoutInflater;
import android.view.View;
-import android.view.ViewGroup;
-import android.widget.AdapterView;
-import android.widget.BaseAdapter;
-import android.widget.BaseExpandableListAdapter;
-import android.widget.ExpandableListView;
-import android.widget.FrameLayout;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.ListView;
-import android.widget.ProgressBar;
-import android.widget.Switch;
-import android.widget.TabHost;
-import android.widget.TextView;
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.app.UnlaunchableAppActivity;
-import com.android.internal.widget.LockPatternUtils;
-import com.android.settings.core.InstrumentedFragment;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.fragment.app.Fragment;
+import androidx.viewpager2.adapter.FragmentStateAdapter;
+import androidx.viewpager2.widget.ViewPager2;
-import java.security.cert.CertificateEncodingException;
-import java.security.cert.X509Certificate;
-import java.util.ArrayList;
-import java.util.Collections;
+import com.android.settings.dashboard.DashboardFragment;
+
+import com.google.android.material.tabs.TabLayout;
+import com.google.android.material.tabs.TabLayoutMediator;
+import com.google.common.collect.ImmutableList;
+
import java.util.List;
-import java.util.Set;
-import java.util.function.IntConsumer;
-public class TrustedCredentialsSettings extends InstrumentedFragment
- implements TrustedCredentialsDialogBuilder.DelegateInterface {
-
- public static final String ARG_SHOW_NEW_FOR_USER = "ARG_SHOW_NEW_FOR_USER";
+/**
+ * Main fragment to display trusted credentials settings.
+ */
+public class TrustedCredentialsSettings extends DashboardFragment {
private static final String TAG = "TrustedCredentialsSettings";
- private DevicePolicyManager mDevicePolicyManager;
- private UserManager mUserManager;
- private KeyguardManager mKeyguardManager;
- private int mTrustAllCaUserId;
+ public static final String ARG_SHOW_NEW_FOR_USER = "ARG_SHOW_NEW_FOR_USER";
- private static final String SAVED_CONFIRMED_CREDENTIAL_USERS = "ConfirmedCredentialUsers";
- private static final String SAVED_CONFIRMING_CREDENTIAL_USER = "ConfirmingCredentialUser";
+ static final ImmutableList<Tab> TABS = ImmutableList.of(Tab.SYSTEM, Tab.USER);
+
private static final String USER_ACTION = "com.android.settings.TRUSTED_CREDENTIALS_USER";
- private static final int REQUEST_CONFIRM_CREDENTIALS = 1;
@Override
public int getMetricsCategory() {
return SettingsEnums.TRUSTED_CREDENTIALS;
}
- private enum Tab {
- SYSTEM("system",
- R.string.trusted_credentials_system_tab,
- R.id.system_tab,
- R.id.system_progress,
- R.id.system_content,
- true),
- USER("user",
- R.string.trusted_credentials_user_tab,
- R.id.user_tab,
- R.id.user_progress,
- R.id.user_content,
- false);
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ getActivity().setTitle(R.string.trusted_credentials);
+ }
- private final String mTag;
+ @Override
+ protected int getPreferenceScreenResId() {
+ return R.xml.placeholder_preference_screen;
+ }
+
+ @Override
+ protected String getLogTag() {
+ return TAG;
+ }
+
+ @Override
+ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
+ View tabContainer = view.findViewById(R.id.tab_container);
+ tabContainer.setVisibility(View.VISIBLE);
+
+ ViewPager2 viewPager = tabContainer.findViewById(R.id.view_pager);
+ viewPager.setAdapter(new FragmentAdapter(this));
+ viewPager.setUserInputEnabled(false);
+
+ Intent intent = getActivity().getIntent();
+ if (intent != null && USER_ACTION.equals(intent.getAction())) {
+ viewPager.setCurrentItem(TABS.indexOf(Tab.USER), false);
+ }
+
+ TabLayout tabLayout = tabContainer.findViewById(R.id.tabs);
+ new TabLayoutMediator(tabLayout, viewPager, false, false,
+ (tab, position) -> tab.setText(TABS.get(position).mLabel)).attach();
+ }
+
+ private static class FragmentAdapter extends FragmentStateAdapter {
+ FragmentAdapter(Fragment fragment) {
+ super(fragment);
+ }
+
+ @NonNull
+ @Override
+ public Fragment createFragment(int position) {
+ TrustedCredentialsFragment fragment = new TrustedCredentialsFragment();
+ Bundle args = new Bundle();
+ args.putInt(TrustedCredentialsFragment.ARG_POSITION, position);
+ fragment.setArguments(args);
+ return fragment;
+ }
+
+ @Override
+ public int getItemCount() {
+ return TrustedCredentialsSettings.TABS.size();
+ }
+ }
+
+ enum Tab {
+ SYSTEM(R.string.trusted_credentials_system_tab, true),
+ USER(R.string.trusted_credentials_user_tab, false);
+
private final int mLabel;
- private final int mView;
- private final int mProgress;
- private final int mContentView;
- private final boolean mSwitch;
+ final boolean mSwitch;
- private Tab(String tag, int label, int view, int progress, int contentView,
- boolean withSwitch) {
- mTag = tag;
+ Tab(int label, boolean withSwitch) {
mLabel = label;
- mView = view;
- mProgress = progress;
- mContentView = contentView;
mSwitch = withSwitch;
}
- private List<String> getAliases(IKeyChainService service) throws RemoteException {
+ List<String> getAliases(IKeyChainService service) throws RemoteException {
switch (this) {
case SYSTEM: {
return service.getSystemCaAliases().getList();
@@ -140,7 +133,8 @@
}
throw new AssertionError();
}
- private boolean deleted(IKeyChainService service, String alias) throws RemoteException {
+
+ boolean deleted(IKeyChainService service, String alias) throws RemoteException {
switch (this) {
case SYSTEM:
return !service.containsCaAlias(alias);
@@ -150,895 +144,4 @@
throw new AssertionError();
}
}
-
- private TabHost mTabHost;
- private ArrayList<GroupAdapter> mGroupAdapters = new ArrayList<>(2);
- private AliasOperation mAliasOperation;
- private ArraySet<Integer> mConfirmedCredentialUsers;
- private int mConfirmingCredentialUser;
- private IntConsumer mConfirmingCredentialListener;
- private Set<AdapterData.AliasLoader> mAliasLoaders = new ArraySet<AdapterData.AliasLoader>(2);
- @GuardedBy("mKeyChainConnectionByProfileId")
- private final SparseArray<KeyChainConnection>
- mKeyChainConnectionByProfileId = new SparseArray<KeyChainConnection>();
-
- private BroadcastReceiver mWorkProfileChangedReceiver = new BroadcastReceiver() {
-
- @Override
- public void onReceive(Context context, Intent intent) {
- final String action = intent.getAction();
- if (Intent.ACTION_MANAGED_PROFILE_AVAILABLE.equals(action) ||
- Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE.equals(action) ||
- Intent.ACTION_MANAGED_PROFILE_UNLOCKED.equals(action)) {
- for (GroupAdapter adapter : mGroupAdapters) {
- adapter.load();
- }
- }
- }
-
- };
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- final Activity activity = getActivity();
- mDevicePolicyManager = activity.getSystemService(DevicePolicyManager.class);
- mUserManager = (UserManager) activity.getSystemService(Context.USER_SERVICE);
- mKeyguardManager = (KeyguardManager) activity
- .getSystemService(Context.KEYGUARD_SERVICE);
- mTrustAllCaUserId = activity.getIntent().getIntExtra(ARG_SHOW_NEW_FOR_USER,
- UserHandle.USER_NULL);
- mConfirmedCredentialUsers = new ArraySet<>(2);
- mConfirmingCredentialUser = UserHandle.USER_NULL;
- if (savedInstanceState != null) {
- mConfirmingCredentialUser = savedInstanceState.getInt(SAVED_CONFIRMING_CREDENTIAL_USER,
- UserHandle.USER_NULL);
- ArrayList<Integer> users = savedInstanceState.getIntegerArrayList(
- SAVED_CONFIRMED_CREDENTIAL_USERS);
- if (users != null) {
- mConfirmedCredentialUsers.addAll(users);
- }
- }
-
- mConfirmingCredentialListener = null;
-
- IntentFilter filter = new IntentFilter();
- filter.addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE);
- filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
- filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNLOCKED);
- activity.registerReceiver(mWorkProfileChangedReceiver, filter);
-
- activity.setTitle(R.string.trusted_credentials);
- }
-
- @Override
- public void onSaveInstanceState(Bundle outState) {
- super.onSaveInstanceState(outState);
- outState.putIntegerArrayList(SAVED_CONFIRMED_CREDENTIAL_USERS, new ArrayList<>(
- mConfirmedCredentialUsers));
- outState.putInt(SAVED_CONFIRMING_CREDENTIAL_USER, mConfirmingCredentialUser);
- }
-
- @Override public View onCreateView(
- LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {
- mTabHost = (TabHost) inflater.inflate(R.layout.trusted_credentials, parent, false);
- mTabHost.setup();
- addTab(Tab.SYSTEM);
- // TODO add Install button on Tab.USER to go to CertInstaller like KeyChainActivity
- addTab(Tab.USER);
- if (getActivity().getIntent() != null &&
- USER_ACTION.equals(getActivity().getIntent().getAction())) {
- mTabHost.setCurrentTabByTag(Tab.USER.mTag);
- }
- return mTabHost;
- }
- @Override
- public void onDestroy() {
- getActivity().unregisterReceiver(mWorkProfileChangedReceiver);
- for (AdapterData.AliasLoader aliasLoader : mAliasLoaders) {
- aliasLoader.cancel(true);
- }
- mAliasLoaders.clear();
- mGroupAdapters.clear();
- if (mAliasOperation != null) {
- mAliasOperation.cancel(true);
- mAliasOperation = null;
- }
- closeKeyChainConnections();
- super.onDestroy();
- }
-
- @Override
- public void onActivityResult(int requestCode, int resultCode, Intent data) {
- if (requestCode == REQUEST_CONFIRM_CREDENTIALS) {
- int userId = mConfirmingCredentialUser;
- IntConsumer listener = mConfirmingCredentialListener;
- // reset them before calling the listener because the listener may call back to start
- // activity again. (though it should never happen.)
- mConfirmingCredentialUser = UserHandle.USER_NULL;
- mConfirmingCredentialListener = null;
- if (resultCode == Activity.RESULT_OK) {
- mConfirmedCredentialUsers.add(userId);
- if (listener != null) {
- listener.accept(userId);
- }
- }
- }
- }
-
- private void closeKeyChainConnections() {
- synchronized (mKeyChainConnectionByProfileId) {
- final int n = mKeyChainConnectionByProfileId.size();
- for (int i = 0; i < n; ++i) {
- mKeyChainConnectionByProfileId.valueAt(i).close();
- }
- mKeyChainConnectionByProfileId.clear();
- }
- }
-
- private void addTab(Tab tab) {
- TabHost.TabSpec systemSpec = mTabHost.newTabSpec(tab.mTag)
- .setIndicator(getActivity().getString(tab.mLabel))
- .setContent(tab.mView);
- mTabHost.addTab(systemSpec);
-
- final GroupAdapter groupAdapter = new GroupAdapter(tab);
- mGroupAdapters.add(groupAdapter);
- final int profilesSize = groupAdapter.getGroupCount();
-
- // Add a transition for non-visibility events like resizing the pane.
- final ViewGroup contentView = (ViewGroup) mTabHost.findViewById(tab.mContentView);
- contentView.getLayoutTransition().enableTransitionType(LayoutTransition.CHANGING);
-
- final LayoutInflater inflater = LayoutInflater.from(getActivity());
- for (int i = 0; i < groupAdapter.getGroupCount(); i++) {
- final boolean isWork = groupAdapter.getUserInfoByGroup(i).isManagedProfile();
- final ChildAdapter adapter = groupAdapter.getChildAdapter(i);
-
- final LinearLayout containerView = (LinearLayout) inflater
- .inflate(R.layout.trusted_credential_list_container, contentView, false);
- adapter.setContainerView(containerView);
-
- adapter.showHeader(profilesSize > 1);
- adapter.showDivider(isWork);
- adapter.setExpandIfAvailable(profilesSize <= 2 ? true : !isWork);
- if (isWork) {
- contentView.addView(containerView);
- } else {
- contentView.addView(containerView, 0);
- }
- }
- }
-
- /**
- * Start work challenge activity.
- * @return true if screenlock exists
- */
- private boolean startConfirmCredential(int userId) {
- final Intent newIntent = mKeyguardManager.createConfirmDeviceCredentialIntent(null, null,
- userId);
- if (newIntent == null) {
- return false;
- }
- mConfirmingCredentialUser = userId;
- startActivityForResult(newIntent, REQUEST_CONFIRM_CREDENTIALS);
- return true;
- }
-
- /**
- * Adapter for expandable list view of certificates. Groups in the view correspond to profiles
- * whereas children correspond to certificates.
- */
- private class GroupAdapter extends BaseExpandableListAdapter implements
- ExpandableListView.OnGroupClickListener, ExpandableListView.OnChildClickListener,
- View.OnClickListener {
- private final AdapterData mData;
-
- private GroupAdapter(Tab tab) {
- mData = new AdapterData(tab, this);
- load();
- }
-
- @Override
- public int getGroupCount() {
- return mData.mCertHoldersByUserId.size();
- }
- @Override
- public int getChildrenCount(int groupPosition) {
- List<CertHolder> certHolders = mData.mCertHoldersByUserId.valueAt(groupPosition);
- if (certHolders != null) {
- return certHolders.size();
- }
- return 0;
- }
- @Override
- public UserHandle getGroup(int groupPosition) {
- return new UserHandle(mData.mCertHoldersByUserId.keyAt(groupPosition));
- }
- @Override
- public CertHolder getChild(int groupPosition, int childPosition) {
- return mData.mCertHoldersByUserId.get(getUserIdByGroup(groupPosition)).get(
- childPosition);
- }
- @Override
- public long getGroupId(int groupPosition) {
- return getUserIdByGroup(groupPosition);
- }
- private int getUserIdByGroup(int groupPosition) {
- return mData.mCertHoldersByUserId.keyAt(groupPosition);
- }
- public UserInfo getUserInfoByGroup(int groupPosition) {
- return mUserManager.getUserInfo(getUserIdByGroup(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 = Utils.inflateCategoryHeader(inflater, parent);
- }
-
- final TextView title = (TextView) convertView.findViewById(android.R.id.title);
- if (getUserInfoByGroup(groupPosition).isManagedProfile()) {
- title.setText(mDevicePolicyManager.getResources().getString(WORK_CATEGORY_HEADER,
- () -> getString(R.string.category_work)));
- } else {
- title.setText(mDevicePolicyManager.getResources().getString(
- PERSONAL_CATEGORY_HEADER,
- () -> getString(R.string.category_personal)));
-
- }
- 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 boolean onChildClick(ExpandableListView expandableListView, View view,
- int groupPosition, int childPosition, long id) {
- showCertDialog(getChild(groupPosition, childPosition));
- return true;
- }
-
- /**
- * Called when the switch on a system certificate is clicked. This will toggle whether it
- * is trusted as a credential.
- */
- @Override
- public void onClick(View view) {
- CertHolder holder = (CertHolder) view.getTag();
- removeOrInstallCert(holder);
- }
-
- @Override
- public boolean onGroupClick(ExpandableListView expandableListView, View view,
- int groupPosition, long id) {
- return !checkGroupExpandableAndStartWarningActivity(groupPosition);
- }
-
- public void load() {
- mData.new AliasLoader().execute();
- }
-
- public void remove(CertHolder certHolder) {
- mData.remove(certHolder);
- }
-
- public void setExpandableListView(ExpandableListView lv) {
- lv.setAdapter(this);
- lv.setOnGroupClickListener(this);
- lv.setOnChildClickListener(this);
- lv.setVisibility(View.VISIBLE);
- }
-
- public ChildAdapter getChildAdapter(int groupPosition) {
- return new ChildAdapter(this, groupPosition);
- }
-
- public boolean checkGroupExpandableAndStartWarningActivity(int groupPosition) {
- return checkGroupExpandableAndStartWarningActivity(groupPosition, true);
- }
-
- public boolean checkGroupExpandableAndStartWarningActivity(int groupPosition,
- boolean startActivity) {
- final UserHandle groupUser = getGroup(groupPosition);
- final int groupUserId = groupUser.getIdentifier();
- if (mUserManager.isQuietModeEnabled(groupUser)) {
- final Intent intent = UnlaunchableAppActivity.createInQuietModeDialogIntent(
- groupUserId);
- if (startActivity) {
- getActivity().startActivity(intent);
- }
- return false;
- } else if (!mUserManager.isUserUnlocked(groupUser)) {
- final LockPatternUtils lockPatternUtils = new LockPatternUtils(
- getActivity());
- if (lockPatternUtils.isSeparateProfileChallengeEnabled(groupUserId)) {
- if (startActivity) {
- startConfirmCredential(groupUserId);
- }
- return false;
- }
- }
- return true;
- }
-
- private View getViewForCertificate(CertHolder certHolder, Tab mTab, View convertView,
- ViewGroup parent) {
- ViewHolder holder;
- if (convertView == null) {
- holder = new ViewHolder();
- LayoutInflater inflater = LayoutInflater.from(getActivity());
- convertView = inflater.inflate(R.layout.trusted_credential, parent, false);
- convertView.setTag(holder);
- holder.mSubjectPrimaryView = (TextView)
- convertView.findViewById(R.id.trusted_credential_subject_primary);
- holder.mSubjectSecondaryView = (TextView)
- convertView.findViewById(R.id.trusted_credential_subject_secondary);
- holder.mSwitch = (Switch) convertView.findViewById(
- R.id.trusted_credential_status);
- holder.mSwitch.setOnClickListener(this);
- } else {
- holder = (ViewHolder) convertView.getTag();
- }
- holder.mSubjectPrimaryView.setText(certHolder.mSubjectPrimary);
- holder.mSubjectSecondaryView.setText(certHolder.mSubjectSecondary);
- if (mTab.mSwitch) {
- holder.mSwitch.setChecked(!certHolder.mDeleted);
- holder.mSwitch.setEnabled(!mUserManager.hasUserRestriction(
- UserManager.DISALLOW_CONFIG_CREDENTIALS,
- new UserHandle(certHolder.mProfileId)));
- holder.mSwitch.setVisibility(View.VISIBLE);
- holder.mSwitch.setTag(certHolder);
- }
- return convertView;
- }
-
- private class ViewHolder {
- private TextView mSubjectPrimaryView;
- private TextView mSubjectSecondaryView;
- private Switch mSwitch;
- }
- }
-
- private class ChildAdapter extends BaseAdapter implements View.OnClickListener,
- AdapterView.OnItemClickListener {
- private final int[] GROUP_EXPANDED_STATE_SET = {com.android.internal.R.attr.state_expanded};
- private final int[] EMPTY_STATE_SET = {};
- private final LinearLayout.LayoutParams HIDE_CONTAINER_LAYOUT_PARAMS =
- new LinearLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT, 0f);
- private final LinearLayout.LayoutParams HIDE_LIST_LAYOUT_PARAMS =
- new LinearLayout.LayoutParams(MATCH_PARENT, 0);
- private final LinearLayout.LayoutParams SHOW_LAYOUT_PARAMS = new LinearLayout.LayoutParams(
- LinearLayout.LayoutParams.MATCH_PARENT, MATCH_PARENT, 1f);
- private final GroupAdapter mParent;
- private final int mGroupPosition;
- /*
- * This class doesn't hold the actual data. Events should notify parent.
- * When notifying DataSet events in this class, events should be forwarded to mParent.
- * i.e. this.notifyDataSetChanged -> mParent.notifyDataSetChanged -> mObserver.onChanged
- * -> outsideObservers.onChanged() (e.g. ListView)
- */
- private final DataSetObserver mObserver = new DataSetObserver() {
- @Override
- public void onChanged() {
- super.onChanged();
- ChildAdapter.super.notifyDataSetChanged();
- }
- @Override
- public void onInvalidated() {
- super.onInvalidated();
- ChildAdapter.super.notifyDataSetInvalidated();
- }
- };
-
- private boolean mIsListExpanded = true;
- private LinearLayout mContainerView;
- private ViewGroup mHeaderView;
- private ListView mListView;
- private ImageView mIndicatorView;
-
- private ChildAdapter(GroupAdapter parent, int groupPosition) {
- mParent = parent;
- mGroupPosition = groupPosition;
- mParent.registerDataSetObserver(mObserver);
- }
-
- @Override public int getCount() {
- return mParent.getChildrenCount(mGroupPosition);
- }
- @Override public CertHolder getItem(int position) {
- return mParent.getChild(mGroupPosition, position);
- }
- @Override public long getItemId(int position) {
- return mParent.getChildId(mGroupPosition, position);
- }
- @Override public View getView(int position, View convertView, ViewGroup parent) {
- return mParent.getChildView(mGroupPosition, position, false, convertView, parent);
- }
- // DataSet events
- @Override
- public void notifyDataSetChanged() {
- // Don't call super as the parent will propagate this event back later in mObserver
- mParent.notifyDataSetChanged();
- }
- @Override
- public void notifyDataSetInvalidated() {
- // Don't call super as the parent will propagate this event back later in mObserver
- mParent.notifyDataSetInvalidated();
- }
-
- // View related codes
- @Override
- public void onClick(View view) {
- mIsListExpanded = checkGroupExpandableAndStartWarningActivity() && !mIsListExpanded;
- refreshViews();
- }
-
- @Override
- public void onItemClick(AdapterView<?> adapterView, View view, int pos, long id) {
- showCertDialog(getItem(pos));
- }
-
- public void setContainerView(LinearLayout containerView) {
- mContainerView = containerView;
-
- mListView = (ListView) mContainerView.findViewById(R.id.cert_list);
- mListView.setAdapter(this);
- mListView.setOnItemClickListener(this);
- mListView.setItemsCanFocus(true);
-
- mHeaderView = (ViewGroup) mContainerView.findViewById(R.id.header_view);
- mHeaderView.setOnClickListener(this);
-
- mIndicatorView = (ImageView) mHeaderView.findViewById(R.id.group_indicator);
- mIndicatorView.setImageDrawable(getGroupIndicator());
-
- FrameLayout headerContentContainer = (FrameLayout)
- mHeaderView.findViewById(R.id.header_content_container);
- headerContentContainer.addView(
- mParent.getGroupView(mGroupPosition, true /* parent ignores it */, null,
- headerContentContainer));
- }
-
- public void showHeader(boolean showHeader) {
- mHeaderView.setVisibility(showHeader ? View.VISIBLE : View.GONE);
- }
-
- public void showDivider(boolean showDivider) {
- View dividerView = mHeaderView.findViewById(R.id.header_divider);
- dividerView.setVisibility(showDivider ? View.VISIBLE : View.GONE );
- }
-
- public void setExpandIfAvailable(boolean expanded) {
- mIsListExpanded = expanded && mParent.checkGroupExpandableAndStartWarningActivity(
- mGroupPosition, false /* startActivity */);
- refreshViews();
- }
-
- private boolean checkGroupExpandableAndStartWarningActivity() {
- return mParent.checkGroupExpandableAndStartWarningActivity(mGroupPosition);
- }
-
- private void refreshViews() {
- mIndicatorView.setImageState(mIsListExpanded ? GROUP_EXPANDED_STATE_SET
- : EMPTY_STATE_SET, false);
- mListView.setLayoutParams(mIsListExpanded ? SHOW_LAYOUT_PARAMS
- : HIDE_LIST_LAYOUT_PARAMS);
- mContainerView.setLayoutParams(mIsListExpanded ? SHOW_LAYOUT_PARAMS
- : HIDE_CONTAINER_LAYOUT_PARAMS);
- }
-
- // Get group indicator from styles of ExpandableListView
- private Drawable getGroupIndicator() {
- final TypedArray a = getActivity().obtainStyledAttributes(null,
- com.android.internal.R.styleable.ExpandableListView,
- com.android.internal.R.attr.expandableListViewStyle, 0);
- Drawable groupIndicator = a.getDrawable(
- com.android.internal.R.styleable.ExpandableListView_groupIndicator);
- a.recycle();
- return groupIndicator;
- }
- }
-
- private class AdapterData {
- private final SparseArray<List<CertHolder>> mCertHoldersByUserId =
- new SparseArray<List<CertHolder>>();
- private final Tab mTab;
- private final GroupAdapter mAdapter;
-
- private AdapterData(Tab tab, GroupAdapter adapter) {
- mAdapter = adapter;
- mTab = tab;
- }
-
- private class AliasLoader extends AsyncTask<Void, Integer, SparseArray<List<CertHolder>>> {
- private ProgressBar mProgressBar;
- private View mContentView;
- private Context mContext;
-
- public AliasLoader() {
- mContext = getActivity();
- mAliasLoaders.add(this);
- List<UserHandle> profiles = mUserManager.getUserProfiles();
- for (UserHandle profile : profiles) {
- mCertHoldersByUserId.put(profile.getIdentifier(), new ArrayList<CertHolder>());
- }
- }
-
- private boolean shouldSkipProfile(UserHandle userHandle) {
- return mUserManager.isQuietModeEnabled(userHandle)
- || !mUserManager.isUserUnlocked(userHandle.getIdentifier());
- }
-
- @Override protected void onPreExecute() {
- View content = mTabHost.getTabContentView();
- mProgressBar = (ProgressBar) content.findViewById(mTab.mProgress);
- mContentView = content.findViewById(mTab.mContentView);
- mProgressBar.setVisibility(View.VISIBLE);
- mContentView.setVisibility(View.GONE);
- }
- @Override protected SparseArray<List<CertHolder>> doInBackground(Void... params) {
- SparseArray<List<CertHolder>> certHoldersByProfile =
- new SparseArray<List<CertHolder>>();
- try {
- synchronized(mKeyChainConnectionByProfileId) {
- List<UserHandle> profiles = mUserManager.getUserProfiles();
- final int n = profiles.size();
- // First we get all aliases for all profiles in order to show progress
- // correctly. Otherwise this could all be in a single loop.
- SparseArray<List<String>> aliasesByProfileId = new SparseArray<
- List<String>>(n);
- int max = 0;
- int progress = 0;
- for (int i = 0; i < n; ++i) {
- UserHandle profile = profiles.get(i);
- int profileId = profile.getIdentifier();
- if (shouldSkipProfile(profile)) {
- continue;
- }
- KeyChainConnection keyChainConnection = KeyChain.bindAsUser(mContext,
- profile);
- // Saving the connection for later use on the certificate dialog.
- mKeyChainConnectionByProfileId.put(profileId, keyChainConnection);
- IKeyChainService service = keyChainConnection.getService();
- List<String> aliases = mTab.getAliases(service);
- if (isCancelled()) {
- return new SparseArray<List<CertHolder>>();
- }
- max += aliases.size();
- aliasesByProfileId.put(profileId, aliases);
- }
- for (int i = 0; i < n; ++i) {
- UserHandle profile = profiles.get(i);
- int profileId = profile.getIdentifier();
- List<String> aliases = aliasesByProfileId.get(profileId);
- if (isCancelled()) {
- return new SparseArray<List<CertHolder>>();
- }
- KeyChainConnection keyChainConnection = mKeyChainConnectionByProfileId.get(
- profileId);
- if (shouldSkipProfile(profile) || aliases == null
- || keyChainConnection == null) {
- certHoldersByProfile.put(profileId, new ArrayList<CertHolder>(0));
- continue;
- }
- IKeyChainService service = keyChainConnection.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);
- 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>>();
- }
- }
- @Override protected void onProgressUpdate(Integer... progressAndMax) {
- int progress = progressAndMax[0];
- int max = progressAndMax[1];
- if (max != mProgressBar.getMax()) {
- mProgressBar.setMax(max);
- }
- mProgressBar.setProgress(progress);
- }
- @Override protected void onPostExecute(SparseArray<List<CertHolder>> certHolders) {
- mCertHoldersByUserId.clear();
- final int n = certHolders.size();
- for (int i = 0; i < n; ++i) {
- mCertHoldersByUserId.put(certHolders.keyAt(i), certHolders.valueAt(i));
- }
- mAdapter.notifyDataSetChanged();
- mProgressBar.setVisibility(View.GONE);
- mContentView.setVisibility(View.VISIBLE);
- mProgressBar.setProgress(0);
- mAliasLoaders.remove(this);
- 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);
- }
- }
-
- public void remove(CertHolder certHolder) {
- if (mCertHoldersByUserId != null) {
- final List<CertHolder> certs = mCertHoldersByUserId.get(certHolder.mProfileId);
- if (certs != null) {
- certs.remove(certHolder);
- }
- }
- }
- }
-
- /* package */ static class CertHolder implements Comparable<CertHolder> {
- public int mProfileId;
- private final IKeyChainService mService;
- private final GroupAdapter mAdapter;
- private final Tab mTab;
- private final String mAlias;
- private final X509Certificate mX509Cert;
-
- private final SslCertificate mSslCert;
- private final String mSubjectPrimary;
- private final String mSubjectSecondary;
- private boolean mDeleted;
-
- private CertHolder(IKeyChainService service,
- GroupAdapter adapter,
- Tab tab,
- String alias,
- X509Certificate x509Cert,
- int profileId) {
- mProfileId = profileId;
- mService = service;
- mAdapter = adapter;
- mTab = tab;
- mAlias = alias;
- mX509Cert = x509Cert;
-
- mSslCert = new SslCertificate(x509Cert);
-
- String cn = mSslCert.getIssuedTo().getCName();
- String o = mSslCert.getIssuedTo().getOName();
- String ou = mSslCert.getIssuedTo().getUName();
- // if we have a O, use O as primary subject, secondary prefer CN over OU
- // if we don't have an O, use CN as primary, empty secondary
- // if we don't have O or CN, use DName as primary, empty secondary
- if (!o.isEmpty()) {
- if (!cn.isEmpty()) {
- mSubjectPrimary = o;
- mSubjectSecondary = cn;
- } else {
- mSubjectPrimary = o;
- mSubjectSecondary = ou;
- }
- } else {
- if (!cn.isEmpty()) {
- mSubjectPrimary = cn;
- mSubjectSecondary = "";
- } else {
- mSubjectPrimary = mSslCert.getIssuedTo().getDName();
- mSubjectSecondary = "";
- }
- }
- 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) {
- int primary = this.mSubjectPrimary.compareToIgnoreCase(o.mSubjectPrimary);
- if (primary != 0) {
- return primary;
- }
- return this.mSubjectSecondary.compareToIgnoreCase(o.mSubjectSecondary);
- }
- @Override public boolean equals(Object o) {
- if (!(o instanceof CertHolder)) {
- return false;
- }
- CertHolder other = (CertHolder) o;
- return mAlias.equals(other.mAlias);
- }
- @Override public int 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 boolean isTrustAllCaCertModeInProgress() {
- return mTrustAllCaUserId != UserHandle.USER_NULL;
- }
-
- private void showTrustAllCaDialog(List<CertHolder> unapprovedCertHolders) {
- 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;
- try {
- synchronized (mKeyChainConnectionByProfileId) {
- KeyChainConnection keyChainConnection = mKeyChainConnectionByProfileId.get(
- 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 certificates;
- }
-
- @Override
- public void removeOrInstallCert(CertHolder certHolder) {
- new AliasOperation(certHolder).execute();
- }
-
- @Override
- public boolean startConfirmCredentialIfNotConfirmed(int userId,
- IntConsumer onCredentialConfirmedListener) {
- if (mConfirmedCredentialUsers.contains(userId)) {
- // Credential has been confirmed. Don't start activity.
- return false;
- }
-
- boolean result = startConfirmCredential(userId);
- if (result) {
- mConfirmingCredentialListener = onCredentialConfirmedListener;
- }
- return result;
- }
-
- private class AliasOperation extends AsyncTask<Void, Void, Boolean> {
- private final CertHolder mCertHolder;
-
- private AliasOperation(CertHolder certHolder) {
- mCertHolder = certHolder;
- mAliasOperation = this;
- }
-
- @Override
- protected Boolean doInBackground(Void... params) {
- try {
- synchronized (mKeyChainConnectionByProfileId) {
- KeyChainConnection keyChainConnection = mKeyChainConnectionByProfileId.get(
- mCertHolder.mProfileId);
- IKeyChainService service = keyChainConnection.getService();
- if (mCertHolder.mDeleted) {
- byte[] bytes = mCertHolder.mX509Cert.getEncoded();
- service.installCaCertificate(bytes);
- return true;
- } else {
- return service.deleteCaCertificate(mCertHolder.mAlias);
- }
- }
- } catch (CertificateEncodingException | SecurityException | IllegalStateException
- | RemoteException e) {
- Log.w(TAG, "Error while toggling alias " + mCertHolder.mAlias, e);
- return false;
- }
- }
-
- @Override
- protected void onPostExecute(Boolean ok) {
- if (ok) {
- if (mCertHolder.mTab.mSwitch) {
- mCertHolder.mDeleted = !mCertHolder.mDeleted;
- } else {
- mCertHolder.mAdapter.remove(mCertHolder);
- }
- mCertHolder.mAdapter.notifyDataSetChanged();
- } else {
- // bail, reload to reset to known state
- mCertHolder.mAdapter.load();
- }
- mAliasOperation = null;
- }
- }
}
diff --git a/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetail.java b/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetail.java
index b397e18..34edf98 100644
--- a/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetail.java
+++ b/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetail.java
@@ -172,7 +172,7 @@
launchArgs.mPackageName = entry.getDefaultPackageName();
launchArgs.mAppLabel = entry.getLabel();
launchArgs.mUid = entry.getUid();
- launchArgs.mIconId = entry.iconId;
+ launchArgs.mIconId = entry.mIconId;
launchArgs.mConsumedPower = (int) entry.getConsumedPower();
launchArgs.mForegroundTimeMs = isValidToShowSummary ? entry.getTimeInForegroundMs() : 0;
launchArgs.mBackgroundTimeMs = isValidToShowSummary ? entry.getTimeInBackgroundMs() : 0;
diff --git a/src/com/android/settings/fuelgauge/BatteryAppListPreferenceController.java b/src/com/android/settings/fuelgauge/BatteryAppListPreferenceController.java
index 8dbce79..8fb0d1e 100644
--- a/src/com/android/settings/fuelgauge/BatteryAppListPreferenceController.java
+++ b/src/com/android/settings/fuelgauge/BatteryAppListPreferenceController.java
@@ -127,9 +127,9 @@
final int userId = UserHandle.getUserId(entry.getUid());
final UserHandle userHandle = new UserHandle(userId);
pgp.setIcon(mUserManager.getBadgedIconForUser(entry.getIcon(), userHandle));
- pgp.setTitle(entry.name);
+ pgp.setTitle(entry.mName);
if (entry.isAppEntry()) {
- pgp.setContentDescription(entry.name);
+ pgp.setContentDescription(entry.mName);
}
}
break;
@@ -249,7 +249,7 @@
contentDescription, entry);
pref.setKey(key);
}
- entry.percent = percentOfTotal;
+ entry.mPercent = percentOfTotal;
pref.setTitle(entry.getLabel());
pref.setOrder(i + 1);
pref.setPercent(percentOfTotal);
@@ -288,7 +288,7 @@
final BatteryEntry entry = usageList.get(i);
final double percentOfTotal = mBatteryUtils.calculateBatteryPercent(
entry.getConsumedPower(), totalPower, dischargePercentage);
- entry.percent = percentOfTotal;
+ entry.mPercent = percentOfTotal;
}
return usageList;
}
diff --git a/src/com/android/settings/fuelgauge/BatteryChartPreferenceController.java b/src/com/android/settings/fuelgauge/BatteryChartPreferenceController.java
index 249ee49..02248c9 100644
--- a/src/com/android/settings/fuelgauge/BatteryChartPreferenceController.java
+++ b/src/com/android/settings/fuelgauge/BatteryChartPreferenceController.java
@@ -508,7 +508,9 @@
mBatteryHistoryKeys[mTrapezoidIndex * 2], mIs24HourFormat);
final String toHour = ConvertUtils.utcToLocalTimeHour(mPrefContext,
mBatteryHistoryKeys[(mTrapezoidIndex + 1) * 2], mIs24HourFormat);
- return String.format("%s - %s", fromHour, toHour);
+ return mIs24HourFormat
+ ? String.format("%s–%s", fromHour, toHour)
+ : String.format("%s – %s", fromHour, toHour);
}
@VisibleForTesting
diff --git a/src/com/android/settings/fuelgauge/BatteryDiffEntry.java b/src/com/android/settings/fuelgauge/BatteryDiffEntry.java
index ca29cfe..5ef1110 100644
--- a/src/com/android/settings/fuelgauge/BatteryDiffEntry.java
+++ b/src/com/android/settings/fuelgauge/BatteryDiffEntry.java
@@ -171,9 +171,9 @@
// Checks whether we have cached data or not first before fetching.
final BatteryEntry.NameAndIcon nameAndIcon = getCache();
if (nameAndIcon != null) {
- mAppLabel = nameAndIcon.name;
- mAppIcon = nameAndIcon.icon;
- mAppIconId = nameAndIcon.iconId;
+ mAppLabel = nameAndIcon.mName;
+ mAppIcon = nameAndIcon.mIcon;
+ mAppIconId = nameAndIcon.mIconId;
}
final Boolean validForRestriction = sValidForRestriction.get(getKey());
if (validForRestriction != null) {
@@ -196,8 +196,8 @@
BatteryEntry.getNameAndIconFromUserId(
mContext, (int) mBatteryHistEntry.mUserId);
if (nameAndIconForUser != null) {
- mAppIcon = nameAndIconForUser.icon;
- mAppLabel = nameAndIconForUser.name;
+ mAppIcon = nameAndIconForUser.mIcon;
+ mAppLabel = nameAndIconForUser.mName;
sResourceCache.put(
getKey(),
new BatteryEntry.NameAndIcon(mAppLabel, mAppIcon, /*iconId=*/ 0));
@@ -208,10 +208,10 @@
BatteryEntry.getNameAndIconFromPowerComponent(
mContext, mBatteryHistEntry.mDrainType);
if (nameAndIconForSystem != null) {
- mAppLabel = nameAndIconForSystem.name;
- if (nameAndIconForSystem.iconId != 0) {
- mAppIconId = nameAndIconForSystem.iconId;
- mAppIcon = mContext.getDrawable(nameAndIconForSystem.iconId);
+ mAppLabel = nameAndIconForSystem.mName;
+ if (nameAndIconForSystem.mIconId != 0) {
+ mAppIconId = nameAndIconForSystem.mIconId;
+ mAppIcon = mContext.getDrawable(nameAndIconForSystem.mIconId);
}
sResourceCache.put(
getKey(),
@@ -308,8 +308,8 @@
if (packages == null || packages.length == 0) {
final BatteryEntry.NameAndIcon nameAndIcon =
BatteryEntry.getNameAndIconFromUid(mContext, mAppLabel, uid);
- mAppLabel = nameAndIcon.name;
- mAppIcon = nameAndIcon.icon;
+ mAppLabel = nameAndIcon.mName;
+ mAppIcon = nameAndIcon.mIcon;
}
final BatteryEntry.NameAndIcon nameAndIcon =
@@ -319,13 +319,13 @@
// Clears BatteryEntry internal cache since we will have another one.
BatteryEntry.clearUidCache();
if (nameAndIcon != null) {
- mAppLabel = nameAndIcon.name;
- mAppIcon = nameAndIcon.icon;
- mDefaultPackageName = nameAndIcon.packageName;
+ mAppLabel = nameAndIcon.mName;
+ mAppIcon = nameAndIcon.mIcon;
+ mDefaultPackageName = nameAndIcon.mPackageName;
if (mDefaultPackageName != null
- && !mDefaultPackageName.equals(nameAndIcon.packageName)) {
+ && !mDefaultPackageName.equals(nameAndIcon.mPackageName)) {
Log.w(TAG, String.format("found different package: %s | %s",
- mDefaultPackageName, nameAndIcon.packageName));
+ mDefaultPackageName, nameAndIcon.mPackageName));
}
}
}
diff --git a/src/com/android/settings/fuelgauge/BatteryEntry.java b/src/com/android/settings/fuelgauge/BatteryEntry.java
index 5c9d071..c9acc4c 100644
--- a/src/com/android/settings/fuelgauge/BatteryEntry.java
+++ b/src/com/android/settings/fuelgauge/BatteryEntry.java
@@ -53,10 +53,10 @@
public class BatteryEntry {
public static final class NameAndIcon {
- public final String name;
- public final String packageName;
- public final Drawable icon;
- public final int iconId;
+ public final String mName;
+ public final String mPackageName;
+ public final Drawable mIcon;
+ public final int mIconId;
public NameAndIcon(String name, Drawable icon, int iconId) {
this(name, /*packageName=*/ null, icon, iconId);
@@ -64,10 +64,10 @@
public NameAndIcon(
String name, String packageName, Drawable icon, int iconId) {
- this.name = name;
- this.icon = icon;
- this.iconId = iconId;
- this.packageName = packageName;
+ this.mName = name;
+ this.mIcon = icon;
+ this.mIconId = iconId;
+ this.mPackageName = packageName;
}
}
@@ -111,11 +111,11 @@
final NameAndIcon nameAndIcon =
BatteryEntry.loadNameAndIcon(
be.mContext, be.getUid(), sHandler, be,
- be.mDefaultPackageName, be.name, be.icon);
+ be.mDefaultPackageName, be.mName, be.mIcon);
if (nameAndIcon != null) {
- be.icon = nameAndIcon.icon;
- be.name = nameAndIcon.name;
- be.mDefaultPackageName = nameAndIcon.packageName;
+ be.mIcon = nameAndIcon.mIcon;
+ be.mName = nameAndIcon.mName;
+ be.mDefaultPackageName = nameAndIcon.mPackageName;
}
}
}
@@ -169,27 +169,27 @@
private long mTimeInForegroundMs;
private long mTimeInBackgroundMs;
- public String name;
- public Drawable icon;
- public int iconId; // For passing to the detail screen.
- public double percent;
+ public String mName;
+ public Drawable mIcon;
+ public int mIconId;
+ public double mPercent;
private String mDefaultPackageName;
private double mConsumedPower;
static class UidToDetail {
- String name;
- String packageName;
- Drawable icon;
+ String mName;
+ String mPackageName;
+ Drawable mIcon;
}
public BatteryEntry(Context context, Handler handler, UserManager um,
- @NonNull BatteryConsumer batteryConsumer, boolean isHidden, int uid, String[] packages,
+ BatteryConsumer batteryConsumer, boolean isHidden, int uid, String[] packages,
String packageName) {
this(context, handler, um, batteryConsumer, isHidden, uid, packages, packageName, true);
}
public BatteryEntry(Context context, Handler handler, UserManager um,
- @NonNull BatteryConsumer batteryConsumer, boolean isHidden, int uid, String[] packages,
+ BatteryConsumer batteryConsumer, boolean isHidden, int uid, String[] packages,
String packageName, boolean loadDataInBackground) {
sHandler = handler;
mContext = context;
@@ -217,11 +217,11 @@
try {
ApplicationInfo appInfo =
pm.getApplicationInfo(mDefaultPackageName, 0 /* no flags */);
- name = pm.getApplicationLabel(appInfo).toString();
+ mName = pm.getApplicationLabel(appInfo).toString();
} catch (NameNotFoundException e) {
Log.d(TAG, "PackageManager failed to retrieve ApplicationInfo for: "
+ mDefaultPackageName);
- name = mDefaultPackageName;
+ mName = mDefaultPackageName;
}
}
getQuickNameIconForUid(uid, packages, loadDataInBackground);
@@ -235,10 +235,10 @@
mConsumedPower = batteryConsumer.getConsumedPower();
final NameAndIcon nameAndIcon = getNameAndIconFromUserId(
context, ((UserBatteryConsumer) batteryConsumer).getUserId());
- icon = nameAndIcon.icon;
- name = nameAndIcon.name;
+ mIcon = nameAndIcon.mIcon;
+ mName = nameAndIcon.mName;
} else {
- throw new IllegalArgumentException("Unsupported battery consumer: " + batteryConsumer);
+ throw new IllegalArgumentException("Unsupported: " + batteryConsumer);
}
}
@@ -257,11 +257,12 @@
mUsageDurationMs = usageDurationMs;
mConsumerType = ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY;
- final NameAndIcon nameAndIcon = getNameAndIconFromPowerComponent(context, powerComponentId);
- iconId = nameAndIcon.iconId;
- name = nameAndIcon.name;
- if (iconId != 0) {
- icon = context.getDrawable(iconId);
+ final NameAndIcon nameAndIcon =
+ getNameAndIconFromPowerComponent(context, powerComponentId);
+ mIconId = nameAndIcon.mIconId;
+ mName = nameAndIcon.mName;
+ if (mIconId != 0) {
+ mIcon = context.getDrawable(mIconId);
}
}
@@ -274,9 +275,9 @@
mIsHidden = false;
mPowerComponentId = powerComponentId;
- iconId = R.drawable.ic_power_system;
- icon = context.getDrawable(iconId);
- name = powerComponentName;
+ mIconId = R.drawable.ic_power_system;
+ mIcon = context.getDrawable(mIconId);
+ mName = powerComponentName;
mConsumedPower =
powerComponentId == BatteryConsumer.POWER_COMPONENT_SCREEN
? devicePowerMah
@@ -285,14 +286,11 @@
}
public Drawable getIcon() {
- return icon;
+ return mIcon;
}
- /**
- * Gets the application name
- */
public String getLabel() {
- return name;
+ return mName;
}
@ConvertUtils.ConsumerType
@@ -317,18 +315,18 @@
final String uidString = Integer.toString(uid);
if (sUidCache.containsKey(uidString)) {
UidToDetail utd = sUidCache.get(uidString);
- mDefaultPackageName = utd.packageName;
- name = utd.name;
- icon = utd.icon;
+ mDefaultPackageName = utd.mPackageName;
+ mName = utd.mName;
+ mIcon = utd.mIcon;
return;
}
if (packages == null || packages.length == 0) {
- final NameAndIcon nameAndIcon = getNameAndIconFromUid(mContext, name, uid);
- icon = nameAndIcon.icon;
- name = nameAndIcon.name;
+ final NameAndIcon nameAndIcon = getNameAndIconFromUid(mContext, mName, uid);
+ mIcon = nameAndIcon.mIcon;
+ mName = nameAndIcon.mName;
} else {
- icon = mContext.getPackageManager().getDefaultActivityIcon();
+ mIcon = mContext.getPackageManager().getDefaultActivityIcon();
}
// Avoids post the loading icon and label in the background request.
@@ -339,9 +337,7 @@
}
}
- /**
- * Loads the app label and icon image and stores into the cache.
- */
+ /** Loads the app label and icon image and stores into the cache. */
public static NameAndIcon loadNameAndIcon(
Context context,
int uid,
@@ -400,7 +396,7 @@
// Look for an official name for this UID.
for (String pkgName : packages) {
try {
- final PackageInfo pi = ipm.getPackageInfo(pkgName, 0 /* no flags */, userId);
+ final PackageInfo pi = ipm.getPackageInfo(pkgName, 0, userId);
if (pi == null) {
Log.d(TAG, "Retrieving null package info for package "
+ pkgName + ", user " + userId);
@@ -432,9 +428,9 @@
}
UidToDetail utd = new UidToDetail();
- utd.name = name;
- utd.icon = icon;
- utd.packageName = defaultPackageName;
+ utd.mName = name;
+ utd.mIcon = icon;
+ utd.mPackageName = defaultPackageName;
sUidCache.put(uidString, utd);
if (handler != null) {
@@ -443,9 +439,7 @@
return new NameAndIcon(name, defaultPackageName, icon, /*iconId=*/ 0);
}
- /**
- * Returns a string that uniquely identifies this battery consumer.
- */
+ /** Returns a string that uniquely identifies this battery consumer. */
public String getKey() {
if (mBatteryConsumer instanceof UidBatteryConsumer) {
return Integer.toString(mUid);
@@ -456,23 +450,17 @@
}
}
- /**
- * Returns true if the entry is hidden from the battery usage summary list.
- */
+ /** Returns true if the entry is hidden from the battery usage summary list. */
public boolean isHidden() {
return mIsHidden;
}
- /**
- * Returns true if this entry describes an app (UID)
- */
+ /** Returns true if this entry describes an app (UID). */
public boolean isAppEntry() {
return mBatteryConsumer instanceof UidBatteryConsumer;
}
- /**
- * Returns true if this entry describes a User.
- */
+ /** Returns true if this entry describes a User. */
public boolean isUserEntry() {
if (mBatteryConsumer instanceof UserBatteryConsumer) {
return true;
@@ -495,9 +483,7 @@
return mUid;
}
- /**
- * Returns foreground foreground time (in milliseconds) that is attributed to this entry.
- */
+ /** Returns foreground foreground time/ms that is attributed to this entry. */
public long getTimeInForegroundMs() {
if (mBatteryConsumer instanceof UidBatteryConsumer) {
return mTimeInForegroundMs;
@@ -506,9 +492,7 @@
}
}
- /**
- * Returns background activity time (in milliseconds) that is attributed to this entry.
- */
+ /** Returns background activity time/ms that is attributed to this entry. */
public long getTimeInBackgroundMs() {
if (mBatteryConsumer instanceof UidBatteryConsumer) {
return mTimeInBackgroundMs;
@@ -542,9 +526,7 @@
}
}
- /**
- * Gets name and icon resource from UserBatteryConsumer userId.
- */
+ /** Gets name and icon resource from UserBatteryConsumer userId. */
public static NameAndIcon getNameAndIconFromUserId(
Context context, final int userId) {
UserManager um = context.getSystemService(UserManager.class);
@@ -562,9 +544,7 @@
return new NameAndIcon(name, icon, 0 /* iconId */);
}
- /**
- * Gets name and icon resource from UidBatteryConsumer uid.
- */
+ /** Gets name and icon resource from UidBatteryConsumer uid. */
public static NameAndIcon getNameAndIconFromUid(
Context context, String name, final int uid) {
Drawable icon = context.getDrawable(R.drawable.ic_power_system);
@@ -579,9 +559,7 @@
return new NameAndIcon(name, icon, 0 /* iconId */);
}
- /**
- * Gets name and icon resource from BatteryConsumer power component ID.
- */
+ /** Gets name and icon resource from BatteryConsumer power component ID. */
public static NameAndIcon getNameAndIconFromPowerComponent(
Context context, @BatteryConsumer.PowerComponent int powerComponentId) {
String name;
@@ -625,8 +603,9 @@
iconId = R.drawable.ic_settings_phone_idle;
break;
default:
- name = DebugUtils.constantToString(BatteryConsumer.class, "POWER_COMPONENT_",
- powerComponentId);
+ Log.w(TAG, "unknown attribute:" + DebugUtils.constantToString(
+ BatteryConsumer.class, "POWER_COMPONENT_", powerComponentId));
+ name = null;
iconId = R.drawable.ic_power_system;
break;
}
diff --git a/src/com/android/settings/fuelgauge/ConvertUtils.java b/src/com/android/settings/fuelgauge/ConvertUtils.java
index 946c910..696147b 100644
--- a/src/com/android/settings/fuelgauge/ConvertUtils.java
+++ b/src/com/android/settings/fuelgauge/ConvertUtils.java
@@ -101,7 +101,7 @@
values.put(BatteryHistEntry.KEY_CONSUME_POWER,
Double.valueOf(entry.getConsumedPower()));
values.put(BatteryHistEntry.KEY_PERCENT_OF_TOTAL,
- Double.valueOf(entry.percent));
+ Double.valueOf(entry.mPercent));
values.put(BatteryHistEntry.KEY_FOREGROUND_USAGE_TIME,
Long.valueOf(entry.getTimeInForegroundMs()));
values.put(BatteryHistEntry.KEY_BACKGROUND_USAGE_TIME,
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetailTest.java b/tests/robotests/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetailTest.java
index a10d323..aaa1487 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetailTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetailTest.java
@@ -181,7 +181,7 @@
when(mBatteryEntry.getLabel()).thenReturn(APP_LABEL);
when(mBatteryEntry.getTimeInBackgroundMs()).thenReturn(BACKGROUND_TIME_MS);
when(mBatteryEntry.getTimeInForegroundMs()).thenReturn(FOREGROUND_TIME_MS);
- mBatteryEntry.iconId = ICON_ID;
+ mBatteryEntry.mIconId = ICON_ID;
mFragment.mHeaderPreference = mHeaderPreference;
mFragment.mState = mState;
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryDiffEntryTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryDiffEntryTest.java
index 13ce29e..710d065 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryDiffEntryTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryDiffEntryTest.java
@@ -140,8 +140,8 @@
// Verifies the app label in the cache.
final BatteryEntry.NameAndIcon nameAndIcon =
BatteryDiffEntry.sResourceCache.get(entry.getKey());
- assertThat(nameAndIcon.name).isEqualTo(expectedName);
- assertThat(nameAndIcon.iconId).isEqualTo(R.drawable.ic_settings_aod);
+ assertThat(nameAndIcon.mName).isEqualTo(expectedName);
+ assertThat(nameAndIcon.mIconId).isEqualTo(R.drawable.ic_settings_aod);
// Verifies the restrictable flag in the cache.
assertThat(entry.mValidForRestriction).isTrue();
assertThat(BatteryDiffEntry.sValidForRestriction.get(entry.getKey())).isTrue();
@@ -166,8 +166,8 @@
// Verifies the app label in the cache.
final BatteryEntry.NameAndIcon nameAndIcon =
BatteryDiffEntry.sResourceCache.get(entry.getKey());
- assertThat(nameAndIcon.name).isEqualTo(expectedName);
- assertThat(nameAndIcon.iconId).isEqualTo(0);
+ assertThat(nameAndIcon.mName).isEqualTo(expectedName);
+ assertThat(nameAndIcon.mIconId).isEqualTo(0);
// Verifies the restrictable flag in the cache.
assertThat(entry.mValidForRestriction).isTrue();
assertThat(BatteryDiffEntry.sValidForRestriction.get(entry.getKey())).isTrue();
@@ -195,7 +195,7 @@
// Verifies the app label in the cache.
final BatteryEntry.NameAndIcon nameAndIcon =
BatteryDiffEntry.sResourceCache.get(entry.getKey());
- assertThat(nameAndIcon.name).isEqualTo(expectedAppLabel);
+ assertThat(nameAndIcon.mName).isEqualTo(expectedAppLabel);
// Verifies the restrictable flag in the cache.
assertThat(entry.mValidForRestriction).isFalse();
assertThat(BatteryDiffEntry.sValidForRestriction.get(entry.getKey())).isFalse();
@@ -215,7 +215,7 @@
// Verifies the app label in the cache.
final BatteryEntry.NameAndIcon nameAndIcon =
BatteryDiffEntry.sResourceCache.get(entry.getKey());
- assertThat(nameAndIcon.name).isEqualTo(expectedAppLabel);
+ assertThat(nameAndIcon.mName).isEqualTo(expectedAppLabel);
}
@Test
@@ -274,7 +274,7 @@
// Verifies the app label in the cache.
final BatteryEntry.NameAndIcon nameAndIcon =
BatteryDiffEntry.sResourceCache.get(entry.getKey());
- assertThat(nameAndIcon.icon).isEqualTo(mockDrawable);
+ assertThat(nameAndIcon.mIcon).isEqualTo(mockDrawable);
}
@Test
@@ -309,7 +309,7 @@
// Verifies the cache is updated into the new drawable.
final BatteryEntry.NameAndIcon nameAndIcon =
BatteryDiffEntry.sResourceCache.get(entry2.getKey());
- assertThat(nameAndIcon.icon).isEqualTo(mockDrawable2);
+ assertThat(nameAndIcon.mIcon).isEqualTo(mockDrawable2);
}
@Test
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryEntryTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryEntryTest.java
index c1b1761..966bc70 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryEntryTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryEntryTest.java
@@ -158,8 +158,8 @@
final BatteryEntry entry = new BatteryEntry(RuntimeEnvironment.application,
BatteryConsumer.POWER_COMPONENT_AMBIENT_DISPLAY, 200, 100, 1000);
- assertThat(entry.iconId).isEqualTo(R.drawable.ic_settings_aod);
- assertThat(entry.name).isEqualTo("Ambient display");
+ assertThat(entry.mIconId).isEqualTo(R.drawable.ic_settings_aod);
+ assertThat(entry.mName).isEqualTo("Ambient display");
}
@Test
@@ -167,8 +167,8 @@
final BatteryEntry entry = new BatteryEntry(RuntimeEnvironment.application,
BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID + 42, "ABC", 200, 100);
- assertThat(entry.iconId).isEqualTo(R.drawable.ic_power_system);
- assertThat(entry.name).isEqualTo("ABC");
+ assertThat(entry.mIconId).isEqualTo(R.drawable.ic_power_system);
+ assertThat(entry.mName).isEqualTo("ABC");
}
@Test
@@ -261,16 +261,16 @@
final NameAndIcon nameAndIcon = BatteryEntry.getNameAndIconFromUserId(
mContext, userId);
- assertThat(nameAndIcon.name).isEqualTo(getString(
+ assertThat(nameAndIcon.mName).isEqualTo(getString(
R.string.running_process_item_removed_user_label));
- assertThat(nameAndIcon.icon).isNull();
+ assertThat(nameAndIcon.mIcon).isNull();
}
@Test
public void getNameAndIconFromUid_rerturnExpectedName() {
final NameAndIcon nameAndIcon = BatteryEntry.getNameAndIconFromUid(
mContext, /* name */ null, /* uid */ 0);
- assertThat(nameAndIcon.name).isEqualTo(getString(R.string.process_kernel_label));
+ assertThat(nameAndIcon.mName).isEqualTo(getString(R.string.process_kernel_label));
assertNameAndIcon("mediaserver", R.string.process_mediaserver_label);
assertNameAndIcon("dex2oat32", R.string.process_dex2oat_label);
@@ -312,14 +312,14 @@
private void assertNameAndIcon(String name, int stringId) {
final NameAndIcon nameAndIcon = BatteryEntry.getNameAndIconFromUid(
mContext, name, /* uid */ 1000);
- assertThat(nameAndIcon.name).isEqualTo(getString(stringId));
+ assertThat(nameAndIcon.mName).isEqualTo(getString(stringId));
}
private void assertNameAndIcon(int powerComponentId, int stringId, int iconId) {
final NameAndIcon nameAndIcon = BatteryEntry.getNameAndIconFromPowerComponent(
mContext, powerComponentId);
- assertThat(nameAndIcon.name).isEqualTo(getString(stringId));
- assertThat(nameAndIcon.iconId).isEqualTo(iconId);
+ assertThat(nameAndIcon.mName).isEqualTo(getString(stringId));
+ assertThat(nameAndIcon.mIconId).isEqualTo(iconId);
}
private String getString(int stringId) {
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryHistEntryTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryHistEntryTest.java
index ca3109c..3acb8f3 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryHistEntryTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryHistEntryTest.java
@@ -57,7 +57,7 @@
when(mockBatteryEntry.isHidden()).thenReturn(true);
when(mBatteryUsageStats.getConsumedPower()).thenReturn(5.1);
when(mockBatteryEntry.getConsumedPower()).thenReturn(1.1);
- mockBatteryEntry.percent = 0.3;
+ mockBatteryEntry.mPercent = 0.3;
when(mockBatteryEntry.getTimeInForegroundMs()).thenReturn(1234L);
when(mockBatteryEntry.getTimeInBackgroundMs()).thenReturn(5689L);
when(mockBatteryEntry.getPowerComponentId()).thenReturn(expectedType);
@@ -76,7 +76,7 @@
assertBatteryHistEntry(
new BatteryHistEntry(values),
/*drainType=*/ expectedType,
- /*percentOfTotal=*/ mockBatteryEntry.percent);
+ /*percentOfTotal=*/ mockBatteryEntry.mPercent);
}
@Test
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/ConvertUtilsTest.java b/tests/robotests/src/com/android/settings/fuelgauge/ConvertUtilsTest.java
index ff0f25c..42483d0 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/ConvertUtilsTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/ConvertUtilsTest.java
@@ -77,7 +77,7 @@
when(mockBatteryEntry.isHidden()).thenReturn(true);
when(mBatteryUsageStats.getConsumedPower()).thenReturn(5.1);
when(mockBatteryEntry.getConsumedPower()).thenReturn(1.1);
- mockBatteryEntry.percent = 0.3;
+ mockBatteryEntry.mPercent = 0.3;
when(mockBatteryEntry.getTimeInForegroundMs()).thenReturn(1234L);
when(mockBatteryEntry.getTimeInBackgroundMs()).thenReturn(5689L);
when(mockBatteryEntry.getPowerComponentId()).thenReturn(expectedType);