Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9a38ed45 authored by Fan Zhang's avatar Fan Zhang
Browse files

Convert trust agent pref list logic to PreferenceController

Bug: 32953042
Test: robotests
Change-Id: I1420e90d4910a11fc5837ef2e150c822635b74a5
parent e9394d82
Loading
Loading
Loading
Loading
+16 −0
Original line number Diff line number Diff line
@@ -28,6 +28,22 @@
        android:title="@string/security_status_title" />

    <!-- TODO Need security section -->
    <PreferenceCategory
        android:key="security_category"
        android:title="@string/lock_settings_title">

        <!-- security_settings_chooser -->
        <com.android.settings.widget.GearPreference
            android:key="unlock_set_or_change"
            android:title="@string/unlock_set_unlock_launch_picker_title"
            android:summary="@string/unlock_set_unlock_mode_none"
            settings:keywords="@string/keywords_lockscreen" />

        <Preference android:key="lockscreen_preferences"
                    android:title="@string/lockscreen_settings_title"
                    android:fragment="com.android.settings.security.LockscreenDashboardFragment"/>

    </PreferenceCategory>

    <!-- security_settings_misc.xml -->
    <PreferenceCategory
+12 −83
Original line number Diff line number Diff line
@@ -41,7 +41,7 @@ import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settings.search.SearchIndexableRaw;
import com.android.settings.security.screenlock.ScreenLockSettings;
import com.android.settings.security.trustagent.ManageTrustAgentsPreferenceController;
import com.android.settings.security.trustagent.TrustAgentManager;
import com.android.settings.security.trustagent.TrustAgentListPreferenceController;
import com.android.settings.widget.GearPreference;
import com.android.settingslib.RestrictedLockUtils;
import com.android.settingslib.RestrictedPreference;
@@ -58,8 +58,6 @@ public class SecuritySettingsV2 extends DashboardFragment

    private static final String TAG = "SecuritySettingsV2";

    private static final String TRUST_AGENT_CLICK_INTENT = "trust_agent_click_intent";

    // Lock Settings
    private static final String KEY_UNLOCK_SET_OR_CHANGE = "unlock_set_or_change";
    private static final String KEY_UNLOCK_SET_OR_CHANGE_PROFILE = "unlock_set_or_change_profile";
@@ -73,16 +71,13 @@ public class SecuritySettingsV2 extends DashboardFragment
    private static final String KEY_LOCATION = "location";

    private static final int SET_OR_CHANGE_LOCK_METHOD_REQUEST = 123;
    private static final int CHANGE_TRUST_AGENT_SETTINGS = 126;
    public static final int CHANGE_TRUST_AGENT_SETTINGS = 126;
    private static final int SET_OR_CHANGE_LOCK_METHOD_REQUEST_PROFILE = 127;
    private static final int UNIFY_LOCK_CONFIRM_DEVICE_REQUEST = 128;
    private static final int UNIFY_LOCK_CONFIRM_PROFILE_REQUEST = 129;
    private static final int UNUNIFY_LOCK_CONFIRM_DEVICE_REQUEST = 130;
    private static final String TAG_UNIFICATION_DIALOG = "unification_dialog";

    // Misc Settings
    private static final String KEY_TRUST_AGENT = "trust_agent";

    // Security status
    private static final String KEY_SECURITY_STATUS = "security_status";
    private static final String SECURITY_STATUS_KEY_PREFIX = "security_status_";
@@ -101,7 +96,6 @@ public class SecuritySettingsV2 extends DashboardFragment
    private DashboardFeatureProvider mDashboardFeatureProvider;
    private DevicePolicyManager mDPM;
    private SecurityFeatureProvider mSecurityFeatureProvider;
    private TrustAgentManager mTrustAgentManager;
    private UserManager mUm;

    private ChooseLockSettingsHelper mChooseLockSettingsHelper;
@@ -111,8 +105,6 @@ public class SecuritySettingsV2 extends DashboardFragment
    private SwitchPreference mVisiblePatternProfile;
    private RestrictedSwitchPreference mUnifyProfile;

    private Intent mTrustAgentClickIntent;

    private int mProfileChallengeUserId;

    private String mCurrentDevicePassword;
@@ -127,6 +119,7 @@ public class SecuritySettingsV2 extends DashboardFragment
    private ScreenPinningPreferenceController mScreenPinningPreferenceController;
    private SimLockPreferenceController mSimLockPreferenceController;
    private ShowPasswordPreferenceController mShowPasswordPreferenceController;
    private TrustAgentListPreferenceController mTrustAgentListPreferenceController;

    @Override
    public int getMetricsCategory() {
@@ -145,7 +138,7 @@ public class SecuritySettingsV2 extends DashboardFragment
        mDashboardFeatureProvider = FeatureFactory.getFactory(context)
                .getDashboardFeatureProvider(context);

        mTrustAgentManager = mSecurityFeatureProvider.getTrustAgentManager();
        mChooseLockSettingsHelper = new ChooseLockSettingsHelper(getActivity());
    }

    @Override
@@ -172,21 +165,11 @@ public class SecuritySettingsV2 extends DashboardFragment
        mShowPasswordPreferenceController = new ShowPasswordPreferenceController(context);
        mEncryptionStatusPreferenceController = new EncryptionStatusPreferenceController(
                context, PREF_KEY_ENCRYPTION_SECURITY_PAGE);
        mTrustAgentListPreferenceController = new TrustAgentListPreferenceController(getActivity(),
                this /* host */, getLifecycle());
        return null;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        mChooseLockSettingsHelper = new ChooseLockSettingsHelper(getActivity());

        if (savedInstanceState != null
                && savedInstanceState.containsKey(TRUST_AGENT_CLICK_INTENT)) {
            mTrustAgentClickIntent = savedInstanceState.getParcelable(TRUST_AGENT_CLICK_INTENT);
        }
    }

    private static int getResIdForLockUnlockScreen(LockPatternUtils lockPatternUtils,
            ManagedLockPasswordProvider managedPasswordProvider, int userId) {
        final boolean isMyUser = userId == MY_USER_ID;
@@ -237,6 +220,7 @@ public class SecuritySettingsV2 extends DashboardFragment
        }
        addPreferencesFromResource(R.xml.security_settings_v2);
        root = getPreferenceScreen();
        mTrustAgentListPreferenceController.displayPreference(root);

        // Add options for lock/unlock screen
        final int resid = getResIdForLockUnlockScreen(mLockPatternUtils,
@@ -272,7 +256,6 @@ public class SecuritySettingsV2 extends DashboardFragment
                        mProfileChallengeUserId);
            }
        }

        Preference unlockSetOrChange = findPreference(KEY_UNLOCK_SET_OR_CHANGE);
        if (unlockSetOrChange instanceof GearPreference) {
            ((GearPreference) unlockSetOrChange).setOnGearClickListener(this);
@@ -284,7 +267,6 @@ public class SecuritySettingsV2 extends DashboardFragment
                root.findPreference(KEY_SECURITY_CATEGORY);
        if (securityCategory != null) {
            maybeAddFingerprintPreference(securityCategory, UserHandle.myUserId());
            addTrustAgentSettings(securityCategory);
            setLockscreenPreferencesSummary(securityCategory);
        }

@@ -379,34 +361,6 @@ public class SecuritySettingsV2 extends DashboardFragment
        }
    }

    // Return the number of trust agents being added
    private int addTrustAgentSettings(PreferenceGroup securityCategory) {
        final boolean hasSecurity = mLockPatternUtils.isSecure(MY_USER_ID);
        final List<TrustAgentManager.TrustAgentComponentInfo> agents =
                mTrustAgentManager.getActiveTrustAgents(getActivity(), mLockPatternUtils);
        for (TrustAgentManager.TrustAgentComponentInfo agent : agents) {
            final RestrictedPreference trustAgentPreference =
                    new RestrictedPreference(securityCategory.getContext());
            trustAgentPreference.setKey(KEY_TRUST_AGENT);
            trustAgentPreference.setTitle(agent.title);
            trustAgentPreference.setSummary(agent.summary);
            // Create intent for this preference.
            Intent intent = new Intent();
            intent.setComponent(agent.componentName);
            intent.setAction(Intent.ACTION_MAIN);
            trustAgentPreference.setIntent(intent);
            // Add preference to the settings menu.
            securityCategory.addPreference(trustAgentPreference);

            trustAgentPreference.setDisabledByAdmin(agent.admin);
            if (!trustAgentPreference.isDisabledByAdmin() && !hasSecurity) {
                trustAgentPreference.setEnabled(false);
                trustAgentPreference.setSummary(R.string.disabled_because_no_backup_security);
            }
        }
        return agents.size();
    }

    @Override
    public void onGearClick(GearPreference p) {
        if (KEY_UNLOCK_SET_OR_CHANGE.equals(p.getKey())) {
@@ -414,14 +368,6 @@ public class SecuritySettingsV2 extends DashboardFragment
        }
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        if (mTrustAgentClickIntent != null) {
            outState.putParcelable(TRUST_AGENT_CLICK_INTENT, mTrustAgentClickIntent);
        }
    }

    @Override
    public void onResume() {
        super.onResume();
@@ -445,7 +391,7 @@ public class SecuritySettingsV2 extends DashboardFragment
        final Preference encryptionStatusPref = getPreferenceScreen().findPreference(
                mEncryptionStatusPreferenceController.getPreferenceKey());
        mEncryptionStatusPreferenceController.updateState(encryptionStatusPref);

        mTrustAgentListPreferenceController.onResume();
        mLocationController.updateSummary();
    }

@@ -465,6 +411,9 @@ public class SecuritySettingsV2 extends DashboardFragment

    @Override
    public boolean onPreferenceTreeClick(Preference preference) {
        if (mTrustAgentListPreferenceController.handlePreferenceTreeClick(preference)) {
            return true;
        }
        final String key = preference.getKey();
        if (KEY_UNLOCK_SET_OR_CHANGE.equals(key)) {
            // TODO(b/35930129): Remove once existing password can be passed into vold directly.
@@ -491,17 +440,6 @@ public class SecuritySettingsV2 extends DashboardFragment
            startFragment(this, ChooseLockGeneric.ChooseLockGenericFragment.class.getName(),
                    R.string.lock_settings_picker_title_profile,
                    SET_OR_CHANGE_LOCK_METHOD_REQUEST_PROFILE, extras);
        } else if (KEY_TRUST_AGENT.equals(key)) {
            ChooseLockSettingsHelper helper =
                    new ChooseLockSettingsHelper(this.getActivity(), this);
            mTrustAgentClickIntent = preference.getIntent();
            boolean confirmationLaunched = helper.launchConfirmationActivity(
                    CHANGE_TRUST_AGENT_SETTINGS, preference.getTitle());
            if (!confirmationLaunched && mTrustAgentClickIntent != null) {
                // If this returns false, it means no password confirmation is required.
                startActivity(mTrustAgentClickIntent);
                mTrustAgentClickIntent = null;
            }
        } else {
            // If we didn't handle it, let preferences handle it.
            return super.onPreferenceTreeClick(preference);
@@ -516,10 +454,7 @@ public class SecuritySettingsV2 extends DashboardFragment
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == CHANGE_TRUST_AGENT_SETTINGS && resultCode == Activity.RESULT_OK) {
            if (mTrustAgentClickIntent != null) {
                startActivity(mTrustAgentClickIntent);
                mTrustAgentClickIntent = null;
            }
            mTrustAgentListPreferenceController.handleActivityResult(resultCode);
            return;
        } else if (requestCode == UNIFY_LOCK_CONFIRM_DEVICE_REQUEST
                && resultCode == Activity.RESULT_OK) {
@@ -760,15 +695,9 @@ public class SecuritySettingsV2 extends DashboardFragment
        @Override
        public List<String> getNonIndexableKeys(Context context) {
            final List<String> keys = super.getNonIndexableKeys(context);
            final LockPatternUtils lockPatternUtils = new LockPatternUtils(context);

            new SimLockPreferenceController(context).updateNonIndexableKeys(keys);

            // TrustAgent settings disappear when the user has no primary security.
            if (!lockPatternUtils.isSecure(MY_USER_ID)) {
                keys.add(KEY_TRUST_AGENT);
            }

            if (!(new EnterprisePrivacyPreferenceController(context))
                    .isAvailable()) {
                keys.add(KEY_ENTERPRISE_PRIVACY);
+172 −0
Original line number Diff line number Diff line
/*
 * 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.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.os.UserHandle;
import android.support.annotation.VisibleForTesting;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceCategory;
import android.support.v7.preference.PreferenceScreen;
import android.text.TextUtils;

import com.android.internal.widget.LockPatternUtils;
import com.android.settings.R;
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.password.ChooseLockSettingsHelper;
import com.android.settings.security.SecurityFeatureProvider;
import com.android.settings.security.SecuritySettingsV2;
import com.android.settingslib.RestrictedPreference;
import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.core.lifecycle.Lifecycle;
import com.android.settingslib.core.lifecycle.LifecycleObserver;
import com.android.settingslib.core.lifecycle.events.OnCreate;
import com.android.settingslib.core.lifecycle.events.OnResume;
import com.android.settingslib.core.lifecycle.events.OnSaveInstanceState;

import java.util.List;

public class TrustAgentListPreferenceController extends AbstractPreferenceController
        implements LifecycleObserver, OnSaveInstanceState, OnCreate, OnResume {

    private static final String TRUST_AGENT_CLICK_INTENT = "trust_agent_click_intent";
    @VisibleForTesting
    static final String PREF_KEY_TRUST_AGENT = "trust_agent";
    @VisibleForTesting
    static final String PREF_KEY_SECURITY_CATEGORY = "security_category";
    private static final int MY_USER_ID = UserHandle.myUserId();

    private final LockPatternUtils mLockPatternUtils;
    private final TrustAgentManager mTrustAgentManager;
    private final Activity mActivity;
    private final SecuritySettingsV2 mHost;

    private Intent mTrustAgentClickIntent;
    private PreferenceCategory mSecurityCategory;

    public TrustAgentListPreferenceController(Activity activity, SecuritySettingsV2 host,
            Lifecycle lifecycle) {
        super(activity);
        final SecurityFeatureProvider provider = FeatureFactory.getFactory(activity)
                .getSecurityFeatureProvider();
        mActivity = activity;
        mHost = host;
        mLockPatternUtils = provider.getLockPatternUtils(activity);
        mTrustAgentManager = provider.getTrustAgentManager();
        if (lifecycle != null) {
            lifecycle.addObserver(this);
        }
    }

    @Override
    public boolean isAvailable() {
        return true;
    }

    @Override
    public String getPreferenceKey() {
        return PREF_KEY_TRUST_AGENT;
    }

    @Override
    public void displayPreference(PreferenceScreen screen) {
        super.displayPreference(screen);
        mSecurityCategory = (PreferenceCategory) screen.findPreference(PREF_KEY_SECURITY_CATEGORY);
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        if (savedInstanceState != null
                && savedInstanceState.containsKey(TRUST_AGENT_CLICK_INTENT)) {
            mTrustAgentClickIntent = savedInstanceState.getParcelable(TRUST_AGENT_CLICK_INTENT);
        }
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        if (mTrustAgentClickIntent != null) {
            outState.putParcelable(TRUST_AGENT_CLICK_INTENT, mTrustAgentClickIntent);
        }
    }

    @Override
    public boolean handlePreferenceTreeClick(Preference preference) {
        if (!TextUtils.equals(preference.getKey(), getPreferenceKey())) {
            return super.handlePreferenceTreeClick(preference);
        }
        final ChooseLockSettingsHelper helper = new ChooseLockSettingsHelper(mActivity, mHost);
        mTrustAgentClickIntent = preference.getIntent();
        boolean confirmationLaunched = helper.launchConfirmationActivity(
                SecuritySettingsV2.CHANGE_TRUST_AGENT_SETTINGS, preference.getTitle());

        if (!confirmationLaunched && mTrustAgentClickIntent != null) {
            // If this returns false, it means no password confirmation is required.
            mHost.startActivity(mTrustAgentClickIntent);
            mTrustAgentClickIntent = null;
        }
        return true;
    }

    @Override
    public void onResume() {
        if (mSecurityCategory == null) {
            return;
        }
        // First remove all old trust agents.
        while (true) {
            final Preference oldAgent = mSecurityCategory.findPreference(PREF_KEY_TRUST_AGENT);
            if (oldAgent == null) {
                break;
            } else {
                mSecurityCategory.removePreference(oldAgent);
            }
        }
        // Then add new ones.
        final boolean hasSecurity = mLockPatternUtils.isSecure(MY_USER_ID);
        final List<TrustAgentManager.TrustAgentComponentInfo> agents =
                mTrustAgentManager.getActiveTrustAgents(mContext, mLockPatternUtils);
        if (agents == null) {
            return;
        }
        for (TrustAgentManager.TrustAgentComponentInfo agent : agents) {
            final RestrictedPreference trustAgentPreference =
                    new RestrictedPreference(mSecurityCategory.getContext());
            trustAgentPreference.setKey(PREF_KEY_TRUST_AGENT);
            trustAgentPreference.setTitle(agent.title);
            trustAgentPreference.setSummary(agent.summary);
            // Create intent for this preference.
            trustAgentPreference.setIntent(new Intent(Intent.ACTION_MAIN)
                    .setComponent(agent.componentName));
            trustAgentPreference.setDisabledByAdmin(agent.admin);
            if (!trustAgentPreference.isDisabledByAdmin() && !hasSecurity) {
                trustAgentPreference.setEnabled(false);
                trustAgentPreference.setSummary(R.string.disabled_because_no_backup_security);
            }
            // Add preference to the settings menu.
            mSecurityCategory.addPreference(trustAgentPreference);
        }
    }

    public void handleActivityResult(int resultCode) {
        if (resultCode == Activity.RESULT_OK && mTrustAgentClickIntent != null) {
            mHost.startActivity(mTrustAgentClickIntent);
            mTrustAgentClickIntent = null;
        }
    }
}
+132 −0
Original line number Diff line number Diff line
/*
 * 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.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.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceCategory;
import android.support.v7.preference.PreferenceScreen;

import com.android.internal.widget.LockPatternUtils;
import com.android.settings.TestConfig;
import com.android.settings.security.SecuritySettingsV2;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settingslib.core.lifecycle.Lifecycle;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.Robolectric;
import org.robolectric.annotation.Config;

import java.util.ArrayList;
import java.util.List;

@RunWith(SettingsRobolectricTestRunner.class)
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public class TrustAgentListPreferenceControllerTest {

    @Mock
    private TrustAgentManager mTrustAgentManager;
    @Mock
    private LockPatternUtils mLockPatternUtils;
    @Mock
    private PreferenceScreen mScreen;
    @Mock
    private PreferenceCategory mCategory;
    @Mock
    private SecuritySettingsV2 mFragment;

    private Lifecycle mLifecycle;
    private FakeFeatureFactory mFeatureFactory;
    private Activity mActivity;

    private TrustAgentListPreferenceController mController;


    @Before
    public void setUp() {
        MockitoAnnotations.initMocks(this);
        mActivity = Robolectric.buildActivity(Activity.class).get();
        mLifecycle = new Lifecycle(() -> mLifecycle);
        mFeatureFactory = FakeFeatureFactory.setupForTest();
        when(mFeatureFactory.securityFeatureProvider.getLockPatternUtils(any(Context.class)))
                .thenReturn(mLockPatternUtils);
        when(mFeatureFactory.securityFeatureProvider.getTrustAgentManager())
                .thenReturn(mTrustAgentManager);
        when(mCategory.getKey()).thenReturn(PREF_KEY_SECURITY_CATEGORY);
        when(mCategory.getContext()).thenReturn(mActivity);
        when(mScreen.findPreference(PREF_KEY_SECURITY_CATEGORY))
                .thenReturn(mCategory);
        mController = new TrustAgentListPreferenceController(mActivity, mFragment, mLifecycle);
    }

    @Test
    public void testConstants() {
        assertThat(mController.isAvailable()).isTrue();
        assertThat(mController.getPreferenceKey()).isEqualTo(PREF_KEY_TRUST_AGENT);
    }

    @Test
    public void onResume_shouldClearOldAgents() {
        final Preference oldAgent = new Preference(mActivity);
        oldAgent.setKey(PREF_KEY_TRUST_AGENT);
        when(mCategory.findPreference(PREF_KEY_TRUST_AGENT))
                .thenReturn(oldAgent)
                .thenReturn(null);

        mController.displayPreference(mScreen);
        mController.onResume();

        verify(mCategory).removePreference(oldAgent);
    }

    @Test
    public void onResume_shouldAddNewAgents() {
        final List<TrustAgentManager.TrustAgentComponentInfo> agents = new ArrayList<>();
        final TrustAgentManager.TrustAgentComponentInfo agent = 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);

        mController.displayPreference(mScreen);
        mController.onResume();

        verify(mCategory).addPreference(any(Preference.class));
    }
}