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

Commit 86419864 authored by Raff Tsai's avatar Raff Tsai
Browse files

Prevent UI jank

Move hide preference logic to getAvailabilityStatus, it can remove
the preference before onresume.

Fixes: 140366463
Test: manual, robolectric
Change-Id: Ie11b5357b1e9340b30b8f19eac60c479cdb7687e
parent e5f89ea8
Loading
Loading
Loading
Loading
+5 −11
Original line number Diff line number Diff line
@@ -49,6 +49,7 @@ public class RestrictAppPreferenceController extends BasePreferenceController {
        super(context, KEY_RESTRICT_APP);
        mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
        mUserManager = context.getSystemService(UserManager.class);
        mAppInfos = BatteryTipUtils.getRestrictedAppsList(mAppOpsManager, mUserManager);
    }

    public RestrictAppPreferenceController(InstrumentedPreferenceFragment preferenceFragment) {
@@ -58,21 +59,14 @@ public class RestrictAppPreferenceController extends BasePreferenceController {

    @Override
    public int getAvailabilityStatus() {
        return AVAILABLE;
        return mAppInfos.size() > 0 ? AVAILABLE : CONDITIONALLY_UNAVAILABLE;
    }

    @Override
    public void updateState(Preference preference) {
        super.updateState(preference);

        mAppInfos = BatteryTipUtils.getRestrictedAppsList(mAppOpsManager, mUserManager);

    public CharSequence getSummary() {
        final int num = mAppInfos.size();
        // Don't show it if no app been restricted
        preference.setVisible(num > 0);
        preference.setSummary(
                mContext.getResources().getQuantityString(R.plurals.restricted_app_summary, num,
                        num));
        return mContext.getResources().getQuantityString(R.plurals.restricted_app_summary, num,
                        num);
    }

    @Override
+0 −1
Original line number Diff line number Diff line
@@ -68,7 +68,6 @@ public class SmartBatterySettings extends DashboardFragment {
            Context context, SettingsActivity settingsActivity,
            InstrumentedPreferenceFragment fragment) {
        final List<AbstractPreferenceController> controllers = new ArrayList<>();
        controllers.add(new SmartBatteryPreferenceController(context));
        if (settingsActivity != null && fragment != null) {
            controllers.add(
                    new RestrictAppPreferenceController(fragment));
+46 −26
Original line number Diff line number Diff line
@@ -23,8 +23,10 @@ import static com.google.common.truth.Truth.assertThat;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import android.app.Activity;
import android.app.AppOpsManager;
@@ -34,6 +36,8 @@ import android.os.UserHandle;
import android.os.UserManager;

import androidx.preference.Preference;
import androidx.preference.PreferenceManager;
import androidx.preference.PreferenceScreen;

import com.android.settings.R;
import com.android.settings.core.InstrumentedPreferenceFragment;
@@ -46,10 +50,10 @@ import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.Robolectric;
import org.robolectric.RobolectricTestRunner;

import java.util.ArrayList;
import java.util.List;
import org.robolectric.RobolectricTestRunner;

@RunWith(RobolectricTestRunner.class)
public class RestrictAppPreferenceControllerTest {
@@ -70,25 +74,23 @@ public class RestrictAppPreferenceControllerTest {
    private AppOpsManager.PackageOps mAllowedPackageOps;
    private AppOpsManager.PackageOps mOtherUserPackageOps;
    private List<AppOpsManager.PackageOps> mPackageOpsList;
    private RestrictAppPreferenceController mRestrictAppPreferenceController;
    private Preference mPreference;
    private PreferenceScreen mPreferenceScreen;
    private Context mContext;

    @Before
    public void setUp() {
        MockitoAnnotations.initMocks(this);
        final AppOpsManager.OpEntry allowOpEntry = new AppOpsManager.OpEntry(
        final List<AppOpsManager.OpEntry> allowOps = new ArrayList<>();
        allowOps.add(new AppOpsManager.OpEntry(
                AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, false, AppOpsManager.MODE_ALLOWED,
                null /*accessTimes*/, null /*rejectTimes*/, null /*durations*/,
            null /* proxyUids */, null /* proxyPackages */);
        final List<AppOpsManager.OpEntry> allowOps = new ArrayList<>();
        allowOps.add(allowOpEntry);
        final AppOpsManager.OpEntry restrictedOpEntry = new AppOpsManager.OpEntry(
                null /* proxyUids */, null /* proxyPackages */));
        final List<AppOpsManager.OpEntry> restrictedOps = new ArrayList<>();
        restrictedOps.add(new AppOpsManager.OpEntry(
                AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, false, AppOpsManager.MODE_IGNORED,
                null /*accessTimes*/, null /*rejectTimes*/, null /*durations*/,
            null /* proxyUids */, null /* proxyPackages */);
        final List<AppOpsManager.OpEntry> restrictedOps = new ArrayList<>();
        restrictedOps.add(restrictedOpEntry);
                null /* proxyUids */, null /* proxyPackages */));
        mAllowedPackageOps = new AppOpsManager.PackageOps(
                ALLOWED_PACKAGE_NAME, ALLOWED_UID, allowOps);
        mRestrictedPackageOps = new AppOpsManager.PackageOps(
@@ -100,11 +102,15 @@ public class RestrictAppPreferenceControllerTest {
        doReturn(mAppOpsManager).when(mContext).getSystemService(Context.APP_OPS_SERVICE);
        doReturn(mUserManager).when(mContext).getSystemService(UserManager.class);
        doReturn(mContext).when(mFragment).getContext();
        mRestrictAppPreferenceController =
                new RestrictAppPreferenceController(mFragment);

        mPackageOpsList = new ArrayList<>();
        mPreference = new Preference(mContext);
        mPreference.setKey(mRestrictAppPreferenceController.getPreferenceKey());
        mPreference.setKey(RestrictAppPreferenceController.KEY_RESTRICT_APP);
        mPreferenceScreen = spy(new PreferenceScreen(mContext, null));
        when(mPreferenceScreen.getPreferenceManager()).thenReturn(mock(PreferenceManager.class));
        when(mPreferenceScreen.getContext()).thenReturn(mContext);
        when(mPreferenceScreen.findPreference(
                RestrictAppPreferenceController.KEY_RESTRICT_APP)).thenReturn(mPreference);

        final List<UserHandle> userHandles = new ArrayList<>();
        userHandles.add(new UserHandle(0));
@@ -112,40 +118,49 @@ public class RestrictAppPreferenceControllerTest {
    }

    @Test
    public void testUpdateState_oneApp_showCorrectSummary() {
    public void updateState_oneApp_showCorrectSummary() {
        mPackageOpsList.add(mRestrictedPackageOps);
        doReturn(mPackageOpsList).when(mAppOpsManager).getPackagesForOps(any(int[].class));

        mRestrictAppPreferenceController.updateState(mPreference);
        final RestrictAppPreferenceController controller = new RestrictAppPreferenceController(
                mFragment);
        controller.displayPreference(mPreferenceScreen);
        controller.updateState(mPreference);

        assertThat(mPreference.getSummary()).isEqualTo("Limiting battery usage for 1 app");
    }

    @Test
    public void testUpdateState_twoRestrictedAppsForPrimaryUser_visibleAndShowCorrectSummary() {
    public void updateState_twoRestrictedAppsForPrimaryUser_visibleAndShowCorrectSummary() {
        mPackageOpsList.add(mRestrictedPackageOps);
        mPackageOpsList.add(mRestrictedPackageOps);
        mPackageOpsList.add(mAllowedPackageOps);
        mPackageOpsList.add(mOtherUserPackageOps);
        doReturn(mPackageOpsList).when(mAppOpsManager).getPackagesForOps(any(int[].class));

        mRestrictAppPreferenceController.updateState(mPreference);
        final RestrictAppPreferenceController controller = new RestrictAppPreferenceController(
                mFragment);
        controller.displayPreference(mPreferenceScreen);
        controller.updateState(mPreference);

        assertThat(mPreference.getSummary()).isEqualTo("Limiting battery usage for 2 apps");
        assertThat(mPreference.isVisible()).isTrue();
    }

    @Test
    public void testUpdateState_oneRestrictedAppForTwoUsers_showSummaryAndContainCorrectApp() {
    public void updateState_oneRestrictedAppForTwoUsers_showSummaryAndContainCorrectApp() {
        // Two packageOps share same package name but different uid.
        mPackageOpsList.add(mRestrictedPackageOps);
        mPackageOpsList.add(mOtherUserPackageOps);
        doReturn(mPackageOpsList).when(mAppOpsManager).getPackagesForOps(any(int[].class));

        mRestrictAppPreferenceController.updateState(mPreference);
        final RestrictAppPreferenceController controller = new RestrictAppPreferenceController(
                mFragment);
        controller.displayPreference(mPreferenceScreen);
        controller.updateState(mPreference);

        assertThat(mPreference.getSummary()).isEqualTo("Limiting battery usage for 1 app");
        assertThat(mRestrictAppPreferenceController.mAppInfos).containsExactly(
        assertThat(controller.mAppInfos).containsExactly(
                new AppInfo.Builder()
                        .setUid(RESTRICTED_UID)
                        .setPackageName(RESTRICTED_PACKAGE_NAME)
@@ -153,20 +168,25 @@ public class RestrictAppPreferenceControllerTest {
    }

    @Test
    public void testUpdateState_zeroRestrictApp_inVisible() {
    public void updateState_zeroRestrictApp_inVisible() {
        mPackageOpsList.add(mAllowedPackageOps);
        doReturn(mPackageOpsList).when(mAppOpsManager).getPackagesForOps(any(int[].class));

        mRestrictAppPreferenceController.updateState(mPreference);
        final RestrictAppPreferenceController controller = new RestrictAppPreferenceController(
                mFragment);
        controller.displayPreference(mPreferenceScreen);
        controller.updateState(mPreference);

        assertThat(mPreference.isVisible()).isFalse();
    }

    @Test
    public void testHandlePreferenceTreeClick_startFragment() {
    public void handlePreferenceTreeClick_startFragment() {
        final ArgumentCaptor<Intent> intent = ArgumentCaptor.forClass(Intent.class);

        mRestrictAppPreferenceController.handlePreferenceTreeClick(mPreference);
        final RestrictAppPreferenceController controller = new RestrictAppPreferenceController(
                mFragment);
        controller.handlePreferenceTreeClick(mPreference);

        verify(mContext).startActivity(intent.capture());
        assertThat(intent.getValue().getStringExtra(EXTRA_SHOW_FRAGMENT))