Merge "Improve launch time for Apps & notifications page"
diff --git a/src/com/android/settings/applications/RecentAppsPreferenceController.java b/src/com/android/settings/applications/RecentAppsPreferenceController.java
index fe52a8b..838d758 100644
--- a/src/com/android/settings/applications/RecentAppsPreferenceController.java
+++ b/src/com/android/settings/applications/RecentAppsPreferenceController.java
@@ -82,6 +82,8 @@
     Preference mAllAppPref;
     @VisibleForTesting
     Preference mDivider;
+    @VisibleForTesting
+    boolean mIsFirstLaunch;
 
     private final PackageManager mPm;
     private final UsageStatsManager mUsageStatsManager;
@@ -93,6 +95,7 @@
     private Fragment mHost;
     private Calendar mCal;
     private List<UsageStats> mStats;
+    private List<UsageStats> mRecentApps;
     private boolean mHasRecentApps;
 
     static {
@@ -115,6 +118,9 @@
         mIconDrawableFactory = IconDrawableFactory.newInstance(mContext);
         mPowerManager = mContext.getSystemService(PowerManager.class);
         mUsageStatsManager = mContext.getSystemService(UsageStatsManager.class);
+        mRecentApps = new ArrayList<>();
+        mIsFirstLaunch = true;
+        reloadData();
     }
 
     public void setFragment(Fragment fragment) {
@@ -123,8 +129,7 @@
 
     @Override
     public int getAvailabilityStatus() {
-        reloadData();
-        return getDisplayableRecentAppList().isEmpty() ? AVAILABLE_UNSEARCHABLE : AVAILABLE;
+        return mRecentApps.isEmpty() ? AVAILABLE_UNSEARCHABLE : AVAILABLE;
     }
 
     @Override
@@ -152,7 +157,11 @@
     @Override
     public void updateState(Preference preference) {
         super.updateState(preference);
-        refreshUi();
+        // In order to improve launch time, we don't load data again at first launch.
+        if (!mIsFirstLaunch) {
+            reloadData();
+            refreshUi();
+        }
         // Show total number of installed apps as See all's summary.
         new InstalledAppCounter(mContext, InstalledAppCounter.IGNORE_INSTALL_REASON,
                 mContext.getPackageManager()) {
@@ -167,6 +176,7 @@
                 }
             }
         }.execute();
+        mIsFirstLaunch = false;
     }
 
     @Override
@@ -177,11 +187,9 @@
 
     @VisibleForTesting
     void refreshUi() {
-        reloadData();
-        final List<UsageStats> recentApps = getDisplayableRecentAppList();
-        if (recentApps != null && !recentApps.isEmpty()) {
+        if (mRecentApps != null && !mRecentApps.isEmpty()) {
             mHasRecentApps = true;
-            displayRecentApps(recentApps);
+            displayRecentApps();
         } else {
             mHasRecentApps = false;
             displayOnlyAppInfo();
@@ -197,6 +205,8 @@
                 : mUsageStatsManager.queryUsageStats(
                         UsageStatsManager.INTERVAL_BEST, mCal.getTimeInMillis(),
                         System.currentTimeMillis());
+
+        updateDisplayableRecentAppList();
     }
 
     private void displayOnlyAppInfo() {
@@ -206,10 +216,10 @@
         mRecentAppsPreference.setVisible(false);
     }
 
-    private void displayRecentApps(List<UsageStats> recentApps) {
+    private void displayRecentApps() {
         int showAppsCount = 0;
 
-        for (UsageStats stat : recentApps) {
+        for (UsageStats stat : mRecentApps) {
             final AppEntityInfo appEntityInfoInfo = createAppEntity(stat);
             if (appEntityInfoInfo != null) {
                 mAppEntitiesController.setAppEntity(showAppsCount++, appEntityInfoInfo);
@@ -246,8 +256,8 @@
                 .build();
     }
 
-    private List<UsageStats> getDisplayableRecentAppList() {
-        final List<UsageStats> recentApps = new ArrayList<>();
+    private void updateDisplayableRecentAppList() {
+        mRecentApps.clear();
         final Map<String, UsageStats> map = new ArrayMap<>();
         final int statCount = mStats.size();
         for (int i = 0; i < statCount; i++) {
@@ -273,13 +283,12 @@
             if (appEntry == null) {
                 continue;
             }
-            recentApps.add(stat);
+            mRecentApps.add(stat);
             count++;
             if (count >= AppEntitiesHeaderController.MAXIMUM_APPS) {
                 break;
             }
         }
-        return recentApps;
     }
 
 
diff --git a/tests/robotests/src/com/android/settings/applications/RecentAppsPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/applications/RecentAppsPreferenceControllerTest.java
index 1411bc0..e2a1657 100644
--- a/tests/robotests/src/com/android/settings/applications/RecentAppsPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/applications/RecentAppsPreferenceControllerTest.java
@@ -25,9 +25,9 @@
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.argThat;
-import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
@@ -146,6 +146,7 @@
         when(mUsageStatsManager.queryUsageStats(anyInt(), anyLong(), anyLong()))
                 .thenReturn(stats);
         mAppEntry.info = mApplicationInfo;
+        mController.reloadData();
 
         assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
     }
@@ -157,13 +158,17 @@
     }
 
     @Test
-    public void displayPreferenceAndUpdateState_shouldRefreshUi() {
-        doNothing().when(mController).refreshUi();
-
+    public void displayPreference_shouldNotReloadData() {
         mController.displayPreference(mScreen);
-        mController.updateState(mScreen);
 
-        verify(mController, times(2)).refreshUi();
+        verify(mController, never()).reloadData();
+    }
+
+    @Test
+    public void displayPreference_shouldRefreshUi() {
+        mController.displayPreference(mScreen);
+
+        verify(mController).refreshUi();
     }
 
     @Test
@@ -174,6 +179,25 @@
     }
 
     @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<UsageStats> stats = new ArrayList<>();
         final UsageStats stat1 = new UsageStats();
@@ -203,6 +227,7 @@
         when(mUsageStatsManager.queryUsageStats(anyInt(), anyLong(), anyLong()))
                 .thenReturn(stats);
         mAppEntry.info = mApplicationInfo;
+        mController.mIsFirstLaunch = false;
 
         mController.updateState(mRecentAppsPreference);
 
@@ -243,6 +268,7 @@
         when(mUsageStatsManager.queryUsageStats(anyInt(), anyLong(), anyLong()))
                 .thenReturn(stats);
         mAppEntry.info = mApplicationInfo;
+        mController.mIsFirstLaunch = false;
 
         mController.updateState(mRecentAppsPreference);
 
@@ -274,6 +300,7 @@
         when(mUsageStatsManager.queryUsageStats(anyInt(), anyLong(), anyLong()))
                 .thenReturn(stats);
         mAppEntry.info = mApplicationInfo;
+        mController.mIsFirstLaunch = false;
 
         mController.updateState(mRecentAppsPreference);
 
@@ -314,6 +341,7 @@
         // Make sure stat2 is considered an instant app.
         ReflectionHelpers.setStaticField(AppUtils.class, "sInstantAppDataProvider",
                 (InstantAppDataProvider) (ApplicationInfo info) -> info == stat2Entry.info);
+        mController.mIsFirstLaunch = false;
 
         mController.updateState(mRecentAppsPreference);
 
@@ -389,6 +417,7 @@
                 .thenReturn(new ResolveInfo());
         when(mUsageStatsManager.queryUsageStats(anyInt(), anyLong(), anyLong()))
                 .thenReturn(stats);
+        mController.mIsFirstLaunch = false;
 
         mController.updateState(mRecentAppsPreference);