From 826879ed63bae0b459aeb7e6d42400d9c7f1b499 Mon Sep 17 00:00:00 2001 From: tmfang Date: Mon, 25 Feb 2019 18:12:24 +0800 Subject: [PATCH] Create a preference controller for "App info" We try to avoid managing too many preferences in a controller. So, we create another controller to manage all apps info preference. RecentAppsPreferenceController and AllAppsInfoPreferenceController share same state of recent apps in order to improve the performance. Test: visual, robo test Fixes: 126134996 Change-Id: I1d8a175b213831415797437c64fd9d432864f9d3 --- res/xml/app_and_notification.xml | 3 +- .../AllAppsInfoPreferenceController.java | 58 ++++++++++++ .../AppAndNotificationDashboardFragment.java | 25 +++++- .../RecentAppsPreferenceController.java | 45 +++------- .../AllAppsInfoPreferenceControllerTest.java | 64 +++++++++++++ .../RecentAppsPreferenceControllerTest.java | 90 +++++++------------ 6 files changed, 190 insertions(+), 95 deletions(-) create mode 100644 src/com/android/settings/applications/AllAppsInfoPreferenceController.java create mode 100644 tests/robotests/src/com/android/settings/applications/AllAppsInfoPreferenceControllerTest.java diff --git a/res/xml/app_and_notification.xml b/res/xml/app_and_notification.xml index 518379ac86e..9dd5feaa1ce 100644 --- a/res/xml/app_and_notification.xml +++ b/res/xml/app_and_notification.xml @@ -27,7 +27,8 @@ android:key="all_app_info" android:title="@string/applications_settings" android:order="-999" - android:fragment="com.android.settings.applications.manageapplications.ManageApplications"/> + android:fragment="com.android.settings.applications.manageapplications.ManageApplications" + settings:controller="com.android.settings.applications.AllAppsInfoPreferenceController"/> mRecentApps; + + public AllAppsInfoPreferenceController(Context context, String key) { + super(context, key); + } + + public void setRecentApps(List recentApps) { + mRecentApps = recentApps; + } + + @Override + public int getAvailabilityStatus() { + return mRecentApps == null || mRecentApps.isEmpty() ? AVAILABLE : CONDITIONALLY_UNAVAILABLE; + } + + @Override + public void updateState(Preference preference) { + super.updateState(preference); + // Show total number of installed apps as See all's summary. + new InstalledAppCounter(mContext, InstalledAppCounter.IGNORE_INSTALL_REASON, + mContext.getPackageManager()) { + @Override + protected void onCountComplete(int num) { + preference.setSummary(mContext.getString(R.string.apps_summary, num)); + } + }.execute(); + } +} diff --git a/src/com/android/settings/applications/AppAndNotificationDashboardFragment.java b/src/com/android/settings/applications/AppAndNotificationDashboardFragment.java index 48483517f91..7aaf80de65c 100644 --- a/src/com/android/settings/applications/AppAndNotificationDashboardFragment.java +++ b/src/com/android/settings/applications/AppAndNotificationDashboardFragment.java @@ -36,6 +36,10 @@ public class AppAndNotificationDashboardFragment extends DashboardFragment { private static final String TAG = "AppAndNotifDashboard"; + private boolean mIsFirstLaunch; + private RecentAppsPreferenceController mRecentAppsPreferenceController; + private AllAppsInfoPreferenceController mAllAppsInfoPreferenceController; + @Override public int getMetricsCategory() { return SettingsEnums.SETTINGS_APP_NOTIF_CATEGORY; @@ -61,7 +65,26 @@ public class AppAndNotificationDashboardFragment extends DashboardFragment { super.onAttach(context); use(SpecialAppAccessPreferenceController.class).setSession(getSettingsLifecycle()); - use(RecentAppsPreferenceController.class).setFragment(this /* fragment */); + mRecentAppsPreferenceController = use(RecentAppsPreferenceController.class); + mRecentAppsPreferenceController.setFragment(this /* fragment */); + + mAllAppsInfoPreferenceController = use(AllAppsInfoPreferenceController.class); + mAllAppsInfoPreferenceController.setRecentApps( + mRecentAppsPreferenceController.getRecentApps()); + + mIsFirstLaunch = true; + } + + @Override + public void onResume() { + if (!mIsFirstLaunch) { + mRecentAppsPreferenceController.reloadData(); + mAllAppsInfoPreferenceController.setRecentApps( + mRecentAppsPreferenceController.getRecentApps()); + } + + super.onResume(); + mIsFirstLaunch = false; } @Override diff --git a/src/com/android/settings/applications/RecentAppsPreferenceController.java b/src/com/android/settings/applications/RecentAppsPreferenceController.java index 838d75849ac..c0d18c6eb81 100644 --- a/src/com/android/settings/applications/RecentAppsPreferenceController.java +++ b/src/com/android/settings/applications/RecentAppsPreferenceController.java @@ -66,8 +66,6 @@ import java.util.Set; public class RecentAppsPreferenceController extends BasePreferenceController implements Comparator { - @VisibleForTesting - static final String KEY_ALL_APP_INFO = "all_app_info"; @VisibleForTesting static final String KEY_DIVIDER = "recent_apps_divider"; @@ -79,11 +77,7 @@ public class RecentAppsPreferenceController extends BasePreferenceController @VisibleForTesting LayoutPreference mRecentAppsPreference; @VisibleForTesting - Preference mAllAppPref; - @VisibleForTesting Preference mDivider; - @VisibleForTesting - boolean mIsFirstLaunch; private final PackageManager mPm; private final UsageStatsManager mUsageStatsManager; @@ -119,7 +113,6 @@ public class RecentAppsPreferenceController extends BasePreferenceController mPowerManager = mContext.getSystemService(PowerManager.class); mUsageStatsManager = mContext.getSystemService(UsageStatsManager.class); mRecentApps = new ArrayList<>(); - mIsFirstLaunch = true; reloadData(); } @@ -129,14 +122,13 @@ public class RecentAppsPreferenceController extends BasePreferenceController @Override public int getAvailabilityStatus() { - return mRecentApps.isEmpty() ? AVAILABLE_UNSEARCHABLE : AVAILABLE; + return mRecentApps.isEmpty() ? CONDITIONALLY_UNAVAILABLE : AVAILABLE; } @Override public void displayPreference(PreferenceScreen screen) { super.displayPreference(screen); - mAllAppPref = screen.findPreference(KEY_ALL_APP_INFO); mDivider = screen.findPreference(KEY_DIVIDER); mRecentAppsPreference = (LayoutPreference) screen.findPreference(getPreferenceKey()); final View view = mRecentAppsPreference.findViewById(R.id.app_entities_header); @@ -157,26 +149,18 @@ public class RecentAppsPreferenceController extends BasePreferenceController @Override public void updateState(Preference preference) { super.updateState(preference); - // In order to improve launch time, we don't load data again at first launch. - if (!mIsFirstLaunch) { - reloadData(); - refreshUi(); - } + + refreshUi(); // Show total number of installed apps as See all's summary. new InstalledAppCounter(mContext, InstalledAppCounter.IGNORE_INSTALL_REASON, mContext.getPackageManager()) { @Override protected void onCountComplete(int num) { - if (mHasRecentApps) { - mAppEntitiesController.setHeaderDetails( - mContext.getString(R.string.see_all_apps_title, num)); - mAppEntitiesController.apply(); - } else { - mAllAppPref.setSummary(mContext.getString(R.string.apps_summary, num)); - } + mAppEntitiesController.setHeaderDetails( + mContext.getString(R.string.see_all_apps_title, num)); + mAppEntitiesController.apply(); } }.execute(); - mIsFirstLaunch = false; } @Override @@ -185,14 +169,16 @@ public class RecentAppsPreferenceController extends BasePreferenceController return Long.compare(b.getLastTimeUsed(), a.getLastTimeUsed()); } + List getRecentApps() { + return mRecentApps; + } + @VisibleForTesting void refreshUi() { if (mRecentApps != null && !mRecentApps.isEmpty()) { - mHasRecentApps = true; displayRecentApps(); } else { - mHasRecentApps = false; - displayOnlyAppInfo(); + mDivider.setVisible(false); } } @@ -209,13 +195,6 @@ public class RecentAppsPreferenceController extends BasePreferenceController updateDisplayableRecentAppList(); } - private void displayOnlyAppInfo() { - mDivider.setVisible(false); - mAllAppPref.setTitle(R.string.applications_settings); - mAllAppPref.setVisible(true); - mRecentAppsPreference.setVisible(false); - } - private void displayRecentApps() { int showAppsCount = 0; @@ -230,8 +209,6 @@ public class RecentAppsPreferenceController extends BasePreferenceController } } mAppEntitiesController.apply(); - mRecentAppsPreference.setVisible(true); - mAllAppPref.setVisible(false); mDivider.setVisible(true); } diff --git a/tests/robotests/src/com/android/settings/applications/AllAppsInfoPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/applications/AllAppsInfoPreferenceControllerTest.java new file mode 100644 index 00000000000..ec3cf657421 --- /dev/null +++ b/tests/robotests/src/com/android/settings/applications/AllAppsInfoPreferenceControllerTest.java @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2019 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.applications; + +import static com.android.settings.core.BasePreferenceController.AVAILABLE; +import static com.android.settings.core.BasePreferenceController.CONDITIONALLY_UNAVAILABLE; + +import static com.google.common.truth.Truth.assertThat; + +import android.app.usage.UsageStats; +import android.content.Context; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.RuntimeEnvironment; + +import java.util.ArrayList; +import java.util.List; + +@RunWith(RobolectricTestRunner.class) +public class AllAppsInfoPreferenceControllerTest { + + private AllAppsInfoPreferenceController mController; + + @Before + public void setUp() { + final Context context = RuntimeEnvironment.application; + mController = new AllAppsInfoPreferenceController(context, "test_key"); + } + + @Test + public void getAvailabilityStatus_hasRecentApps_shouldReturnConditionallyUnavailable() { + final List stats = new ArrayList<>(); + final UsageStats stat1 = new UsageStats(); + stat1.mLastTimeUsed = System.currentTimeMillis(); + stat1.mPackageName = "pkg.class"; + stats.add(stat1); + mController.setRecentApps(stats); + + assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE); + } + + @Test + public void getAvailabilityStatus_noRecentApps_shouldReturnAvailable() { + // No data + assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE); + } +} diff --git a/tests/robotests/src/com/android/settings/applications/RecentAppsPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/applications/RecentAppsPreferenceControllerTest.java index e2a16579ad4..1a28f37548f 100644 --- a/tests/robotests/src/com/android/settings/applications/RecentAppsPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/applications/RecentAppsPreferenceControllerTest.java @@ -18,6 +18,7 @@ package com.android.settings.applications; import static com.android.settings.core.BasePreferenceController.AVAILABLE; import static com.android.settings.core.BasePreferenceController.AVAILABLE_UNSEARCHABLE; +import static com.android.settings.core.BasePreferenceController.CONDITIONALLY_UNAVAILABLE; import static com.google.common.truth.Truth.assertThat; @@ -111,7 +112,6 @@ public class RecentAppsPreferenceControllerTest { final View appEntitiesHeaderView = LayoutInflater.from(context).inflate( R.layout.app_entities_header, null /* root */); - final Preference seeAllPreference = new Preference(context); final Preference dividerPreference = new Preference(context); mRecentAppsPreference = spy(new LayoutPreference(context, appEntitiesHeaderView)); @@ -119,11 +119,8 @@ public class RecentAppsPreferenceControllerTest { mController.setFragment(mFragment); mController.mAppEntitiesController = mock(AppEntitiesHeaderController.class); mController.mRecentAppsPreference = mRecentAppsPreference; - mController.mAllAppPref = seeAllPreference; mController.mDivider = dividerPreference; - when(mScreen.findPreference(RecentAppsPreferenceController.KEY_ALL_APP_INFO)) - .thenReturn(seeAllPreference); when(mScreen.findPreference(RecentAppsPreferenceController.KEY_DIVIDER)) .thenReturn(dividerPreference); when(mScreen.findPreference("test_key")).thenReturn(mRecentAppsPreference); @@ -152,9 +149,33 @@ public class RecentAppsPreferenceControllerTest { } @Test - public void getAvailabilityStatus_noRecentApps_shouldReturnAvailableUnsearchable() { + public void getAvailabilityStatus_noRecentApps_shouldReturnConditionallyUnavailable() { // No data - assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE_UNSEARCHABLE); + assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE); + } + + @Test + public void getAvailabilityStatus_powerSaverModeOn_shouldReturnConditionallyUnavailable() { + when(mPowerManager.isPowerSaveMode()).thenReturn(true); + + final List stats = new ArrayList<>(); + final UsageStats stat1 = new UsageStats(); + + stat1.mLastTimeUsed = System.currentTimeMillis(); + stat1.mPackageName = "pkg.class"; + stats.add(stat1); + + // stat1, stat2 are valid apps. stat3 is invalid. + when(mAppState.getEntry(stat1.mPackageName, UserHandle.myUserId())) + .thenReturn(mAppEntry); + when(mPackageManager.resolveActivity(any(Intent.class), anyInt())) + .thenReturn(new ResolveInfo()); + when(mUsageStatsManager.queryUsageStats(anyInt(), anyLong(), anyLong())) + .thenReturn(stats); + mAppEntry.info = mApplicationInfo; + mController.reloadData(); + + assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE); } @Test @@ -178,25 +199,6 @@ public class RecentAppsPreferenceControllerTest { assertThat(mController.mAppEntitiesController).isNotNull(); } - @Test - public void updateState_firstLaunch_shouldNotReloadData() { - mController.mIsFirstLaunch = true; - - mController.updateState(mRecentAppsPreference); - - verify(mController, never()).reloadData(); - } - - @Test - public void updateState_afterFirstLaunch_shouldReloadDataAndRefreshUi() { - mController.mIsFirstLaunch = false; - - mController.updateState(mRecentAppsPreference); - - verify(mController).reloadData(); - verify(mController).refreshUi(); - } - @Test public void updateState_threeValidRecentOpenAppsSet_setAppEntityThreeTime() { final List stats = new ArrayList<>(); @@ -227,7 +229,7 @@ public class RecentAppsPreferenceControllerTest { when(mUsageStatsManager.queryUsageStats(anyInt(), anyLong(), anyLong())) .thenReturn(stats); mAppEntry.info = mApplicationInfo; - mController.mIsFirstLaunch = false; + mController.reloadData(); mController.updateState(mRecentAppsPreference); @@ -235,7 +237,6 @@ public class RecentAppsPreferenceControllerTest { .setAppEntity(anyInt(), any(AppEntityInfo.class)); assertThat(mController.mRecentAppsPreference.isVisible()).isTrue(); assertThat(mController.mDivider.isVisible()).isTrue(); - assertThat(mController.mAllAppPref.isVisible()).isFalse(); } @Test @@ -268,7 +269,7 @@ public class RecentAppsPreferenceControllerTest { when(mUsageStatsManager.queryUsageStats(anyInt(), anyLong(), anyLong())) .thenReturn(stats); mAppEntry.info = mApplicationInfo; - mController.mIsFirstLaunch = false; + mController.reloadData(); mController.updateState(mRecentAppsPreference); @@ -278,35 +279,6 @@ public class RecentAppsPreferenceControllerTest { .setAppEntity(anyInt(), any(AppEntityInfo.class)); assertThat(mController.mRecentAppsPreference.isVisible()).isTrue(); assertThat(mController.mDivider.isVisible()).isTrue(); - assertThat(mController.mAllAppPref.isVisible()).isFalse(); - } - - @Test - public void updateState_powerSaverModeOn_headerIsNotVisible() { - when(mPowerManager.isPowerSaveMode()).thenReturn(true); - - final List stats = new ArrayList<>(); - final UsageStats stat1 = new UsageStats(); - - stat1.mLastTimeUsed = System.currentTimeMillis(); - stat1.mPackageName = "pkg.class"; - stats.add(stat1); - - // stat1, stat2 are valid apps. stat3 is invalid. - when(mAppState.getEntry(stat1.mPackageName, UserHandle.myUserId())) - .thenReturn(mAppEntry); - when(mPackageManager.resolveActivity(any(Intent.class), anyInt())) - .thenReturn(new ResolveInfo()); - when(mUsageStatsManager.queryUsageStats(anyInt(), anyLong(), anyLong())) - .thenReturn(stats); - mAppEntry.info = mApplicationInfo; - mController.mIsFirstLaunch = false; - - mController.updateState(mRecentAppsPreference); - - assertThat(mController.mRecentAppsPreference.isVisible()).isFalse(); - assertThat(mController.mDivider.isVisible()).isFalse(); - assertThat(mController.mAllAppPref.isVisible()).isTrue(); } @Test @@ -341,7 +313,7 @@ public class RecentAppsPreferenceControllerTest { // Make sure stat2 is considered an instant app. ReflectionHelpers.setStaticField(AppUtils.class, "sInstantAppDataProvider", (InstantAppDataProvider) (ApplicationInfo info) -> info == stat2Entry.info); - mController.mIsFirstLaunch = false; + mController.reloadData(); mController.updateState(mRecentAppsPreference); @@ -417,7 +389,7 @@ public class RecentAppsPreferenceControllerTest { .thenReturn(new ResolveInfo()); when(mUsageStatsManager.queryUsageStats(anyInt(), anyLong(), anyLong())) .thenReturn(stats); - mController.mIsFirstLaunch = false; + mController.reloadData(); mController.updateState(mRecentAppsPreference);