Prevent UI jank

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

Fixes: 140366463
Test: manual, robolectric
Change-Id: Ie11b5357b1e9340b30b8f19eac60c479cdb7687e
This commit is contained in:
Raff Tsai
2019-09-03 10:00:56 +08:00
parent e5f89ea85d
commit 8641986401
3 changed files with 51 additions and 38 deletions

View File

@@ -49,6 +49,7 @@ public class RestrictAppPreferenceController extends BasePreferenceController {
super(context, KEY_RESTRICT_APP); super(context, KEY_RESTRICT_APP);
mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE); mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
mUserManager = context.getSystemService(UserManager.class); mUserManager = context.getSystemService(UserManager.class);
mAppInfos = BatteryTipUtils.getRestrictedAppsList(mAppOpsManager, mUserManager);
} }
public RestrictAppPreferenceController(InstrumentedPreferenceFragment preferenceFragment) { public RestrictAppPreferenceController(InstrumentedPreferenceFragment preferenceFragment) {
@@ -58,21 +59,14 @@ public class RestrictAppPreferenceController extends BasePreferenceController {
@Override @Override
public int getAvailabilityStatus() { public int getAvailabilityStatus() {
return AVAILABLE; return mAppInfos.size() > 0 ? AVAILABLE : CONDITIONALLY_UNAVAILABLE;
} }
@Override @Override
public void updateState(Preference preference) { public CharSequence getSummary() {
super.updateState(preference);
mAppInfos = BatteryTipUtils.getRestrictedAppsList(mAppOpsManager, mUserManager);
final int num = mAppInfos.size(); final int num = mAppInfos.size();
// Don't show it if no app been restricted return mContext.getResources().getQuantityString(R.plurals.restricted_app_summary, num,
preference.setVisible(num > 0); num);
preference.setSummary(
mContext.getResources().getQuantityString(R.plurals.restricted_app_summary, num,
num));
} }
@Override @Override

View File

@@ -68,7 +68,6 @@ public class SmartBatterySettings extends DashboardFragment {
Context context, SettingsActivity settingsActivity, Context context, SettingsActivity settingsActivity,
InstrumentedPreferenceFragment fragment) { InstrumentedPreferenceFragment fragment) {
final List<AbstractPreferenceController> controllers = new ArrayList<>(); final List<AbstractPreferenceController> controllers = new ArrayList<>();
controllers.add(new SmartBatteryPreferenceController(context));
if (settingsActivity != null && fragment != null) { if (settingsActivity != null && fragment != null) {
controllers.add( controllers.add(
new RestrictAppPreferenceController(fragment)); new RestrictAppPreferenceController(fragment));

View File

@@ -23,8 +23,10 @@ import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy; import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.Activity; import android.app.Activity;
import android.app.AppOpsManager; import android.app.AppOpsManager;
@@ -34,6 +36,8 @@ import android.os.UserHandle;
import android.os.UserManager; import android.os.UserManager;
import androidx.preference.Preference; import androidx.preference.Preference;
import androidx.preference.PreferenceManager;
import androidx.preference.PreferenceScreen;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.core.InstrumentedPreferenceFragment; import com.android.settings.core.InstrumentedPreferenceFragment;
@@ -46,10 +50,10 @@ import org.mockito.ArgumentCaptor;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.MockitoAnnotations; import org.mockito.MockitoAnnotations;
import org.robolectric.Robolectric; import org.robolectric.Robolectric;
import org.robolectric.RobolectricTestRunner;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.robolectric.RobolectricTestRunner;
@RunWith(RobolectricTestRunner.class) @RunWith(RobolectricTestRunner.class)
public class RestrictAppPreferenceControllerTest { public class RestrictAppPreferenceControllerTest {
@@ -70,25 +74,23 @@ public class RestrictAppPreferenceControllerTest {
private AppOpsManager.PackageOps mAllowedPackageOps; private AppOpsManager.PackageOps mAllowedPackageOps;
private AppOpsManager.PackageOps mOtherUserPackageOps; private AppOpsManager.PackageOps mOtherUserPackageOps;
private List<AppOpsManager.PackageOps> mPackageOpsList; private List<AppOpsManager.PackageOps> mPackageOpsList;
private RestrictAppPreferenceController mRestrictAppPreferenceController;
private Preference mPreference; private Preference mPreference;
private PreferenceScreen mPreferenceScreen;
private Context mContext; private Context mContext;
@Before @Before
public void setUp() { public void setUp() {
MockitoAnnotations.initMocks(this); 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, AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, false, AppOpsManager.MODE_ALLOWED,
null /*accessTimes*/, null /*rejectTimes*/, null /*durations*/, null /*accessTimes*/, null /*rejectTimes*/, null /*durations*/,
null /* proxyUids */, null /* proxyPackages */); null /* proxyUids */, null /* proxyPackages */));
final List<AppOpsManager.OpEntry> allowOps = new ArrayList<>(); final List<AppOpsManager.OpEntry> restrictedOps = new ArrayList<>();
allowOps.add(allowOpEntry); restrictedOps.add(new AppOpsManager.OpEntry(
final AppOpsManager.OpEntry restrictedOpEntry = new AppOpsManager.OpEntry(
AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, false, AppOpsManager.MODE_IGNORED, AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, false, AppOpsManager.MODE_IGNORED,
null /*accessTimes*/, null /*rejectTimes*/, null /*durations*/, null /*accessTimes*/, null /*rejectTimes*/, null /*durations*/,
null /* proxyUids */, null /* proxyPackages */); null /* proxyUids */, null /* proxyPackages */));
final List<AppOpsManager.OpEntry> restrictedOps = new ArrayList<>();
restrictedOps.add(restrictedOpEntry);
mAllowedPackageOps = new AppOpsManager.PackageOps( mAllowedPackageOps = new AppOpsManager.PackageOps(
ALLOWED_PACKAGE_NAME, ALLOWED_UID, allowOps); ALLOWED_PACKAGE_NAME, ALLOWED_UID, allowOps);
mRestrictedPackageOps = new AppOpsManager.PackageOps( mRestrictedPackageOps = new AppOpsManager.PackageOps(
@@ -100,11 +102,15 @@ public class RestrictAppPreferenceControllerTest {
doReturn(mAppOpsManager).when(mContext).getSystemService(Context.APP_OPS_SERVICE); doReturn(mAppOpsManager).when(mContext).getSystemService(Context.APP_OPS_SERVICE);
doReturn(mUserManager).when(mContext).getSystemService(UserManager.class); doReturn(mUserManager).when(mContext).getSystemService(UserManager.class);
doReturn(mContext).when(mFragment).getContext(); doReturn(mContext).when(mFragment).getContext();
mRestrictAppPreferenceController =
new RestrictAppPreferenceController(mFragment);
mPackageOpsList = new ArrayList<>(); mPackageOpsList = new ArrayList<>();
mPreference = new Preference(mContext); 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<>(); final List<UserHandle> userHandles = new ArrayList<>();
userHandles.add(new UserHandle(0)); userHandles.add(new UserHandle(0));
@@ -112,40 +118,49 @@ public class RestrictAppPreferenceControllerTest {
} }
@Test @Test
public void testUpdateState_oneApp_showCorrectSummary() { public void updateState_oneApp_showCorrectSummary() {
mPackageOpsList.add(mRestrictedPackageOps); mPackageOpsList.add(mRestrictedPackageOps);
doReturn(mPackageOpsList).when(mAppOpsManager).getPackagesForOps(any(int[].class)); 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(mPreference.getSummary()).isEqualTo("Limiting battery usage for 1 app");
} }
@Test @Test
public void testUpdateState_twoRestrictedAppsForPrimaryUser_visibleAndShowCorrectSummary() { public void updateState_twoRestrictedAppsForPrimaryUser_visibleAndShowCorrectSummary() {
mPackageOpsList.add(mRestrictedPackageOps); mPackageOpsList.add(mRestrictedPackageOps);
mPackageOpsList.add(mRestrictedPackageOps); mPackageOpsList.add(mRestrictedPackageOps);
mPackageOpsList.add(mAllowedPackageOps); mPackageOpsList.add(mAllowedPackageOps);
mPackageOpsList.add(mOtherUserPackageOps); mPackageOpsList.add(mOtherUserPackageOps);
doReturn(mPackageOpsList).when(mAppOpsManager).getPackagesForOps(any(int[].class)); 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.getSummary()).isEqualTo("Limiting battery usage for 2 apps");
assertThat(mPreference.isVisible()).isTrue(); assertThat(mPreference.isVisible()).isTrue();
} }
@Test @Test
public void testUpdateState_oneRestrictedAppForTwoUsers_showSummaryAndContainCorrectApp() { public void updateState_oneRestrictedAppForTwoUsers_showSummaryAndContainCorrectApp() {
// Two packageOps share same package name but different uid. // Two packageOps share same package name but different uid.
mPackageOpsList.add(mRestrictedPackageOps); mPackageOpsList.add(mRestrictedPackageOps);
mPackageOpsList.add(mOtherUserPackageOps); mPackageOpsList.add(mOtherUserPackageOps);
doReturn(mPackageOpsList).when(mAppOpsManager).getPackagesForOps(any(int[].class)); 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(mPreference.getSummary()).isEqualTo("Limiting battery usage for 1 app");
assertThat(mRestrictAppPreferenceController.mAppInfos).containsExactly( assertThat(controller.mAppInfos).containsExactly(
new AppInfo.Builder() new AppInfo.Builder()
.setUid(RESTRICTED_UID) .setUid(RESTRICTED_UID)
.setPackageName(RESTRICTED_PACKAGE_NAME) .setPackageName(RESTRICTED_PACKAGE_NAME)
@@ -153,20 +168,25 @@ public class RestrictAppPreferenceControllerTest {
} }
@Test @Test
public void testUpdateState_zeroRestrictApp_inVisible() { public void updateState_zeroRestrictApp_inVisible() {
mPackageOpsList.add(mAllowedPackageOps); mPackageOpsList.add(mAllowedPackageOps);
doReturn(mPackageOpsList).when(mAppOpsManager).getPackagesForOps(any(int[].class)); 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(); assertThat(mPreference.isVisible()).isFalse();
} }
@Test @Test
public void testHandlePreferenceTreeClick_startFragment() { public void handlePreferenceTreeClick_startFragment() {
final ArgumentCaptor<Intent> intent = ArgumentCaptor.forClass(Intent.class); 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()); verify(mContext).startActivity(intent.capture());
assertThat(intent.getValue().getStringExtra(EXTRA_SHOW_FRAGMENT)) assertThat(intent.getValue().getStringExtra(EXTRA_SHOW_FRAGMENT))