diff --git a/src/com/android/settings/deviceinfo/StorageDashboardFragment.java b/src/com/android/settings/deviceinfo/StorageDashboardFragment.java index 33d7d36b85c..dd0db9a2335 100644 --- a/src/com/android/settings/deviceinfo/StorageDashboardFragment.java +++ b/src/com/android/settings/deviceinfo/StorageDashboardFragment.java @@ -40,6 +40,7 @@ import com.android.settings.applications.UserManagerWrapper; import com.android.settings.applications.UserManagerWrapperImpl; import com.android.settings.dashboard.DashboardFragment; import com.android.settings.deviceinfo.storage.AutomaticStorageManagementSwitchPreferenceController; +import com.android.settings.deviceinfo.storage.CachedStorageValuesHelper; import com.android.settings.deviceinfo.storage.SecondaryUserController; import com.android.settings.deviceinfo.storage.StorageAsyncLoader; import com.android.settings.deviceinfo.storage.StorageItemPreferenceController; @@ -68,6 +69,7 @@ public class StorageDashboardFragment extends DashboardFragment private VolumeInfo mVolume; private PrivateStorageInfo mStorageInfo; private SparseArray mAppsResult; + private CachedStorageValuesHelper mCachedStorageValuesHelper; private StorageSummaryDonutPreferenceController mSummaryController; private StorageItemPreferenceController mPreferenceController; @@ -102,7 +104,10 @@ public class StorageDashboardFragment extends DashboardFragment @Override public void onViewCreated(View v, Bundle savedInstanceState) { super.onViewCreated(v, savedInstanceState); - setLoading(true, false); + initializeCacheProvider(); + if (mAppsResult == null || mStorageInfo == null) { + setLoading(true, false); + } } @Override @@ -249,6 +254,7 @@ public class StorageDashboardFragment extends DashboardFragment public void onLoadFinished(Loader> loader, SparseArray data) { mAppsResult = data; + maybeCacheFreshValues(); onReceivedSizes(); } @@ -256,6 +262,48 @@ public class StorageDashboardFragment extends DashboardFragment public void onLoaderReset(Loader> loader) { } + @VisibleForTesting + public void setCachedStorageValuesHelper(CachedStorageValuesHelper helper) { + mCachedStorageValuesHelper = helper; + } + + @VisibleForTesting + public PrivateStorageInfo getPrivateStorageInfo() { + return mStorageInfo; + } + + @VisibleForTesting + public SparseArray getAppsStorageResult() { + return mAppsResult; + } + + @VisibleForTesting + public void initializeCachedValues() { + PrivateStorageInfo info = mCachedStorageValuesHelper.getCachedPrivateStorageInfo(); + SparseArray loaderResult = + mCachedStorageValuesHelper.getCachedAppsStorageResult(); + if (info == null || loaderResult == null) { + return; + } + + mStorageInfo = info; + mAppsResult = loaderResult; + } + + private void initializeCacheProvider() { + mCachedStorageValuesHelper = + new CachedStorageValuesHelper(getContext(), UserHandle.myUserId()); + initializeCachedValues(); + onReceivedSizes(); + } + + private void maybeCacheFreshValues() { + if (mStorageInfo != null && mAppsResult != null) { + mCachedStorageValuesHelper.cacheResult( + mStorageInfo, mAppsResult.get(UserHandle.myUserId())); + } + } + /** * IconLoaderCallbacks exists because StorageDashboardFragment already implements * LoaderCallbacks for a different type. @@ -308,6 +356,7 @@ public class StorageDashboardFragment extends DashboardFragment } mStorageInfo = privateStorageInfo; + maybeCacheFreshValues(); onReceivedSizes(); } } diff --git a/src/com/android/settings/deviceinfo/storage/CachedStorageValuesHelper.java b/src/com/android/settings/deviceinfo/storage/CachedStorageValuesHelper.java new file mode 100644 index 00000000000..8225db39434 --- /dev/null +++ b/src/com/android/settings/deviceinfo/storage/CachedStorageValuesHelper.java @@ -0,0 +1,172 @@ +/* + * Copyright (C) 2017 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; +import android.provider.Settings; +import android.support.annotation.VisibleForTesting; +import android.util.SparseArray; + +import com.android.settingslib.applications.StorageStatsSource; +import com.android.settingslib.deviceinfo.PrivateStorageInfo; + +import java.util.concurrent.TimeUnit; + +public class CachedStorageValuesHelper { + + @VisibleForTesting public static final String SHARED_PREFERENCES_NAME = "CachedStorageValues"; + public static final String TIMESTAMP_KEY = "last_query_timestamp"; + public static final String FREE_BYTES_KEY = "free_bytes"; + public static final String TOTAL_BYTES_KEY = "total_bytes"; + public static final String GAME_APPS_SIZE_KEY = "game_apps_size"; + public static final String MUSIC_APPS_SIZE_KEY = "music_apps_size"; + public static final String VIDEO_APPS_SIZE_KEY = "video_apps_size"; + public static final String PHOTO_APPS_SIZE_KEY = "photo_apps_size"; + public static final String OTHER_APPS_SIZE_KEY = "other_apps_size"; + public static final String CACHE_APPS_SIZE_KEY = "cache_apps_size"; + public static final String EXTERNAL_TOTAL_BYTES = "external_total_bytes"; + public static final String EXTERNAL_AUDIO_BYTES = "external_audio_bytes"; + public static final String EXTERNAL_VIDEO_BYTES = "external_video_bytes"; + public static final String EXTERNAL_IMAGE_BYTES = "external_image_bytes"; + public static final String EXTERNAL_APP_BYTES = "external_apps_bytes"; + public static final String USER_ID_KEY = "user_id"; + private final Long mClobberThreshold; + private final SharedPreferences mSharedPreferences; + private final int mUserId; + // This clock is used to provide the time. By default, it uses the system clock, but can be + // replaced for test purposes. + protected Clock mClock; + + public CachedStorageValuesHelper(Context context, int userId) { + mSharedPreferences = + context.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE); + mClock = new Clock(); + mUserId = userId; + mClobberThreshold = + Settings.Global.getLong( + context.getContentResolver(), + Settings.Global.STORAGE_SETTINGS_CLOBBER_THRESHOLD, + TimeUnit.MINUTES.toMillis(5)); + } + + public PrivateStorageInfo getCachedPrivateStorageInfo() { + if (!isDataValid()) { + return null; + } + final long freeBytes = mSharedPreferences.getLong(FREE_BYTES_KEY, -1); + final long totalBytes = mSharedPreferences.getLong(TOTAL_BYTES_KEY, -1); + if (freeBytes < 0 || totalBytes < 0) { + return null; + } + + return new PrivateStorageInfo(freeBytes, totalBytes); + } + + public SparseArray getCachedAppsStorageResult() { + if (!isDataValid()) { + return null; + } + final long gamesSize = mSharedPreferences.getLong(GAME_APPS_SIZE_KEY, -1); + final long musicAppsSize = mSharedPreferences.getLong(MUSIC_APPS_SIZE_KEY, -1); + final long videoAppsSize = mSharedPreferences.getLong(VIDEO_APPS_SIZE_KEY, -1); + final long photoAppSize = mSharedPreferences.getLong(PHOTO_APPS_SIZE_KEY, -1); + final long otherAppsSize = mSharedPreferences.getLong(OTHER_APPS_SIZE_KEY, -1); + final long cacheSize = mSharedPreferences.getLong(CACHE_APPS_SIZE_KEY, -1); + if (gamesSize < 0 + || musicAppsSize < 0 + || videoAppsSize < 0 + || photoAppSize < 0 + || otherAppsSize < 0 + || cacheSize < 0) { + return null; + } + + final long externalTotalBytes = mSharedPreferences.getLong(EXTERNAL_TOTAL_BYTES, -1); + final long externalAudioBytes = mSharedPreferences.getLong(EXTERNAL_AUDIO_BYTES, -1); + final long externalVideoBytes = mSharedPreferences.getLong(EXTERNAL_VIDEO_BYTES, -1); + final long externalImageBytes = mSharedPreferences.getLong(EXTERNAL_IMAGE_BYTES, -1); + final long externalAppBytes = mSharedPreferences.getLong(EXTERNAL_APP_BYTES, -1); + if (externalTotalBytes < 0 + || externalAudioBytes < 0 + || externalVideoBytes < 0 + || externalImageBytes < 0 + || externalAppBytes < 0) { + return null; + } + + final StorageStatsSource.ExternalStorageStats externalStats = + new StorageStatsSource.ExternalStorageStats( + externalTotalBytes, + externalAudioBytes, + externalVideoBytes, + externalImageBytes, + externalAppBytes); + final StorageAsyncLoader.AppsStorageResult result = + new StorageAsyncLoader.AppsStorageResult(); + result.gamesSize = gamesSize; + result.musicAppsSize = musicAppsSize; + result.videoAppsSize = videoAppsSize; + result.photosAppsSize = photoAppSize; + result.otherAppsSize = otherAppsSize; + result.cacheSize = cacheSize; + result.externalStats = externalStats; + final SparseArray resultArray = new SparseArray<>(); + resultArray.append(mUserId, result); + return resultArray; + } + + public void cacheResult( + PrivateStorageInfo storageInfo, StorageAsyncLoader.AppsStorageResult result) { + mSharedPreferences + .edit() + .putLong(FREE_BYTES_KEY, storageInfo.freeBytes) + .putLong(TOTAL_BYTES_KEY, storageInfo.totalBytes) + .putLong(GAME_APPS_SIZE_KEY, result.gamesSize) + .putLong(MUSIC_APPS_SIZE_KEY, result.musicAppsSize) + .putLong(VIDEO_APPS_SIZE_KEY, result.videoAppsSize) + .putLong(PHOTO_APPS_SIZE_KEY, result.photosAppsSize) + .putLong(OTHER_APPS_SIZE_KEY, result.otherAppsSize) + .putLong(CACHE_APPS_SIZE_KEY, result.cacheSize) + .putLong(EXTERNAL_TOTAL_BYTES, result.externalStats.totalBytes) + .putLong(EXTERNAL_AUDIO_BYTES, result.externalStats.audioBytes) + .putLong(EXTERNAL_VIDEO_BYTES, result.externalStats.videoBytes) + .putLong(EXTERNAL_IMAGE_BYTES, result.externalStats.imageBytes) + .putLong(EXTERNAL_APP_BYTES, result.externalStats.appBytes) + .putInt(USER_ID_KEY, mUserId) + .putLong(TIMESTAMP_KEY, mClock.getCurrentTime()) + .apply(); + } + + private boolean isDataValid() { + final int cachedUserId = mSharedPreferences.getInt(USER_ID_KEY, -1); + if (cachedUserId != mUserId) { + return false; + } + + final long lastQueryTime = mSharedPreferences.getLong(TIMESTAMP_KEY, Long.MAX_VALUE); + final long currentTime = mClock.getCurrentTime(); + return currentTime - lastQueryTime < mClobberThreshold; + } + + /** Clock provides the current time. */ + static class Clock { + public long getCurrentTime() { + return System.currentTimeMillis(); + } + } +} diff --git a/tests/robotests/src/com/android/settings/deviceinfo/StorageDashboardFragmentTest.java b/tests/robotests/src/com/android/settings/deviceinfo/StorageDashboardFragmentTest.java index b2d259a1846..a87f563cc9e 100644 --- a/tests/robotests/src/com/android/settings/deviceinfo/StorageDashboardFragmentTest.java +++ b/tests/robotests/src/com/android/settings/deviceinfo/StorageDashboardFragmentTest.java @@ -20,13 +20,18 @@ import static com.google.common.truth.Truth.assertThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import android.app.Activity; import android.os.storage.StorageManager; import android.provider.SearchIndexableResource; +import android.util.SparseArray; +import com.android.settings.deviceinfo.storage.CachedStorageValuesHelper; +import com.android.settings.deviceinfo.storage.StorageAsyncLoader; import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settings.TestConfig; +import com.android.settingslib.deviceinfo.PrivateStorageInfo; import com.android.settingslib.drawer.CategoryKey; import org.junit.Before; @@ -68,6 +73,47 @@ public class StorageDashboardFragmentTest { verify(activity).invalidateOptionsMenu(); } + @Test + public void test_cacheProviderProvidesValuesIfBothCached() { + CachedStorageValuesHelper helper = mock(CachedStorageValuesHelper.class); + PrivateStorageInfo info = new PrivateStorageInfo(0, 0); + when(helper.getCachedPrivateStorageInfo()).thenReturn(info); + SparseArray result = new SparseArray<>(); + when(helper.getCachedAppsStorageResult()).thenReturn(result); + + mFragment.setCachedStorageValuesHelper(helper); + mFragment.initializeCachedValues(); + + assertThat(mFragment.getPrivateStorageInfo()).isEqualTo(info); + assertThat(mFragment.getAppsStorageResult()).isEqualTo(result); + } + + @Test + public void test_cacheProviderDoesntProvideValuesIfAppsMissing() { + CachedStorageValuesHelper helper = mock(CachedStorageValuesHelper.class); + PrivateStorageInfo info = new PrivateStorageInfo(0, 0); + when(helper.getCachedPrivateStorageInfo()).thenReturn(info); + + mFragment.setCachedStorageValuesHelper(helper); + mFragment.initializeCachedValues(); + + assertThat(mFragment.getPrivateStorageInfo()).isNull(); + assertThat(mFragment.getAppsStorageResult()).isNull(); + } + + @Test + public void test_cacheProviderDoesntProvideValuesIfVolumeInfoMissing() { + CachedStorageValuesHelper helper = mock(CachedStorageValuesHelper.class); + SparseArray result = new SparseArray<>(); + when(helper.getCachedAppsStorageResult()).thenReturn(result); + + mFragment.setCachedStorageValuesHelper(helper); + mFragment.initializeCachedValues(); + + assertThat(mFragment.getPrivateStorageInfo()).isNull(); + assertThat(mFragment.getAppsStorageResult()).isNull(); + } + @Test public void testSearchIndexProvider_shouldIndexResource() { final List indexRes = diff --git a/tests/robotests/src/com/android/settings/deviceinfo/storage/CachedStorageValuesHelperTest.java b/tests/robotests/src/com/android/settings/deviceinfo/storage/CachedStorageValuesHelperTest.java new file mode 100644 index 00000000000..154a7a1afbf --- /dev/null +++ b/tests/robotests/src/com/android/settings/deviceinfo/storage/CachedStorageValuesHelperTest.java @@ -0,0 +1,295 @@ +/* + * Copyright (C) 2017 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.android.settings.deviceinfo.storage.CachedStorageValuesHelper.CACHE_APPS_SIZE_KEY; +import static com.android.settings.deviceinfo.storage.CachedStorageValuesHelper.EXTERNAL_APP_BYTES; +import static com.android.settings.deviceinfo.storage.CachedStorageValuesHelper.EXTERNAL_AUDIO_BYTES; +import static com.android.settings.deviceinfo.storage.CachedStorageValuesHelper.EXTERNAL_IMAGE_BYTES; +import static com.android.settings.deviceinfo.storage.CachedStorageValuesHelper.EXTERNAL_TOTAL_BYTES; +import static com.android.settings.deviceinfo.storage.CachedStorageValuesHelper.EXTERNAL_VIDEO_BYTES; +import static com.android.settings.deviceinfo.storage.CachedStorageValuesHelper.FREE_BYTES_KEY; +import static com.android.settings.deviceinfo.storage.CachedStorageValuesHelper.GAME_APPS_SIZE_KEY; +import static com.android.settings.deviceinfo.storage.CachedStorageValuesHelper.MUSIC_APPS_SIZE_KEY; +import static com.android.settings.deviceinfo.storage.CachedStorageValuesHelper.OTHER_APPS_SIZE_KEY; +import static com.android.settings.deviceinfo.storage.CachedStorageValuesHelper.PHOTO_APPS_SIZE_KEY; +import static com.android.settings.deviceinfo.storage.CachedStorageValuesHelper.SHARED_PREFERENCES_NAME; +import static com.android.settings.deviceinfo.storage.CachedStorageValuesHelper.TIMESTAMP_KEY; +import static com.android.settings.deviceinfo.storage.CachedStorageValuesHelper.TOTAL_BYTES_KEY; +import static com.android.settings.deviceinfo.storage.CachedStorageValuesHelper.USER_ID_KEY; +import static com.android.settings.deviceinfo.storage.CachedStorageValuesHelper.VIDEO_APPS_SIZE_KEY; + +import static org.mockito.Mockito.when; + +import android.content.Context; +import android.content.SharedPreferences; +import android.util.SparseArray; + +import com.android.settings.TestConfig; +import com.android.settings.testutils.SettingsRobolectricTestRunner; +import com.android.settingslib.applications.StorageStatsSource; +import com.android.settingslib.deviceinfo.PrivateStorageInfo; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.annotation.Config; + +import static com.google.common.truth.Truth.assertThat; + +@RunWith(SettingsRobolectricTestRunner.class) +@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) +public class CachedStorageValuesHelperTest { + private Context mContext; + + @Mock private CachedStorageValuesHelper.Clock mMockClock; + private CachedStorageValuesHelper mCachedValuesHelper; + private SharedPreferences mSharedPreferences; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + mContext = RuntimeEnvironment.application.getApplicationContext(); + mSharedPreferences = mContext.getSharedPreferences(SHARED_PREFERENCES_NAME, 0); + mCachedValuesHelper = new CachedStorageValuesHelper(mContext, 0); + mCachedValuesHelper.mClock = mMockClock; + } + + @Test + public void getCachedPrivateStorageInfo_cachedValuesAreLoaded() throws Exception { + when(mMockClock.getCurrentTime()).thenReturn(10001L); + mSharedPreferences + .edit() + .putLong(GAME_APPS_SIZE_KEY, 0) + .putLong(MUSIC_APPS_SIZE_KEY, 10) + .putLong(VIDEO_APPS_SIZE_KEY, 100) + .putLong(PHOTO_APPS_SIZE_KEY, 1000) + .putLong(OTHER_APPS_SIZE_KEY, 10000) + .putLong(CACHE_APPS_SIZE_KEY, 100000) + .putLong(EXTERNAL_TOTAL_BYTES, 2) + .putLong(EXTERNAL_AUDIO_BYTES, 22) + .putLong(EXTERNAL_VIDEO_BYTES, 222) + .putLong(EXTERNAL_IMAGE_BYTES, 2222) + .putLong(EXTERNAL_APP_BYTES, 22222) + .putLong(FREE_BYTES_KEY, 1000L) + .putLong(TOTAL_BYTES_KEY, 6000L) + .putInt(USER_ID_KEY, 0) + .putLong(TIMESTAMP_KEY, 10000L) + .apply(); + + PrivateStorageInfo info = mCachedValuesHelper.getCachedPrivateStorageInfo(); + + assertThat(info.freeBytes).isEqualTo(1000L); + assertThat(info.totalBytes).isEqualTo(6000L); + } + + @Test + public void getCachedAppsStorageResult_cachedValuesAreLoaded() throws Exception { + when(mMockClock.getCurrentTime()).thenReturn(10001L); + mSharedPreferences + .edit() + .putLong(GAME_APPS_SIZE_KEY, 1) + .putLong(MUSIC_APPS_SIZE_KEY, 10) + .putLong(VIDEO_APPS_SIZE_KEY, 100) + .putLong(PHOTO_APPS_SIZE_KEY, 1000) + .putLong(OTHER_APPS_SIZE_KEY, 10000) + .putLong(CACHE_APPS_SIZE_KEY, 100000) + .putLong(EXTERNAL_TOTAL_BYTES, 222222) + .putLong(EXTERNAL_AUDIO_BYTES, 22) + .putLong(EXTERNAL_VIDEO_BYTES, 222) + .putLong(EXTERNAL_IMAGE_BYTES, 2222) + .putLong(EXTERNAL_APP_BYTES, 22222) + .putLong(FREE_BYTES_KEY, 1000L) + .putLong(TOTAL_BYTES_KEY, 5000L) + .putInt(USER_ID_KEY, 0) + .putLong(TIMESTAMP_KEY, 10000L) + .apply(); + + SparseArray result = + mCachedValuesHelper.getCachedAppsStorageResult(); + + StorageAsyncLoader.AppsStorageResult primaryResult = result.get(0); + assertThat(primaryResult.gamesSize).isEqualTo(1L); + assertThat(primaryResult.musicAppsSize).isEqualTo(10L); + assertThat(primaryResult.videoAppsSize).isEqualTo(100L); + assertThat(primaryResult.photosAppsSize).isEqualTo(1000L); + assertThat(primaryResult.otherAppsSize).isEqualTo(10000L); + assertThat(primaryResult.cacheSize).isEqualTo(100000L); + assertThat(primaryResult.externalStats.totalBytes).isEqualTo(222222L); + assertThat(primaryResult.externalStats.audioBytes).isEqualTo(22L); + assertThat(primaryResult.externalStats.videoBytes).isEqualTo(222L); + assertThat(primaryResult.externalStats.imageBytes).isEqualTo(2222L); + assertThat(primaryResult.externalStats.appBytes).isEqualTo(22222L); + } + + @Test + public void getCachedPrivateStorageInfo_nullIfDataIsStale() throws Exception { + when(mMockClock.getCurrentTime()).thenReturn(10000000L); + mSharedPreferences + .edit() + .putLong(GAME_APPS_SIZE_KEY, 0) + .putLong(MUSIC_APPS_SIZE_KEY, 10) + .putLong(VIDEO_APPS_SIZE_KEY, 100) + .putLong(PHOTO_APPS_SIZE_KEY, 1000) + .putLong(OTHER_APPS_SIZE_KEY, 10000) + .putLong(CACHE_APPS_SIZE_KEY, 100000) + .putLong(EXTERNAL_TOTAL_BYTES, 2) + .putLong(EXTERNAL_AUDIO_BYTES, 22) + .putLong(EXTERNAL_VIDEO_BYTES, 222) + .putLong(EXTERNAL_IMAGE_BYTES, 2222) + .putLong(EXTERNAL_APP_BYTES, 22222) + .putLong(FREE_BYTES_KEY, 1000L) + .putLong(TOTAL_BYTES_KEY, 5000L) + .putInt(USER_ID_KEY, 0) + .putLong(TIMESTAMP_KEY, 10000L) + .apply(); + + PrivateStorageInfo info = mCachedValuesHelper.getCachedPrivateStorageInfo(); + assertThat(info).isNull(); + } + + @Test + public void getCachedAppsStorageResult_nullIfDataIsStale() throws Exception { + when(mMockClock.getCurrentTime()).thenReturn(10000000L); + mSharedPreferences + .edit() + .putLong(GAME_APPS_SIZE_KEY, 0) + .putLong(MUSIC_APPS_SIZE_KEY, 10) + .putLong(VIDEO_APPS_SIZE_KEY, 100) + .putLong(PHOTO_APPS_SIZE_KEY, 1000) + .putLong(OTHER_APPS_SIZE_KEY, 10000) + .putLong(CACHE_APPS_SIZE_KEY, 100000) + .putLong(EXTERNAL_TOTAL_BYTES, 2) + .putLong(EXTERNAL_AUDIO_BYTES, 22) + .putLong(EXTERNAL_VIDEO_BYTES, 222) + .putLong(EXTERNAL_IMAGE_BYTES, 2222) + .putLong(EXTERNAL_APP_BYTES, 22222) + .putLong(FREE_BYTES_KEY, 1000L) + .putLong(TOTAL_BYTES_KEY, 5000L) + .putInt(USER_ID_KEY, 0) + .putLong(TIMESTAMP_KEY, 10000L) + .apply(); + + SparseArray result = + mCachedValuesHelper.getCachedAppsStorageResult(); + assertThat(result).isNull(); + } + + @Test + public void getCachedPrivateStorageInfo_nullIfWrongUser() throws Exception { + when(mMockClock.getCurrentTime()).thenReturn(10001L); + mSharedPreferences + .edit() + .putLong(GAME_APPS_SIZE_KEY, 0) + .putLong(MUSIC_APPS_SIZE_KEY, 10) + .putLong(VIDEO_APPS_SIZE_KEY, 100) + .putLong(PHOTO_APPS_SIZE_KEY, 1000) + .putLong(OTHER_APPS_SIZE_KEY, 10000) + .putLong(CACHE_APPS_SIZE_KEY, 100000) + .putLong(EXTERNAL_TOTAL_BYTES, 2) + .putLong(EXTERNAL_AUDIO_BYTES, 22) + .putLong(EXTERNAL_VIDEO_BYTES, 222) + .putLong(EXTERNAL_IMAGE_BYTES, 2222) + .putLong(EXTERNAL_APP_BYTES, 22222) + .putLong(FREE_BYTES_KEY, 1000L) + .putLong(TOTAL_BYTES_KEY, 5000L) + .putInt(USER_ID_KEY, 1) + .putLong(TIMESTAMP_KEY, 10000L) + .apply(); + + PrivateStorageInfo info = mCachedValuesHelper.getCachedPrivateStorageInfo(); + assertThat(info).isNull(); + } + + @Test + public void getCachedAppsStorageResult_nullIfWrongUser() throws Exception { + when(mMockClock.getCurrentTime()).thenReturn(10001L); + mSharedPreferences + .edit() + .putLong(GAME_APPS_SIZE_KEY, 0) + .putLong(MUSIC_APPS_SIZE_KEY, 10) + .putLong(VIDEO_APPS_SIZE_KEY, 100) + .putLong(PHOTO_APPS_SIZE_KEY, 1000) + .putLong(OTHER_APPS_SIZE_KEY, 10000) + .putLong(CACHE_APPS_SIZE_KEY, 100000) + .putLong(EXTERNAL_TOTAL_BYTES, 2) + .putLong(EXTERNAL_AUDIO_BYTES, 22) + .putLong(EXTERNAL_VIDEO_BYTES, 222) + .putLong(EXTERNAL_IMAGE_BYTES, 2222) + .putLong(EXTERNAL_APP_BYTES, 22222) + .putLong(FREE_BYTES_KEY, 1000L) + .putLong(TOTAL_BYTES_KEY, 5000L) + .putInt(USER_ID_KEY, 1) + .putLong(TIMESTAMP_KEY, 10000L) + .apply(); + + SparseArray result = + mCachedValuesHelper.getCachedAppsStorageResult(); + assertThat(result).isNull(); + } + + @Test + public void getCachedPrivateStorageInfo_nullIfEmpty() throws Exception { + PrivateStorageInfo info = mCachedValuesHelper.getCachedPrivateStorageInfo(); + assertThat(info).isNull(); + } + + @Test + public void getCachedAppsStorageResult_nullIfEmpty() throws Exception { + SparseArray result = + mCachedValuesHelper.getCachedAppsStorageResult(); + assertThat(result).isNull(); + } + + @Test + public void cacheResult_succeeds() throws Exception { + when(mMockClock.getCurrentTime()).thenReturn(10000L); + final StorageStatsSource.ExternalStorageStats externalStats = + new StorageStatsSource.ExternalStorageStats(22222l, 2l, 20L, 200L, 2000L); + final StorageAsyncLoader.AppsStorageResult result = + new StorageAsyncLoader.AppsStorageResult(); + result.gamesSize = 1L; + result.musicAppsSize = 10l; + result.videoAppsSize = 100L; + result.photosAppsSize = 1000L; + result.otherAppsSize = 10000L; + result.cacheSize = 100000l; + result.externalStats = externalStats; + final PrivateStorageInfo info = new PrivateStorageInfo(1000L, 6000L); + + mCachedValuesHelper.cacheResult(info, result); + + assertThat(mSharedPreferences.getLong(GAME_APPS_SIZE_KEY, -1)).isEqualTo(1L); + assertThat(mSharedPreferences.getLong(MUSIC_APPS_SIZE_KEY, -1)).isEqualTo(10L); + assertThat(mSharedPreferences.getLong(VIDEO_APPS_SIZE_KEY, -1)).isEqualTo(100L); + assertThat(mSharedPreferences.getLong(PHOTO_APPS_SIZE_KEY, -1)).isEqualTo(1000L); + assertThat(mSharedPreferences.getLong(OTHER_APPS_SIZE_KEY, -1)).isEqualTo(10000L); + assertThat(mSharedPreferences.getLong(CACHE_APPS_SIZE_KEY, -1)).isEqualTo(100000L); + assertThat(mSharedPreferences.getLong(EXTERNAL_TOTAL_BYTES, -1)).isEqualTo(22222L); + assertThat(mSharedPreferences.getLong(EXTERNAL_AUDIO_BYTES, -1)).isEqualTo(2L); + assertThat(mSharedPreferences.getLong(EXTERNAL_VIDEO_BYTES, -1)).isEqualTo(20L); + assertThat(mSharedPreferences.getLong(EXTERNAL_IMAGE_BYTES, -1)).isEqualTo(200L); + assertThat(mSharedPreferences.getLong(EXTERNAL_APP_BYTES, -1)).isEqualTo(2000L); + assertThat(mSharedPreferences.getLong(FREE_BYTES_KEY, -1)).isEqualTo(1000L); + assertThat(mSharedPreferences.getLong(TOTAL_BYTES_KEY, -1)).isEqualTo(6000L); + assertThat(mSharedPreferences.getInt(USER_ID_KEY, -1)).isEqualTo(0); + assertThat(mSharedPreferences.getLong(TIMESTAMP_KEY, -1)).isEqualTo(10000L); + }; +}