Merge "Cache mechanism for Storage page" into tm-dev
diff --git a/src/com/android/settings/deviceinfo/StorageDashboardFragment.java b/src/com/android/settings/deviceinfo/StorageDashboardFragment.java
index 746d234..cf31724 100644
--- a/src/com/android/settings/deviceinfo/StorageDashboardFragment.java
+++ b/src/com/android/settings/deviceinfo/StorageDashboardFragment.java
@@ -47,6 +47,7 @@
 import com.android.settings.deviceinfo.storage.DiskInitFragment;
 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.StorageSelectionPreferenceController;
@@ -109,6 +110,8 @@
     private boolean mIsWorkProfile;
     private int mUserId;
     private Preference mFreeUpSpacePreference;
+    private boolean mIsLoadedFromCache;
+    private StorageCacheHelper mStorageCacheHelper;
 
     private final StorageEventListener mStorageEventListener = new StorageEventListener() {
         @Override
@@ -239,15 +242,27 @@
             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);
-
+            // Hide the loading spinner if there is cached data.
+            if (mStorageCacheHelper.hasCachedSizeInfo()) {
+                //TODO(b/220259287): apply cache mechanism to secondary user
+                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);
             getLoaderManager()
@@ -277,6 +292,16 @@
 
         initializePreference();
         initializeOptionsMenu(activity);
+
+        if (mStorageCacheHelper.hasCachedSizeInfo()) {
+            mIsLoadedFromCache = true;
+            mStorageEntries.clear();
+            mStorageEntries.addAll(
+                    StorageUtils.getAllStorageEntries(getContext(), mStorageManager));
+            refreshUi();
+            updateSecondaryUserControllers(mSecondaryUsers, mAppsResult);
+            setSecondaryUsersVisible(true);
+        }
     }
 
     private void initializePreference() {
@@ -291,6 +316,7 @@
         mUserManager = context.getSystemService(UserManager.class);
         mIsWorkProfile = false;
         mUserId = UserHandle.myUserId();
+        mStorageCacheHelper = new StorageCacheHelper(getContext(), mUserId);
 
         super.onAttach(context);
         use(AutomaticStorageManagementSwitchPreferenceController.class).setFragmentManager(
@@ -323,9 +349,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);
     }
 
@@ -333,6 +364,11 @@
     public void onPause() {
         super.onPause();
         mStorageManager.unregisterListener(mStorageEventListener);
+        // 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
@@ -359,6 +395,8 @@
         mPreferenceController.setVolume(mSelectedStorageEntry.getVolumeInfo());
         mPreferenceController.setUsedSize(privateUsedBytes);
         mPreferenceController.setTotalSize(mStorageInfo.totalBytes);
+        // Cache total size and used size
+        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) {
diff --git a/src/com/android/settings/deviceinfo/StorageItemPreference.java b/src/com/android/settings/deviceinfo/StorageItemPreference.java
index 934ff3f..d3549d4 100644
--- a/src/com/android/settings/deviceinfo/StorageItemPreference.java
+++ b/src/com/android/settings/deviceinfo/StorageItemPreference.java
@@ -66,7 +66,7 @@
             return;
 
         mProgressBar.setMax(PROGRESS_MAX);
-        mProgressBar.setProgress(mProgressPercent);
+        mProgressBar.setProgress(mProgressPercent, true /* animate */);
     }
 
     @Override
diff --git a/src/com/android/settings/deviceinfo/storage/SecondaryUserController.java b/src/com/android/settings/deviceinfo/storage/SecondaryUserController.java
index f87a06a..84cafd4 100644
--- a/src/com/android/settings/deviceinfo/storage/SecondaryUserController.java
+++ b/src/com/android/settings/deviceinfo/storage/SecondaryUserController.java
@@ -183,6 +183,9 @@
 
     @Override
     public void handleResult(SparseArray<StorageAsyncLoader.StorageResult> stats) {
+        if (stats == null) {
+            return;
+        }
         final StorageAsyncLoader.StorageResult result = stats.get(getUser().id);
         if (result != null) {
             setSize(result.externalStats.totalBytes);
diff --git a/src/com/android/settings/deviceinfo/storage/StorageCacheHelper.java b/src/com/android/settings/deviceinfo/storage/StorageCacheHelper.java
new file mode 100644
index 0000000..a868c9f
--- /dev/null
+++ b/src/com/android/settings/deviceinfo/storage/StorageCacheHelper.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2022 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.deviceinfo.storage;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+
+/**
+ * A utility class to cache and restore the storage size information.
+ */
+public class StorageCacheHelper {
+
+    private static final String SHARED_PREFERENCE_NAME = "StorageCache";
+    private static final String TOTAL_SIZE_KEY = "total_size_key";
+    private static final String USED_SIZE_KEY = "used_size_key";
+    private static final String IMAGES_SIZE_KEY = "images_size_key";
+    private static final String VIDEOS_SIZE_KEY = "videos_size_key";
+    private static final String AUDIO_SIZE_KEY = "audio_size_key";
+    private static final String APPS_SIZE_KEY = "apps_size_key";
+    private static final String GAMES_SIZE_KEY = "games_size_key";
+    private static final String DOCUMENTS_AND_OTHER_SIZE_KEY = "documents_and_other_size_key";
+    private static final String TRASH_SIZE_KEY = "trash_size_key";
+    private static final String SYSTEM_SIZE_KEY = "system_size_key";
+
+    private final SharedPreferences mSharedPreferences;
+
+    public StorageCacheHelper(Context context, int userId) {
+        String sharedPrefName = SHARED_PREFERENCE_NAME + userId;
+        mSharedPreferences = context.getSharedPreferences(sharedPrefName, Context.MODE_PRIVATE);
+    }
+
+    /**
+     * Returns true if there's a cached size info.
+     */
+    public boolean hasCachedSizeInfo() {
+        return mSharedPreferences.getAll().size() > 0;
+    }
+
+    /**
+     * Cache the size info
+     * @param data a data about the file size info.
+     */
+    public void cacheSizeInfo(StorageCache data) {
+        mSharedPreferences
+                .edit()
+                .putLong(IMAGES_SIZE_KEY, data.imagesSize)
+                .putLong(VIDEOS_SIZE_KEY, data.videosSize)
+                .putLong(AUDIO_SIZE_KEY, data.audioSize)
+                .putLong(APPS_SIZE_KEY, data.allAppsExceptGamesSize)
+                .putLong(GAMES_SIZE_KEY, data.gamesSize)
+                .putLong(DOCUMENTS_AND_OTHER_SIZE_KEY, data.documentsAndOtherSize)
+                .putLong(TRASH_SIZE_KEY, data.trashSize)
+                .putLong(SYSTEM_SIZE_KEY, data.systemSize)
+                .apply();
+    }
+
+    /**
+     * Cache total size and used size
+     */
+    public void cacheTotalSizeAndUsedSize(long totalSize, long usedSize) {
+        mSharedPreferences
+                .edit()
+                .putLong(TOTAL_SIZE_KEY, totalSize)
+                .putLong(USED_SIZE_KEY, usedSize)
+                .apply();
+    }
+
+    /**
+     * Returns a cached data about all file size information.
+     */
+    public StorageCache retrieveCachedSize() {
+        StorageCache result = new StorageCache();
+        result.totalSize = mSharedPreferences.getLong(TOTAL_SIZE_KEY, 0);
+        result.usedSize = mSharedPreferences.getLong(USED_SIZE_KEY, 0);
+        result.imagesSize = mSharedPreferences.getLong(IMAGES_SIZE_KEY, 0);
+        result.videosSize = mSharedPreferences.getLong(VIDEOS_SIZE_KEY, 0);
+        result.audioSize = mSharedPreferences.getLong(AUDIO_SIZE_KEY, 0);
+        result.allAppsExceptGamesSize = mSharedPreferences.getLong(APPS_SIZE_KEY, 0);
+        result.gamesSize = mSharedPreferences.getLong(GAMES_SIZE_KEY, 0);
+        result.documentsAndOtherSize = mSharedPreferences.getLong(DOCUMENTS_AND_OTHER_SIZE_KEY, 0);
+        result.trashSize = mSharedPreferences.getLong(TRASH_SIZE_KEY, 0);
+        result.systemSize = mSharedPreferences.getLong(SYSTEM_SIZE_KEY, 0);
+        return result;
+    }
+
+    /**
+     *  All the cached data about the file size information.
+     */
+    public static class StorageCache {
+        public long totalSize;
+        public long usedSize;
+        public long gamesSize;
+        public long allAppsExceptGamesSize;
+        public long audioSize;
+        public long imagesSize;
+        public long videosSize;
+        public long documentsAndOtherSize;
+        public long trashSize;
+        public long systemSize;
+    }
+}
diff --git a/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceController.java b/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceController.java
index ee0c9e7..9813439 100644
--- a/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceController.java
+++ b/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceController.java
@@ -34,6 +34,7 @@
 import android.util.SparseArray;
 import android.widget.Toast;
 
+import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
 import androidx.fragment.app.Fragment;
 import androidx.preference.Preference;
@@ -135,7 +136,11 @@
 
     private boolean mIsWorkProfile;
 
-    private static final String AUTHORITY_MEDIA = "com.android.providers.media.documents";
+    private StorageCacheHelper mStorageCacheHelper;
+    // The mIsDocumentsPrefShown being used here is to prevent a flicker problem from displaying
+    // the Document entry.
+    private boolean mIsDocumentsPrefShown;
+    private boolean mIsPreferenceOrderedBySize;
 
     public StorageItemPreferenceController(Context context, Fragment hostFragment,
             VolumeInfo volume, StorageVolumeProvider svp, boolean isWorkProfile) {
@@ -148,6 +153,8 @@
         mIsWorkProfile = isWorkProfile;
         mMetricsFeatureProvider = FeatureFactory.getFactory(context).getMetricsFeatureProvider();
         mUserId = getCurrentUserId();
+        mIsDocumentsPrefShown = isDocumentsPrefShown();
+        mStorageCacheHelper = new StorageCacheHelper(mContext, mUserId);
 
         mImagesUri = Uri.parse(context.getResources()
                 .getString(R.string.config_images_storage_category_uri));
@@ -267,14 +274,17 @@
         // If we don't have a shared volume for our internal storage (or the shared volume isn't
         // mounted as readable for whatever reason), we should hide the File preference.
         if (visible) {
-            final VolumeInfo sharedVolume = mSvp.findEmulatedForPrivate(mVolume);
-            mDocumentsAndOtherPreference.setVisible(sharedVolume != null
-                    && sharedVolume.isMountedReadable());
+            mDocumentsAndOtherPreference.setVisible(mIsDocumentsPrefShown);
         } else {
             mDocumentsAndOtherPreference.setVisible(false);
         }
     }
 
+    private boolean isDocumentsPrefShown() {
+        VolumeInfo sharedVolume = mSvp.findEmulatedForPrivate(mVolume);
+        return sharedVolume != null && sharedVolume.isMountedReadable();
+    }
+
     private void updatePrivateStorageCategoryPreferencesOrder() {
         if (mScreen == null || !isValidPrivateVolume()) {
             return;
@@ -360,44 +370,74 @@
         mTrashPreference = screen.findPreference(TRASH_KEY);
     }
 
-    /** Fragments use it to set storage result and update UI of this controller. */
-    public void onLoadFinished(SparseArray<StorageAsyncLoader.StorageResult> result, int userId) {
-        final StorageAsyncLoader.StorageResult data = result.get(userId);
-
-        mImagesPreference.setStorageSize(data.imagesSize, mTotalSize);
-        mVideosPreference.setStorageSize(data.videosSize, mTotalSize);
-        mAudioPreference.setStorageSize(data.audioSize, mTotalSize);
-        mAppsPreference.setStorageSize(data.allAppsExceptGamesSize, mTotalSize);
-        mGamesPreference.setStorageSize(data.gamesSize, mTotalSize);
-        mDocumentsAndOtherPreference.setStorageSize(data.documentsAndOtherSize, mTotalSize);
-        mTrashPreference.setStorageSize(data.trashSize, mTotalSize);
-
+    /**
+     * Fragments use it to set storage result and update UI of this controller.
+     * @param result The StorageResult from StorageAsyncLoader. This allows a nullable result.
+     *               When it's null, the cached storage size info will be used instead.
+     * @param userId User ID to get the storage size info
+     */
+    public void onLoadFinished(@Nullable SparseArray<StorageAsyncLoader.StorageResult> result,
+            int userId) {
+        // Calculate the size info for each category
+        StorageCacheHelper.StorageCache storageCache = getSizeInfo(result, userId);
+        // Set size info to each preference
+        mImagesPreference.setStorageSize(storageCache.imagesSize, mTotalSize);
+        mVideosPreference.setStorageSize(storageCache.videosSize, mTotalSize);
+        mAudioPreference.setStorageSize(storageCache.audioSize, mTotalSize);
+        mAppsPreference.setStorageSize(storageCache.allAppsExceptGamesSize, mTotalSize);
+        mGamesPreference.setStorageSize(storageCache.gamesSize, mTotalSize);
+        mDocumentsAndOtherPreference.setStorageSize(storageCache.documentsAndOtherSize, mTotalSize);
+        mTrashPreference.setStorageSize(storageCache.trashSize, mTotalSize);
         if (mSystemPreference != null) {
-            // Everything else that hasn't already been attributed is tracked as
-            // belonging to system.
-            long attributedSize = 0;
-            for (int i = 0; i < result.size(); i++) {
-                final StorageAsyncLoader.StorageResult otherData = result.valueAt(i);
-                attributedSize +=
-                        otherData.gamesSize
-                                + otherData.audioSize
-                                + otherData.videosSize
-                                + otherData.imagesSize
-                                + otherData.documentsAndOtherSize
-                                + otherData.trashSize
-                                + otherData.allAppsExceptGamesSize;
-                attributedSize -= otherData.duplicateCodeSize;
-            }
-
-            final long systemSize = Math.max(DataUnit.GIBIBYTES.toBytes(1),
-                    mUsedBytes - attributedSize);
-            mSystemPreference.setStorageSize(systemSize, mTotalSize);
+            mSystemPreference.setStorageSize(storageCache.systemSize, mTotalSize);
+        }
+        // Cache the size info
+        if (result != null) {
+            mStorageCacheHelper.cacheSizeInfo(storageCache);
         }
 
-        updatePrivateStorageCategoryPreferencesOrder();
+        // Sort the preference according to size info in descending order
+        if (!mIsPreferenceOrderedBySize) {
+            updatePrivateStorageCategoryPreferencesOrder();
+            mIsPreferenceOrderedBySize = true;
+        }
         setPrivateStorageCategoryPreferencesVisibility(true);
     }
 
+    private StorageCacheHelper.StorageCache getSizeInfo(
+            SparseArray<StorageAsyncLoader.StorageResult> result, int userId) {
+        if (result == null) {
+            return mStorageCacheHelper.retrieveCachedSize();
+        }
+        StorageAsyncLoader.StorageResult data = result.get(userId);
+        StorageCacheHelper.StorageCache storageCache = new StorageCacheHelper.StorageCache();
+        storageCache.imagesSize = data.imagesSize;
+        storageCache.videosSize = data.videosSize;
+        storageCache.audioSize = data.audioSize;
+        storageCache.allAppsExceptGamesSize = data.allAppsExceptGamesSize;
+        storageCache.gamesSize = data.gamesSize;
+        storageCache.documentsAndOtherSize = data.documentsAndOtherSize;
+        storageCache.trashSize = data.trashSize;
+        // Everything else that hasn't already been attributed is tracked as
+        // belonging to system.
+        long attributedSize = 0;
+        for (int i = 0; i < result.size(); i++) {
+            final StorageAsyncLoader.StorageResult otherData = result.valueAt(i);
+            attributedSize +=
+                    otherData.gamesSize
+                            + otherData.audioSize
+                            + otherData.videosSize
+                            + otherData.imagesSize
+                            + otherData.documentsAndOtherSize
+                            + otherData.trashSize
+                            + otherData.allAppsExceptGamesSize;
+            attributedSize -= otherData.duplicateCodeSize;
+        }
+        storageCache.systemSize = Math.max(DataUnit.GIBIBYTES.toBytes(1),
+                mUsedBytes - attributedSize);
+        return storageCache;
+    }
+
     public void setUsedSize(long usedSizeBytes) {
         mUsedBytes = usedSizeBytes;
     }
diff --git a/src/com/android/settings/deviceinfo/storage/StorageUsageProgressBarPreferenceController.java b/src/com/android/settings/deviceinfo/storage/StorageUsageProgressBarPreferenceController.java
index 7660353..872fa8a 100644
--- a/src/com/android/settings/deviceinfo/storage/StorageUsageProgressBarPreferenceController.java
+++ b/src/com/android/settings/deviceinfo/storage/StorageUsageProgressBarPreferenceController.java
@@ -18,6 +18,7 @@
 
 import android.app.usage.StorageStatsManager;
 import android.content.Context;
+import android.os.UserHandle;
 import android.util.Log;
 
 import androidx.annotation.VisibleForTesting;
@@ -47,11 +48,13 @@
     private UsageProgressBarPreference mUsageProgressBarPreference;
     private StorageEntry mStorageEntry;
     boolean mIsUpdateStateFromSelectedStorageEntry;
+    private StorageCacheHelper mStorageCacheHelper;
 
     public StorageUsageProgressBarPreferenceController(Context context, String key) {
         super(context, key);
 
         mStorageStatsManager = context.getSystemService(StorageStatsManager.class);
+        mStorageCacheHelper = new StorageCacheHelper(context, UserHandle.myUserId());
     }
 
     /** Set StorageEntry to display. */
@@ -71,6 +74,15 @@
     }
 
     private void getStorageStatsAndUpdateUi() {
+        // Use cached data for both total size and used size.
+        if (mStorageEntry != null && mStorageEntry.isMounted() && mStorageEntry.isPrivate()) {
+            StorageCacheHelper.StorageCache cachedData = mStorageCacheHelper.retrieveCachedSize();
+            mTotalBytes = cachedData.totalSize;
+            mUsedBytes = cachedData.usedSize;
+            mIsUpdateStateFromSelectedStorageEntry = true;
+            updateState(mUsageProgressBarPreference);
+        }
+        // Get the latest data from StorageStatsManager.
         ThreadUtils.postOnBackgroundThread(() -> {
             try {
                 if (mStorageEntry == null || !mStorageEntry.isMounted()) {
diff --git a/tests/robotests/src/com/android/settings/deviceinfo/storage/StorageCacheHelperTest.java b/tests/robotests/src/com/android/settings/deviceinfo/storage/StorageCacheHelperTest.java
new file mode 100644
index 0000000..1956b09
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/deviceinfo/storage/StorageCacheHelperTest.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2022 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.deviceinfo.storage;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+import android.os.UserHandle;
+
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class StorageCacheHelperTest {
+    private static final long FAKE_IMAGES_SIZE = 7000L;
+    private static final long FAKE_VIDEOS_SIZE = 8900L;
+    private static final long FAKE_AUDIO_SIZE = 3500L;
+    private static final long FAKE_APPS_SIZE = 4000L;
+    private static final long FAKE_GAMES_SIZE = 5000L;
+    private static final long FAKE_DOCS_SIZE = 1500L;
+    private static final long FAKE_TRASH_SIZE = 500L;
+    private static final long FAKE_SYSTEM_SIZE = 2300L;
+    private static final long FAKE_TOTAL_SIZE = 256000L;
+    private static final long FAKE_USED_SIZE = 50000L;
+
+    private Context mContext;
+    private StorageCacheHelper mHelper;
+
+    @Before
+    public void setUp() {
+        mContext = ApplicationProvider.getApplicationContext();
+        mHelper = new StorageCacheHelper(mContext, UserHandle.myUserId());
+    }
+
+    @Test
+    public void hasCachedSizeInfo_noCacheData_shouldReturnFalse() {
+        assertThat(mHelper.hasCachedSizeInfo()).isFalse();
+    }
+
+    @Test
+    public void hasCachedSizeInfo_hasCacheData_shouldReturnTrue() {
+        mHelper.cacheSizeInfo(getFakeStorageCache());
+
+        assertThat(mHelper.hasCachedSizeInfo()).isTrue();
+    }
+
+    @Test
+    public void cacheSizeInfo_shouldSaveToSharedPreference() {
+        mHelper.cacheSizeInfo(getFakeStorageCache());
+
+        StorageCacheHelper.StorageCache storageCache = mHelper.retrieveCachedSize();
+
+        assertThat(storageCache.imagesSize).isEqualTo(FAKE_IMAGES_SIZE);
+        assertThat(storageCache.totalSize).isEqualTo(0);
+    }
+
+    @Test
+    public void cacheTotalSizeAndUsedSize_shouldSaveToSharedPreference() {
+        mHelper.cacheTotalSizeAndUsedSize(FAKE_TOTAL_SIZE, FAKE_USED_SIZE);
+
+        StorageCacheHelper.StorageCache storageCache = mHelper.retrieveCachedSize();
+
+        assertThat(storageCache.totalSize).isEqualTo(FAKE_TOTAL_SIZE);
+        assertThat(storageCache.usedSize).isEqualTo(FAKE_USED_SIZE);
+    }
+
+    private StorageCacheHelper.StorageCache getFakeStorageCache() {
+        StorageCacheHelper.StorageCache result = new StorageCacheHelper.StorageCache();
+        result.trashSize = FAKE_TRASH_SIZE;
+        result.systemSize = FAKE_SYSTEM_SIZE;
+        result.imagesSize = FAKE_IMAGES_SIZE;
+        result.documentsAndOtherSize = FAKE_DOCS_SIZE;
+        result.audioSize = FAKE_AUDIO_SIZE;
+        result.gamesSize = FAKE_GAMES_SIZE;
+        result.videosSize = FAKE_VIDEOS_SIZE;
+        result.allAppsExceptGamesSize = FAKE_APPS_SIZE;
+        return result;
+    }
+}