From fc64a6c8add2b29726f3fa791aaa48a3e68985b9 Mon Sep 17 00:00:00 2001 From: Mill Chen Date: Fri, 13 Apr 2018 03:59:19 +0000 Subject: [PATCH] TrustAgentSettings use DashboardFragment - Remove dummy preference from trust_agent_setting.xml. - Build a controller to generate/manage a list of preferences. - Move some logics to the controller and add tests. Bug: 73899467 Test: make RunSettingsRoboTests -j ROBOTEST_FILTER=com.android.settings.security Test: make RunSettingsRoboTests -j ROBOTEST_FILTER=com.android.settings.core Test: make RunSettingsRoboTests -j ROBOTEST_FILTER=com.android.settings.search Test: atest SettingsGatewayTest UniquePreferenceTest Change-Id: Ideae0c1e7311d7647cf522e01592822e565a0ff7 --- res/xml/trust_agent_settings.xml | 11 +- .../security/trustagent/TrustAgentInfo.java | 57 +++++ .../trustagent/TrustAgentSettings.java | 187 ++------------ .../TrustAgentsPreferenceController.java | 193 +++++++++++++++ .../grandfather_not_implementing_indexable | 1 - ...rustAgentListPreferenceControllerTest.java | 25 +- .../TrustAgentsPreferenceControllerTest.java | 231 ++++++++++++++++++ .../shadow/ShadowDevicePolicyManager.java | 8 + .../shadow/ShadowLockPatternUtils.java | 8 + 9 files changed, 541 insertions(+), 180 deletions(-) create mode 100644 src/com/android/settings/security/trustagent/TrustAgentInfo.java create mode 100644 src/com/android/settings/security/trustagent/TrustAgentsPreferenceController.java create mode 100644 tests/robotests/src/com/android/settings/security/trustagent/TrustAgentsPreferenceControllerTest.java diff --git a/res/xml/trust_agent_settings.xml b/res/xml/trust_agent_settings.xml index 2bf71fb028c..c6539c4fde9 100644 --- a/res/xml/trust_agent_settings.xml +++ b/res/xml/trust_agent_settings.xml @@ -14,11 +14,10 @@ limitations under the License. --> - - - - + android:title="@string/manage_trust_agents" + settings:controller="com.android.settings.security.trustagent.TrustAgentsPreferenceController"> diff --git a/src/com/android/settings/security/trustagent/TrustAgentInfo.java b/src/com/android/settings/security/trustagent/TrustAgentInfo.java new file mode 100644 index 00000000000..f8198021273 --- /dev/null +++ b/src/com/android/settings/security/trustagent/TrustAgentInfo.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2018 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.security.trustagent; + +import android.content.ComponentName; +import android.graphics.drawable.Drawable; + +public class TrustAgentInfo implements Comparable { + private final CharSequence mLabel; + private final ComponentName mComponentName; + private final Drawable mIcon; + + public TrustAgentInfo(CharSequence label, ComponentName componentName, Drawable icon) { + mLabel = label; + mComponentName = componentName; + mIcon = icon; + } + + public CharSequence getLabel() { + return mLabel; + } + + public ComponentName getComponentName() { + return mComponentName; + } + + public Drawable getIcon() { + return mIcon; + } + + @Override + public boolean equals(Object other) { + if (other instanceof TrustAgentInfo) { + return mComponentName.equals(((TrustAgentInfo) other).getComponentName()); + } + return false; + } + + @Override + public int compareTo(TrustAgentInfo other) { + return mComponentName.compareTo(other.getComponentName()); + } +} \ No newline at end of file diff --git a/src/com/android/settings/security/trustagent/TrustAgentSettings.java b/src/com/android/settings/security/trustagent/TrustAgentSettings.java index 02d354a78fd..11d23418731 100644 --- a/src/com/android/settings/security/trustagent/TrustAgentSettings.java +++ b/src/com/android/settings/security/trustagent/TrustAgentSettings.java @@ -16,62 +16,22 @@ package com.android.settings.security.trustagent; -import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; - -import android.app.admin.DevicePolicyManager; -import android.content.ComponentName; import android.content.Context; -import android.content.Intent; -import android.content.pm.PackageManager; -import android.content.pm.ResolveInfo; -import android.graphics.drawable.Drawable; -import android.os.Bundle; -import android.os.UserHandle; -import android.service.trust.TrustAgentService; -import androidx.preference.SwitchPreference; -import androidx.preference.Preference; -import androidx.preference.PreferenceGroup; -import android.util.ArrayMap; -import android.util.ArraySet; +import android.provider.SearchIndexableResource; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; -import com.android.internal.widget.LockPatternUtils; import com.android.settings.R; -import com.android.settings.SettingsPreferenceFragment; -import com.android.settings.overlay.FeatureFactory; -import com.android.settingslib.RestrictedLockUtils; -import com.android.settingslib.RestrictedSwitchPreference; +import com.android.settings.dashboard.DashboardFragment; +import com.android.settings.search.BaseSearchIndexProvider; +import com.android.settings.search.Indexable; +import com.android.settingslib.search.SearchIndexable; +import java.util.ArrayList; import java.util.List; -public class TrustAgentSettings extends SettingsPreferenceFragment implements - Preference.OnPreferenceChangeListener { - private static final String SERVICE_INTERFACE = TrustAgentService.SERVICE_INTERFACE; - - private ArrayMap mAvailableAgents; - private final ArraySet mActiveAgents = new ArraySet(); - private LockPatternUtils mLockPatternUtils; - private DevicePolicyManager mDpm; - private TrustAgentManager mTrustAgentManager; - - public static final class AgentInfo { - CharSequence label; - ComponentName component; // service that implements ITrustAgent - SwitchPreference preference; - public Drawable icon; - - @Override - public boolean equals(Object other) { - if (other instanceof AgentInfo) { - return component.equals(((AgentInfo)other).component); - } - return true; - } - - public int compareTo(AgentInfo other) { - return component.compareTo(other.component); - } - } +@SearchIndexable +public class TrustAgentSettings extends DashboardFragment { + private static final String TAG = "TrustAgentSettings"; @Override public int getMetricsCategory() { @@ -84,122 +44,25 @@ public class TrustAgentSettings extends SettingsPreferenceFragment implements } @Override - public void onCreate(Bundle icicle) { - super.onCreate(icicle); - mDpm = getActivity().getSystemService(DevicePolicyManager.class); - mTrustAgentManager = - FeatureFactory.getFactory(getActivity()).getSecurityFeatureProvider() - .getTrustAgentManager(); - - addPreferencesFromResource(R.xml.trust_agent_settings); - } - - public void onResume() { - super.onResume(); - removePreference("dummy_preference"); - updateAgents(); - } - - private void updateAgents() { - final Context context = getActivity(); - if (mAvailableAgents == null) { - mAvailableAgents = findAvailableTrustAgents(); - } - if (mLockPatternUtils == null) { - mLockPatternUtils = new LockPatternUtils(getActivity()); - } - loadActiveAgents(); - PreferenceGroup category = - (PreferenceGroup) getPreferenceScreen().findPreference("trust_agents"); - category.removeAll(); - - final EnforcedAdmin admin = RestrictedLockUtils.checkIfKeyguardFeaturesDisabled(context, - DevicePolicyManager.KEYGUARD_DISABLE_TRUST_AGENTS, UserHandle.myUserId()); - - final int count = mAvailableAgents.size(); - for (int i = 0; i < count; i++) { - AgentInfo agent = mAvailableAgents.valueAt(i); - final RestrictedSwitchPreference preference = - new RestrictedSwitchPreference(getPrefContext()); - preference.useAdminDisabledSummary(true); - agent.preference = preference; - preference.setPersistent(false); - preference.setTitle(agent.label); - preference.setIcon(agent.icon); - preference.setPersistent(false); - preference.setOnPreferenceChangeListener(this); - preference.setChecked(mActiveAgents.contains(agent.component)); - - if (admin != null - && mDpm.getTrustAgentConfiguration(null, agent.component) == null) { - preference.setChecked(false); - preference.setDisabledByAdmin(admin); - } - - category.addPreference(agent.preference); - } - } - - private void loadActiveAgents() { - List activeTrustAgents = mLockPatternUtils.getEnabledTrustAgents( - UserHandle.myUserId()); - if (activeTrustAgents != null) { - mActiveAgents.addAll(activeTrustAgents); - } - } - - private void saveActiveAgents() { - mLockPatternUtils.setEnabledTrustAgents(mActiveAgents, - UserHandle.myUserId()); - } - - private ArrayMap findAvailableTrustAgents() { - PackageManager pm = getActivity().getPackageManager(); - Intent trustAgentIntent = new Intent(SERVICE_INTERFACE); - List resolveInfos = pm.queryIntentServices(trustAgentIntent, - PackageManager.GET_META_DATA); - - ArrayMap agents = new ArrayMap(); - final int count = resolveInfos.size(); - agents.ensureCapacity(count); - for (int i = 0; i < count; i++ ) { - ResolveInfo resolveInfo = resolveInfos.get(i); - if (resolveInfo.serviceInfo == null) { - continue; - } - if (!mTrustAgentManager.shouldProvideTrust(resolveInfo, pm)) { - continue; - } - ComponentName name = mTrustAgentManager.getComponentName(resolveInfo); - AgentInfo agentInfo = new AgentInfo(); - agentInfo.label = resolveInfo.loadLabel(pm); - agentInfo.icon = resolveInfo.loadIcon(pm); - agentInfo.component = name; - agents.put(name, agentInfo); - } - return agents; + protected String getLogTag() { + return TAG; } @Override - public boolean onPreferenceChange(Preference preference, Object newValue) { - if (preference instanceof SwitchPreference) { - final int count = mAvailableAgents.size(); - for (int i = 0; i < count; i++) { - AgentInfo agent = mAvailableAgents.valueAt(i); - if (agent.preference == preference) { - if ((Boolean) newValue) { - if (!mActiveAgents.contains(agent.component)) { - mActiveAgents.add(agent.component); - } - } else { - mActiveAgents.remove(agent.component); - } - saveActiveAgents(); - return true; - } - } - } - return false; + protected int getPreferenceScreenResId() { + return R.xml.trust_agent_settings; } + public static final Indexable.SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = + new BaseSearchIndexProvider() { + @Override + public List getXmlResourcesToIndex( + Context context, boolean enabled) { + final List result = new ArrayList<>(); + final SearchIndexableResource sir = new SearchIndexableResource(context); + sir.xmlResId = R.xml.trust_agent_settings; + result.add(sir); + return result; + } + }; } diff --git a/src/com/android/settings/security/trustagent/TrustAgentsPreferenceController.java b/src/com/android/settings/security/trustagent/TrustAgentsPreferenceController.java new file mode 100644 index 00000000000..604583b33e7 --- /dev/null +++ b/src/com/android/settings/security/trustagent/TrustAgentsPreferenceController.java @@ -0,0 +1,193 @@ +/* + * Copyright (C) 2018 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.security.trustagent; + +import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; + +import android.app.admin.DevicePolicyManager; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.graphics.drawable.Drawable; +import android.os.UserHandle; +import android.service.trust.TrustAgentService; +import android.text.TextUtils; +import android.util.ArrayMap; +import android.util.ArraySet; +import android.util.IconDrawableFactory; + +import com.android.internal.widget.LockPatternUtils; +import com.android.settings.core.BasePreferenceController; +import com.android.settings.overlay.FeatureFactory; +import com.android.settings.security.SecurityFeatureProvider; +import com.android.settingslib.RestrictedLockUtils; +import com.android.settingslib.RestrictedSwitchPreference; +import com.android.settingslib.core.lifecycle.LifecycleObserver; +import com.android.settingslib.core.lifecycle.events.OnStart; + +import java.util.List; + +import androidx.preference.Preference; +import androidx.preference.PreferenceScreen; +import androidx.preference.SwitchPreference; + +public class TrustAgentsPreferenceController extends BasePreferenceController + implements Preference.OnPreferenceChangeListener, LifecycleObserver, OnStart { + + private static final Intent TRUST_AGENT_INTENT = + new Intent(TrustAgentService.SERVICE_INTERFACE); + + private final ArrayMap mAvailableAgents; + private final ArraySet mActiveAgents; + private final DevicePolicyManager mDevicePolicyManager; + private final IconDrawableFactory mIconDrawableFactory; + private final LockPatternUtils mLockPatternUtils; + private final PackageManager mPackageManager; + private final TrustAgentManager mTrustAgentManager; + + private PreferenceScreen mScreen; + + public TrustAgentsPreferenceController(Context context, String key) { + super(context, key); + mAvailableAgents = new ArrayMap<>(); + mActiveAgents = new ArraySet<>(); + mDevicePolicyManager = context.getSystemService(DevicePolicyManager.class); + mIconDrawableFactory = IconDrawableFactory.newInstance(context); + final SecurityFeatureProvider securityFeatureProvider = + FeatureFactory.getFactory(context).getSecurityFeatureProvider(); + mTrustAgentManager = securityFeatureProvider.getTrustAgentManager(); + mLockPatternUtils = securityFeatureProvider.getLockPatternUtils(context); + mPackageManager = context.getPackageManager(); + } + + @Override + public void displayPreference(PreferenceScreen screen) { + super.displayPreference(screen); + mScreen = screen; + } + + @Override + public int getAvailabilityStatus() { + return AVAILABLE; + } + + @Override + public void onStart() { + updateAgents(); + } + + private void updateAgents() { + findAvailableTrustAgents(); + loadActiveAgents(); + removeUselessExistingPreferences(); + + final EnforcedAdmin admin = RestrictedLockUtils.checkIfKeyguardFeaturesDisabled(mContext, + DevicePolicyManager.KEYGUARD_DISABLE_TRUST_AGENTS, UserHandle.myUserId()); + + for (TrustAgentInfo agent : mAvailableAgents.values()) { + final ComponentName componentName = agent.getComponentName(); + RestrictedSwitchPreference preference = (RestrictedSwitchPreference) + mScreen.findPreference(componentName.flattenToString()); + if (preference == null) { + preference = new RestrictedSwitchPreference(mScreen.getContext()); + } + preference.setKey(componentName.flattenToString()); + preference.useAdminDisabledSummary(true); + preference.setTitle(agent.getLabel()); + preference.setIcon(agent.getIcon()); + preference.setOnPreferenceChangeListener(this); + preference.setChecked(mActiveAgents.contains(componentName)); + if (admin != null && mDevicePolicyManager.getTrustAgentConfiguration(null /* admin */, + componentName) == null) { + preference.setChecked(false); + preference.setDisabledByAdmin(admin); + } + mScreen.addPreference(preference); + } + } + + private void loadActiveAgents() { + final List activeTrustAgents = mLockPatternUtils.getEnabledTrustAgents( + UserHandle.myUserId()); + if (activeTrustAgents != null) { + mActiveAgents.addAll(activeTrustAgents); + } + } + + private void saveActiveAgents() { + mLockPatternUtils.setEnabledTrustAgents(mActiveAgents, UserHandle.myUserId()); + } + + private void findAvailableTrustAgents() { + final List resolveInfos = mPackageManager.queryIntentServices( + TRUST_AGENT_INTENT, PackageManager.GET_META_DATA); + mAvailableAgents.clear(); + for (ResolveInfo resolveInfo : resolveInfos) { + if (resolveInfo.serviceInfo == null) { + continue; + } + if (!mTrustAgentManager.shouldProvideTrust(resolveInfo, mPackageManager)) { + continue; + } + final CharSequence label = resolveInfo.loadLabel(mPackageManager); + final ComponentName componentName = mTrustAgentManager.getComponentName(resolveInfo); + final Drawable icon = mIconDrawableFactory.getBadgedIcon( + resolveInfo.getComponentInfo().applicationInfo); + final TrustAgentInfo agentInfo = new TrustAgentInfo(label, componentName, icon); + mAvailableAgents.put(componentName, agentInfo); + } + } + + private void removeUselessExistingPreferences() { + final int count = mScreen.getPreferenceCount(); + if (count <= 0) { + return; + } + for (int i = count - 1; i >= 0; i--) { + final Preference pref = mScreen.getPreference(i); + final String[] names = TextUtils.split(pref.getKey(), "/"); + final ComponentName componentName = new ComponentName(names[0], names[1]); + if (!mAvailableAgents.containsKey(componentName)) { + mScreen.removePreference(pref); + mActiveAgents.remove(componentName); + } + } + } + + @Override + public boolean onPreferenceChange(Preference preference, Object newValue) { + if (!(preference instanceof SwitchPreference)) { + return false; + } + for (TrustAgentInfo agent : mAvailableAgents.values()) { + final ComponentName componentName = agent.getComponentName(); + if (!TextUtils.equals(preference.getKey(), componentName.flattenToString())) { + continue; + } + if ((Boolean) newValue && !mActiveAgents.contains(componentName)) { + mActiveAgents.add(componentName); + } else { + mActiveAgents.remove(componentName); + } + saveActiveAgents(); + return true; + } + return false; + } +} diff --git a/tests/robotests/assets/grandfather_not_implementing_indexable b/tests/robotests/assets/grandfather_not_implementing_indexable index 9e8952e92de..8523b2f1ab9 100644 --- a/tests/robotests/assets/grandfather_not_implementing_indexable +++ b/tests/robotests/assets/grandfather_not_implementing_indexable @@ -57,7 +57,6 @@ com.android.settings.network.ApnSettings com.android.settings.wifi.calling.WifiCallingSettingsForSub com.android.settings.password.SetupChooseLockGeneric$SetupChooseLockGenericFragment com.android.settings.SetupRedactionInterstitial$SetupRedactionInterstitialFragment -com.android.settings.security.trustagent.TrustAgentSettings com.android.settings.password.ChooseLockGeneric$ChooseLockGenericFragment com.android.settings.IccLockSettings com.android.settings.TetherSettings diff --git a/tests/robotests/src/com/android/settings/security/trustagent/TrustAgentListPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/security/trustagent/TrustAgentListPreferenceControllerTest.java index 94298be696d..6be834b8871 100644 --- a/tests/robotests/src/com/android/settings/security/trustagent/TrustAgentListPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/security/trustagent/TrustAgentListPreferenceControllerTest.java @@ -16,8 +16,10 @@ package com.android.settings.security.trustagent; -import static com.android.settings.security.trustagent.TrustAgentListPreferenceController.PREF_KEY_SECURITY_CATEGORY; -import static com.android.settings.security.trustagent.TrustAgentListPreferenceController.PREF_KEY_TRUST_AGENT; +import static com.android.settings.security.trustagent.TrustAgentListPreferenceController + .PREF_KEY_SECURITY_CATEGORY; +import static com.android.settings.security.trustagent.TrustAgentListPreferenceController + .PREF_KEY_TRUST_AGENT; import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.atLeastOnce; @@ -27,12 +29,8 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.app.Activity; -import androidx.lifecycle.LifecycleOwner; import android.content.ComponentName; import android.content.Context; -import androidx.preference.Preference; -import androidx.preference.PreferenceCategory; -import androidx.preference.PreferenceScreen; import com.android.internal.widget.LockPatternUtils; import com.android.settings.core.PreferenceControllerMixin; @@ -52,6 +50,11 @@ import org.robolectric.annotation.Config; import java.util.ArrayList; import java.util.List; +import androidx.lifecycle.LifecycleOwner; +import androidx.preference.Preference; +import androidx.preference.PreferenceCategory; +import androidx.preference.PreferenceScreen; + @RunWith(SettingsRobolectricTestRunner.class) public class TrustAgentListPreferenceControllerTest { @@ -81,9 +84,9 @@ public class TrustAgentListPreferenceControllerTest { mLifecycle = new Lifecycle(mLifecycleOwner); mFeatureFactory = FakeFeatureFactory.setupForTest(); when(mFeatureFactory.securityFeatureProvider.getLockPatternUtils(any(Context.class))) - .thenReturn(mLockPatternUtils); + .thenReturn(mLockPatternUtils); when(mFeatureFactory.securityFeatureProvider.getTrustAgentManager()) - .thenReturn(mTrustAgentManager); + .thenReturn(mTrustAgentManager); when(mCategory.getKey()).thenReturn(PREF_KEY_SECURITY_CATEGORY); when(mCategory.getContext()).thenReturn(mActivity); when(mScreen.findPreference(PREF_KEY_SECURITY_CATEGORY)).thenReturn(mCategory); @@ -121,14 +124,14 @@ public class TrustAgentListPreferenceControllerTest { public void onResume_shouldAddNewAgents() { final List agents = new ArrayList<>(); final TrustAgentManager.TrustAgentComponentInfo agent = - mock(TrustAgentManager.TrustAgentComponentInfo.class); + mock(TrustAgentManager.TrustAgentComponentInfo.class); agent.title = "Test_title"; agent.summary = "test summary"; agent.componentName = new ComponentName("pkg", "agent"); agent.admin = null; agents.add(agent); when(mTrustAgentManager.getActiveTrustAgents(mActivity, mLockPatternUtils)) - .thenReturn(agents); + .thenReturn(agents); mController.displayPreference(mScreen); mController.onResume(); @@ -141,7 +144,7 @@ public class TrustAgentListPreferenceControllerTest { public void onResume_ifNotAvailable_shouldNotAddNewAgents() { final List agents = new ArrayList<>(); final TrustAgentManager.TrustAgentComponentInfo agent = - mock(TrustAgentManager.TrustAgentComponentInfo.class); + mock(TrustAgentManager.TrustAgentComponentInfo.class); agent.title = "Test_title"; agent.summary = "test summary"; agent.componentName = new ComponentName("pkg", "agent"); diff --git a/tests/robotests/src/com/android/settings/security/trustagent/TrustAgentsPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/security/trustagent/TrustAgentsPreferenceControllerTest.java new file mode 100644 index 00000000000..43a80018cc5 --- /dev/null +++ b/tests/robotests/src/com/android/settings/security/trustagent/TrustAgentsPreferenceControllerTest.java @@ -0,0 +1,231 @@ +/* + * Copyright (C) 2018 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.security.trustagent; + +import static com.google.common.truth.Truth.assertThat; + +import android.app.admin.DevicePolicyManager; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.content.pm.ServiceInfo; +import android.service.trust.TrustAgentService; + +import com.android.settings.core.BasePreferenceController; +import com.android.settings.testutils.SettingsRobolectricTestRunner; +import com.android.settings.testutils.shadow.ShadowDevicePolicyManager; +import com.android.settings.testutils.shadow.ShadowLockPatternUtils; +import com.android.settings.testutils.shadow.ShadowRestrictedLockUtils; +import com.android.settingslib.RestrictedSwitchPreference; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.Shadows; +import org.robolectric.annotation.Config; +import org.robolectric.annotation.Implementation; +import org.robolectric.annotation.Implements; +import org.robolectric.shadows.ShadowApplicationPackageManager; + +import java.util.ArrayList; +import java.util.List; + +import androidx.preference.PreferenceManager; +import androidx.preference.PreferenceScreen; + +@RunWith(SettingsRobolectricTestRunner.class) +@Config(shadows = { + ShadowLockPatternUtils.class, + ShadowRestrictedLockUtils.class, + ShadowDevicePolicyManager.class, + ShadowApplicationPackageManager.class, + TrustAgentsPreferenceControllerTest.ShadowTrustAgentManager.class +}) +public class TrustAgentsPreferenceControllerTest { + + private static final Intent TEST_INTENT = + new Intent(TrustAgentService.SERVICE_INTERFACE); + + private Context mContext; + private ShadowApplicationPackageManager mPackageManager; + private TrustAgentsPreferenceController mController; + private PreferenceManager mPreferenceManager; + private PreferenceScreen mPreferenceScreen; + + @Before + public void setUp() { + mContext = RuntimeEnvironment.application; + mPackageManager = (ShadowApplicationPackageManager) Shadows.shadowOf( + mContext.getPackageManager()); + mController = new TrustAgentsPreferenceController(mContext, "pref_key"); + mPreferenceManager = new PreferenceManager(mContext); + mPreferenceScreen = mPreferenceManager.createPreferenceScreen(mContext); + mPreferenceScreen.setKey("pref_key"); + } + + @After + public void tearDown() { + ShadowTrustAgentManager.clearPermissionGrantedList(); + } + + @Test + public void getAvailabilityStatus_byDefault_shouldBeShown() { + assertThat(mController.getAvailabilityStatus()) + .isEqualTo(BasePreferenceController.AVAILABLE); + } + + @Test + public void onStart_noTrustAgent_shouldNotAddPreference() { + final List availableAgents = createFakeAvailableAgents(); + mPackageManager.addResolveInfoForIntent(TEST_INTENT, availableAgents); + + mController.displayPreference(mPreferenceScreen); + mController.onStart(); + + assertThat(mPreferenceScreen.getPreferenceCount()).isEqualTo(0); + } + + @Test + public void + onStart_hasAUninstalledTrustAgent_shouldRemoveOnePreferenceAndLeaveTwoPreferences() { + final List availableAgents = createFakeAvailableAgents(); + final ResolveInfo uninstalledTrustAgent = availableAgents.get(0); + for (ResolveInfo rInfo : availableAgents) { + ShadowTrustAgentManager.grantPermissionToResolveInfo(rInfo); + } + mPackageManager.addResolveInfoForIntent(TEST_INTENT, availableAgents); + mController.displayPreference(mPreferenceScreen); + mController.onStart(); + availableAgents.remove(uninstalledTrustAgent); + + mPackageManager.addResolveInfoForIntent(TEST_INTENT, availableAgents); + mController.onStart(); + + assertThat(mPreferenceScreen.getPreferenceCount()).isEqualTo(2); + } + + @Test + public void onStart_hasANewTrustAgent_shouldAddOnePreferenceAndHaveFourPreferences() { + final List availableAgents = createFakeAvailableAgents(); + final ComponentName newComponentName = new ComponentName("test.data.packageD", "clzDDD"); + final ResolveInfo newTrustAgent = createFakeResolveInfo(newComponentName); + for (ResolveInfo rInfo : availableAgents) { + ShadowTrustAgentManager.grantPermissionToResolveInfo(rInfo); + } + mPackageManager.addResolveInfoForIntent(TEST_INTENT, availableAgents); + mController.displayPreference(mPreferenceScreen); + mController.onStart(); + availableAgents.add(newTrustAgent); + ShadowTrustAgentManager.grantPermissionToResolveInfo(newTrustAgent); + + mPackageManager.addResolveInfoForIntent(TEST_INTENT, availableAgents); + mController.onStart(); + + assertThat(mPreferenceScreen.getPreferenceCount()).isEqualTo(4); + } + + @Test + public void onStart_hasUnrestrictedTrustAgent_shouldAddThreeChangeablePreferences() { + ShadowRestrictedLockUtils.setKeyguardDisabledFeatures(0); + final List availableAgents = createFakeAvailableAgents(); + for (ResolveInfo rInfo : availableAgents) { + ShadowTrustAgentManager.grantPermissionToResolveInfo(rInfo); + } + mPackageManager.addResolveInfoForIntent(TEST_INTENT, availableAgents); + + mController.displayPreference(mPreferenceScreen); + mController.onStart(); + + assertThat(mPreferenceScreen.getPreferenceCount()).isEqualTo(3); + for (int i = 0; i < mPreferenceScreen.getPreferenceCount(); i++) { + RestrictedSwitchPreference preference = + (RestrictedSwitchPreference) mPreferenceScreen.getPreference(i); + assertThat(preference.isDisabledByAdmin()).isFalse(); + } + } + + @Test + public void onStart_hasRestrictedTructAgent_shouldAddThreeUnchangeablePreferences() { + final List availableAgents = createFakeAvailableAgents(); + for (ResolveInfo rInfo : availableAgents) { + ShadowTrustAgentManager.grantPermissionToResolveInfo(rInfo); + } + mPackageManager.addResolveInfoForIntent(TEST_INTENT, availableAgents); + ShadowRestrictedLockUtils.setKeyguardDisabledFeatures( + DevicePolicyManager.KEYGUARD_DISABLE_TRUST_AGENTS); + + mController.displayPreference(mPreferenceScreen); + mController.onStart(); + + assertThat(mPreferenceScreen.getPreferenceCount()).isEqualTo(3); + for (int i = 0; i < mPreferenceScreen.getPreferenceCount(); i++) { + RestrictedSwitchPreference preference = + (RestrictedSwitchPreference) mPreferenceScreen.getPreference(i); + assertThat(preference.isDisabledByAdmin()).isTrue(); + } + } + + private List createFakeAvailableAgents() { + final List componentNames = new ArrayList<>(); + componentNames.add(new ComponentName("test.data.packageA", "clzAAA")); + componentNames.add(new ComponentName("test.data.packageB", "clzBBB")); + componentNames.add(new ComponentName("test.data.packageC", "clzCCC")); + final List result = new ArrayList<>(); + for (ComponentName cn : componentNames) { + final ResolveInfo ri = createFakeResolveInfo(cn); + result.add(ri); + } + return result; + } + + private ResolveInfo createFakeResolveInfo(ComponentName cn) { + final ResolveInfo ri = new ResolveInfo(); + ri.serviceInfo = new ServiceInfo(); + ri.serviceInfo.packageName = cn.getPackageName(); + ri.serviceInfo.name = cn.getClassName(); + ri.serviceInfo.applicationInfo = new ApplicationInfo(); + ri.serviceInfo.applicationInfo.packageName = cn.getPackageName(); + ri.serviceInfo.applicationInfo.name = cn.getClassName(); + return ri; + } + + @Implements(TrustAgentManager.class) + public static class ShadowTrustAgentManager { + private final static List sPermissionGrantedList = new ArrayList<>(); + + @Implementation + public boolean shouldProvideTrust(ResolveInfo resolveInfo, PackageManager pm) { + if (sPermissionGrantedList.contains(resolveInfo)) { + return true; + } + return false; + } + + public static void grantPermissionToResolveInfo(ResolveInfo rInfo) { + sPermissionGrantedList.add(rInfo); + } + + public static void clearPermissionGrantedList() { + sPermissionGrantedList.clear(); + } + } +} diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowDevicePolicyManager.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowDevicePolicyManager.java index 16ef69981fc..b4e64924628 100644 --- a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowDevicePolicyManager.java +++ b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowDevicePolicyManager.java @@ -5,6 +5,7 @@ import android.annotation.Nullable; import android.annotation.UserIdInt; import android.app.admin.DevicePolicyManager; import android.content.ComponentName; +import android.os.PersistableBundle; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Implementation; @@ -12,6 +13,7 @@ import org.robolectric.annotation.Implements; import org.robolectric.shadow.api.Shadow; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Objects; @@ -75,4 +77,10 @@ public class ShadowDevicePolicyManager extends org.robolectric.shadows.ShadowDev return (ShadowDevicePolicyManager) Shadow.extract( RuntimeEnvironment.application.getSystemService(DevicePolicyManager.class)); } + + public @Nullable + List getTrustAgentConfiguration( + @Nullable ComponentName admin, @NonNull ComponentName agent) { + return null; + } } diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowLockPatternUtils.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowLockPatternUtils.java index e7f6be5f743..86276689b57 100644 --- a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowLockPatternUtils.java +++ b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowLockPatternUtils.java @@ -17,12 +17,15 @@ package com.android.settings.testutils.shadow; import android.app.admin.DevicePolicyManager; +import android.content.ComponentName; import com.android.internal.widget.LockPatternUtils; import org.robolectric.annotation.Implementation; import org.robolectric.annotation.Implements; +import java.util.List; + @Implements(LockPatternUtils.class) public class ShadowLockPatternUtils { @@ -49,6 +52,11 @@ public class ShadowLockPatternUtils { return sDeviceEncryptionEnabled; } + @Implementation + public List getEnabledTrustAgents(int userId) { + return null; + } + public static void setDeviceEncryptionEnabled(boolean deviceEncryptionEnabled) { sDeviceEncryptionEnabled = deviceEncryptionEnabled; }