Cache mechanism for Storage page with work profile

Apply a cache mechanism to prevent the flicker problem from entering
Storage page.

Bug: 191117970
Test: manual test
1) Create a work profile with TestDPC
2) The loading spinner will be shown when entering Storage page after
   the first boot.
3) Back to Settings homepage and switch back to Storage page, the
   loading spinner shouldn't be shown.
4) The preference order shouldn't be updated after changing the storage
   size.

Change-Id: I518679f90c63e12f61f08d08d5ed3f3900825be2
Merged-In: I518679f90c63e12f61f08d08d5ed3f3900825be2
(cherry picked from commit cda892df85162b154e9fbc3f11df45adae08511e)
diff --git a/src/com/android/settings/dashboard/profileselector/ProfileSelectStorageFragment.java b/src/com/android/settings/dashboard/profileselector/ProfileSelectStorageFragment.java
index c4ff91b..57988c5 100644
--- a/src/com/android/settings/dashboard/profileselector/ProfileSelectStorageFragment.java
+++ b/src/com/android/settings/dashboard/profileselector/ProfileSelectStorageFragment.java
@@ -20,6 +20,7 @@
 import android.app.settings.SettingsEnums;
 import android.content.Context;
 import android.os.Bundle;
+import android.os.UserHandle;
 import android.os.storage.DiskInfo;
 import android.os.storage.StorageEventListener;
 import android.os.storage.StorageManager;
@@ -36,6 +37,7 @@
 import com.android.settings.deviceinfo.VolumeOptionMenuController;
 import com.android.settings.deviceinfo.storage.AutomaticStorageManagementSwitchPreferenceController;
 import com.android.settings.deviceinfo.storage.DiskInitFragment;
+import com.android.settings.deviceinfo.storage.StorageCacheHelper;
 import com.android.settings.deviceinfo.storage.StorageEntry;
 import com.android.settings.deviceinfo.storage.StorageSelectionPreferenceController;
 import com.android.settings.deviceinfo.storage.StorageUsageProgressBarPreferenceController;
@@ -71,6 +73,8 @@
     private StorageSelectionPreferenceController mStorageSelectionController;
     private StorageUsageProgressBarPreferenceController mStorageUsageProgressBarController;
     private VolumeOptionMenuController mOptionMenuController;
+    private boolean mIsLoadedFromCache;
+    private StorageCacheHelper mStorageCacheHelper;
 
     private final StorageEventListener mStorageEventListener = new StorageEventListener() {
         @Override
@@ -246,11 +250,20 @@
         }
 
         initializeOptionsMenu(activity);
+
+        if (mStorageCacheHelper.hasCachedSizeInfo()) {
+            mIsLoadedFromCache = true;
+            mStorageEntries.clear();
+            mStorageEntries.addAll(
+                    StorageUtils.getAllStorageEntries(getContext(), mStorageManager));
+            refreshUi();
+        }
     }
 
     @Override
     public void onAttach(Context context) {
         super.onAttach(context);
+        mStorageCacheHelper = new StorageCacheHelper(getContext(), UserHandle.myUserId());
         use(AutomaticStorageManagementSwitchPreferenceController.class).setFragmentManager(
                 getFragmentManager());
         mStorageSelectionController = use(StorageSelectionPreferenceController.class);
@@ -281,9 +294,14 @@
     public void onResume() {
         super.onResume();
 
-        mStorageEntries.clear();
-        mStorageEntries.addAll(StorageUtils.getAllStorageEntries(getContext(), mStorageManager));
-        refreshUi();
+        if (mIsLoadedFromCache) {
+            mIsLoadedFromCache = false;
+        } else {
+            mStorageEntries.clear();
+            mStorageEntries.addAll(
+                    StorageUtils.getAllStorageEntries(getContext(), mStorageManager));
+            refreshUi();
+        }
         mStorageManager.registerListener(mStorageEventListener);
     }
 
diff --git a/src/com/android/settings/deviceinfo/StorageCategoryFragment.java b/src/com/android/settings/deviceinfo/StorageCategoryFragment.java
index c851987..efdd165 100644
--- a/src/com/android/settings/deviceinfo/StorageCategoryFragment.java
+++ b/src/com/android/settings/deviceinfo/StorageCategoryFragment.java
@@ -39,6 +39,7 @@
 import com.android.settings.dashboard.profileselector.ProfileSelectFragment;
 import com.android.settings.deviceinfo.storage.SecondaryUserController;
 import com.android.settings.deviceinfo.storage.StorageAsyncLoader;
+import com.android.settings.deviceinfo.storage.StorageCacheHelper;
 import com.android.settings.deviceinfo.storage.StorageEntry;
 import com.android.settings.deviceinfo.storage.StorageItemPreferenceController;
 import com.android.settings.deviceinfo.storage.UserIconLoader;
@@ -90,6 +91,8 @@
     private boolean mIsWorkProfile;
     private int mUserId;
     private Preference mFreeUpSpacePreference;
+    private boolean mIsLoadedFromCache;
+    private StorageCacheHelper mStorageCacheHelper;
 
     /**
      * Refresh UI for specified storageEntry.
@@ -111,14 +114,23 @@
             mPreferenceController.setVolume(null);
             return;
         }
+        if (mStorageCacheHelper.hasCachedSizeInfo() && mSelectedStorageEntry.isPrivate()) {
+            StorageCacheHelper.StorageCache cachedData = mStorageCacheHelper.retrieveCachedSize();
+            mPreferenceController.setVolume(mSelectedStorageEntry.getVolumeInfo());
+            mPreferenceController.setUsedSize(cachedData.usedSize);
+            mPreferenceController.setTotalSize(cachedData.totalSize);
+        }
         if (mSelectedStorageEntry.isPrivate()) {
             mStorageInfo = null;
             mAppsResult = null;
-            maybeSetLoading(isQuotaSupported());
-
-            // To prevent flicker, sets null volume to hide category preferences.
-            // onReceivedSizes will setVolume with the volume of selected storage.
-            mPreferenceController.setVolume(null);
+            if (mStorageCacheHelper.hasCachedSizeInfo()) {
+                mPreferenceController.onLoadFinished(mAppsResult, mUserId);
+            } else {
+                maybeSetLoading(isQuotaSupported());
+                // To prevent flicker, sets null volume to hide category preferences.
+                // onReceivedSizes will setVolume with the volume of selected storage.
+                mPreferenceController.setVolume(null);
+            }
 
             // Stats data is only available on private volumes.
             getLoaderManager().restartLoader(STORAGE_JOB_ID, Bundle.EMPTY, this);
@@ -141,6 +153,15 @@
         }
 
         initializePreference();
+
+        if (mStorageCacheHelper.hasCachedSizeInfo()) {
+            mIsLoadedFromCache = true;
+            if (mSelectedStorageEntry != null) {
+                refreshUi(mSelectedStorageEntry);
+            }
+            updateSecondaryUserControllers(mSecondaryUsers, mAppsResult);
+            setSecondaryUsersVisible(true);
+        }
     }
 
     private void initializePreference() {
@@ -156,6 +177,7 @@
         mIsWorkProfile = getArguments().getInt(ProfileSelectFragment.EXTRA_PROFILE)
                 == ProfileSelectFragment.ProfileType.WORK;
         mUserId = Utils.getCurrentUserId(mUserManager, mIsWorkProfile);
+        mStorageCacheHelper = new StorageCacheHelper(getContext(), mUserId);
 
         super.onAttach(context);
     }
@@ -164,12 +186,26 @@
     public void onResume() {
         super.onResume();
 
-        if (mSelectedStorageEntry != null) {
-            refreshUi(mSelectedStorageEntry);
+        if (mIsLoadedFromCache) {
+            mIsLoadedFromCache = false;
+        } else {
+            if (mSelectedStorageEntry != null) {
+                refreshUi(mSelectedStorageEntry);
+            }
         }
     }
 
     @Override
+    public void onPause() {
+        super.onPause();
+        // Destroy the data loaders to prevent unnecessary data loading when switching back to the
+        // page.
+        getLoaderManager().destroyLoader(STORAGE_JOB_ID);
+        getLoaderManager().destroyLoader(ICON_JOB_ID);
+        getLoaderManager().destroyLoader(VOLUME_SIZE_JOB_ID);
+    }
+
+    @Override
     public void onSaveInstanceState(Bundle outState) {
         outState.putParcelable(SELECTED_STORAGE_ENTRY_KEY, mSelectedStorageEntry);
         super.onSaveInstanceState(outState);
@@ -188,6 +224,8 @@
         mPreferenceController.setVolume(mSelectedStorageEntry.getVolumeInfo());
         mPreferenceController.setUsedSize(privateUsedBytes);
         mPreferenceController.setTotalSize(mStorageInfo.totalBytes);
+        // Cache total size infor and used size info
+        mStorageCacheHelper.cacheTotalSizeAndUsedSize(mStorageInfo.totalBytes, privateUsedBytes);
         for (int i = 0, size = mSecondaryUsers.size(); i < size; i++) {
             final AbstractPreferenceController controller = mSecondaryUsers.get(i);
             if (controller instanceof SecondaryUserController) {