Storage Settings hides categories when loading

To hide sorting animation.

- Storage Settings always loads cache and updates UI, then
  loads storage size and updates UI.
  Remove the chche design because storage category preferences
  will hide during loading, it no meaning to load from cache
  and update UI.

- Hides loading circle before storage category preferences
  become visible, it prevents flickers.

- Remove Calculating... summary of StorageItemPreference.

- Private storage category preferences and secondary user
  preference become visible at
  StorageItemPreferenceController#onLoadFinished.

Bug: 188731179
Bug: 185547228
Bug: 188615591
Test: atest com.android.settings.deviceinfo
      atest com.android.settings.deviceinfo.storage
      make RunSettingsRoboTests -j ROBOTEST_FILTER=com.android.settings.deviceinfo
      make RunSettingsRoboTests -j ROBOTEST_FILTER=com.android.settings.deviceinfo.storage
      manual visual
Change-Id: I3ebef5829ef4f806add07f58fa02520804768be5
This commit is contained in:
Arc Wang
2021-05-31 11:50:22 +08:00
parent 3940e5293c
commit 51b3e7a093
11 changed files with 95 additions and 649 deletions

View File

@@ -24,8 +24,7 @@
android:order="4"
android:title="@string/storage_free_up_space_title"
android:summary="@string/storage_free_up_space_summary"
android:icon="@drawable/ic_files_go_round"
settings:allowDividerAbove="true"/>
android:icon="@drawable/ic_files_go_round"/>
<!-- Preference order 100~200 are 'ONLY' for storage category preferences below. -->
<Preference
android:key="pref_public_storage"

View File

@@ -37,7 +37,6 @@ import com.android.settings.R;
import com.android.settings.Utils;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.dashboard.profileselector.ProfileSelectFragment;
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.StorageEntry;
@@ -54,6 +53,7 @@ import com.android.settingslib.deviceinfo.StorageManagerVolumeProvider;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
/**
* Storage Settings main UI is composed by 3 fragments:
@@ -85,7 +85,6 @@ public class StorageCategoryFragment extends DashboardFragment
private StorageEntry mSelectedStorageEntry;
private PrivateStorageInfo mStorageInfo;
private SparseArray<StorageAsyncLoader.StorageResult> mAppsResult;
private CachedStorageValuesHelper mCachedStorageValuesHelper;
private StorageItemPreferenceController mPreferenceController;
private List<AbstractPreferenceController> mSecondaryUsers;
@@ -104,6 +103,10 @@ public class StorageCategoryFragment extends DashboardFragment
return;
}
// To prevent flicker, hides secondary users preference.
// onReceivedSizes will set it visible for private storage.
setSecondaryUsersVisible(false);
if (!mSelectedStorageEntry.isMounted()) {
// Set null volume to hide category stats.
mPreferenceController.setVolume(null);
@@ -114,6 +117,10 @@ public class StorageCategoryFragment extends DashboardFragment
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);
// Stats data is only available on private volumes.
getLoaderManager().restartLoader(STORAGE_JOB_ID, Bundle.EMPTY, this);
getLoaderManager()
@@ -157,7 +164,6 @@ public class StorageCategoryFragment extends DashboardFragment
@Override
public void onViewCreated(View v, Bundle savedInstanceState) {
super.onViewCreated(v, savedInstanceState);
initializeCacheProvider();
EntityHeaderController.newInstance(getActivity(), this /*fragment*/,
null /* header view */)
@@ -184,6 +190,10 @@ public class StorageCategoryFragment extends DashboardFragment
return;
}
if (getView().findViewById(R.id.loading_container).getVisibility() == View.VISIBLE) {
setLoading(false /* loading */, true /* animate */);
}
final long privateUsedBytes = mStorageInfo.totalBytes - mStorageInfo.freeBytes;
mPreferenceController.setVolume(mSelectedStorageEntry.getVolumeInfo());
mPreferenceController.setUsedSize(privateUsedBytes);
@@ -198,10 +208,7 @@ public class StorageCategoryFragment extends DashboardFragment
mPreferenceController.onLoadFinished(mAppsResult, mUserId);
updateSecondaryUserControllers(mSecondaryUsers, mAppsResult);
if (getView().findViewById(R.id.loading_container).getVisibility() == View.VISIBLE) {
setLoading(false, true);
}
setSecondaryUsersVisible(true);
}
@Override
@@ -263,7 +270,6 @@ public class StorageCategoryFragment extends DashboardFragment
public void onLoadFinished(Loader<SparseArray<StorageAsyncLoader.StorageResult>> loader,
SparseArray<StorageAsyncLoader.StorageResult> data) {
mAppsResult = data;
maybeCacheFreshValues();
onReceivedSizes();
}
@@ -286,11 +292,6 @@ public class StorageCategoryFragment extends DashboardFragment
return false;
}
@VisibleForTesting
public void setCachedStorageValuesHelper(CachedStorageValuesHelper helper) {
mCachedStorageValuesHelper = helper;
}
@VisibleForTesting
public PrivateStorageInfo getPrivateStorageInfo() {
return mStorageInfo;
@@ -311,19 +312,6 @@ public class StorageCategoryFragment extends DashboardFragment
mAppsResult = info;
}
@VisibleForTesting
void initializeCachedValues() {
final PrivateStorageInfo info = mCachedStorageValuesHelper.getCachedPrivateStorageInfo();
final SparseArray<StorageAsyncLoader.StorageResult> loaderResult =
mCachedStorageValuesHelper.getCachedStorageResult();
if (info == null || loaderResult == null) {
return;
}
mStorageInfo = info;
mAppsResult = loaderResult;
}
/**
* Activate loading UI and animation if it's necessary.
*/
@@ -337,24 +325,22 @@ public class StorageCategoryFragment extends DashboardFragment
}
}
private void initializeCacheProvider() {
mCachedStorageValuesHelper = new CachedStorageValuesHelper(getContext(), mUserId);
initializeCachedValues();
onReceivedSizes();
}
private void maybeCacheFreshValues() {
if (mStorageInfo != null && mAppsResult != null) {
mCachedStorageValuesHelper.cacheResult(mStorageInfo, mAppsResult.get(mUserId));
}
}
private boolean isQuotaSupported() {
return mSelectedStorageEntry.isMounted()
&& getActivity().getSystemService(StorageStatsManager.class)
.isQuotaSupported(mSelectedStorageEntry.getFsUuid());
}
private void setSecondaryUsersVisible(boolean visible) {
final Optional<SecondaryUserController> secondaryUserController = mSecondaryUsers.stream()
.filter(controller -> controller instanceof SecondaryUserController)
.map(controller -> (SecondaryUserController) controller)
.findAny();
if (secondaryUserController.isPresent()) {
secondaryUserController.get().setPreferenceGroupVisible(visible);
}
}
/**
* IconLoaderCallbacks exists because StorageCategoryFragment already implements
* LoaderCallbacks for a different type.
@@ -414,7 +400,6 @@ public class StorageCategoryFragment extends DashboardFragment
}
mStorageInfo = privateStorageInfo;
maybeCacheFreshValues();
onReceivedSizes();
}
}

View File

@@ -44,7 +44,6 @@ import com.android.settings.R;
import com.android.settings.Utils;
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.DiskInitFragment;
import com.android.settings.deviceinfo.storage.SecondaryUserController;
import com.android.settings.deviceinfo.storage.StorageAsyncLoader;
@@ -68,6 +67,7 @@ import com.android.settingslib.search.SearchIndexable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
/**
* Storage Settings main UI is composed by 3 fragments:
@@ -101,7 +101,6 @@ public class StorageDashboardFragment extends DashboardFragment
private StorageEntry mSelectedStorageEntry;
private PrivateStorageInfo mStorageInfo;
private SparseArray<StorageAsyncLoader.StorageResult> mAppsResult;
private CachedStorageValuesHelper mCachedStorageValuesHelper;
private StorageItemPreferenceController mPreferenceController;
private VolumeOptionMenuController mOptionMenuController;
@@ -232,6 +231,10 @@ public class StorageDashboardFragment extends DashboardFragment
mOptionMenuController.setSelectedStorageEntry(mSelectedStorageEntry);
getActivity().invalidateOptionsMenu();
// To prevent flicker, hides secondary users preference.
// onReceivedSizes will set it visible for private storage.
setSecondaryUsersVisible(false);
if (!mSelectedStorageEntry.isMounted()) {
// Set null volume to hide category stats.
mPreferenceController.setVolume(null);
@@ -242,6 +245,10 @@ public class StorageDashboardFragment extends DashboardFragment
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);
// Stats data is only available on private volumes.
getLoaderManager().restartLoader(STORAGE_JOB_ID, Bundle.EMPTY, this);
getLoaderManager()
@@ -316,7 +323,6 @@ public class StorageDashboardFragment extends DashboardFragment
@Override
public void onViewCreated(View v, Bundle savedInstanceState) {
super.onViewCreated(v, savedInstanceState);
initializeCacheProvider();
EntityHeaderController.newInstance(getActivity(), this /*fragment*/,
null /* header view */)
@@ -355,6 +361,10 @@ public class StorageDashboardFragment extends DashboardFragment
return;
}
if (getView().findViewById(R.id.loading_container).getVisibility() == View.VISIBLE) {
setLoading(false /* loading */, true /* animate */);
}
final long privateUsedBytes = mStorageInfo.totalBytes - mStorageInfo.freeBytes;
mPreferenceController.setVolume(mSelectedStorageEntry.getVolumeInfo());
mPreferenceController.setUsedSize(privateUsedBytes);
@@ -369,10 +379,7 @@ public class StorageDashboardFragment extends DashboardFragment
mPreferenceController.onLoadFinished(mAppsResult, mUserId);
updateSecondaryUserControllers(mSecondaryUsers, mAppsResult);
if (getView().findViewById(R.id.loading_container).getVisibility() == View.VISIBLE) {
setLoading(false, true);
}
setSecondaryUsersVisible(true);
}
@Override
@@ -463,7 +470,6 @@ public class StorageDashboardFragment extends DashboardFragment
public void onLoadFinished(Loader<SparseArray<StorageAsyncLoader.StorageResult>> loader,
SparseArray<StorageAsyncLoader.StorageResult> data) {
mAppsResult = data;
maybeCacheFreshValues();
onReceivedSizes();
}
@@ -486,11 +492,6 @@ public class StorageDashboardFragment extends DashboardFragment
return false;
}
@VisibleForTesting
public void setCachedStorageValuesHelper(CachedStorageValuesHelper helper) {
mCachedStorageValuesHelper = helper;
}
@VisibleForTesting
public PrivateStorageInfo getPrivateStorageInfo() {
return mStorageInfo;
@@ -511,19 +512,6 @@ public class StorageDashboardFragment extends DashboardFragment
mAppsResult = info;
}
@VisibleForTesting
void initializeCachedValues() {
final PrivateStorageInfo info = mCachedStorageValuesHelper.getCachedPrivateStorageInfo();
final SparseArray<StorageAsyncLoader.StorageResult> loaderResult =
mCachedStorageValuesHelper.getCachedStorageResult();
if (info == null || loaderResult == null) {
return;
}
mStorageInfo = info;
mAppsResult = loaderResult;
}
/**
* Activate loading UI and animation if it's necessary.
*/
@@ -537,24 +525,22 @@ public class StorageDashboardFragment extends DashboardFragment
}
}
private void initializeCacheProvider() {
mCachedStorageValuesHelper = new CachedStorageValuesHelper(getContext(), mUserId);
initializeCachedValues();
onReceivedSizes();
}
private void maybeCacheFreshValues() {
if (mStorageInfo != null && mAppsResult != null) {
mCachedStorageValuesHelper.cacheResult(mStorageInfo, mAppsResult.get(mUserId));
}
}
private boolean isQuotaSupported() {
return mSelectedStorageEntry.isMounted()
&& getActivity().getSystemService(StorageStatsManager.class)
.isQuotaSupported(mSelectedStorageEntry.getFsUuid());
}
private void setSecondaryUsersVisible(boolean visible) {
final Optional<SecondaryUserController> secondaryUserController = mSecondaryUsers.stream()
.filter(controller -> controller instanceof SecondaryUserController)
.map(controller -> (SecondaryUserController) controller)
.findAny();
if (secondaryUserController.isPresent()) {
secondaryUserController.get().setPreferenceGroupVisible(visible);
}
}
/**
* IconLoaderCallbacks exists because StorageDashboardFragment already implements
* LoaderCallbacks for a different type.
@@ -614,7 +600,6 @@ public class StorageDashboardFragment extends DashboardFragment
}
mStorageInfo = privateStorageInfo;
maybeCacheFreshValues();
onReceivedSizes();
}
}

View File

@@ -43,7 +43,6 @@ public class StorageItemPreference extends Preference {
public StorageItemPreference(Context context, AttributeSet attrs) {
super(context, attrs);
setLayoutResource(R.layout.storage_item);
setSummary(R.string.memory_calculating_size);
}
public void setStorageSize(long size, long total) {

View File

@@ -1,184 +0,0 @@
/*
* 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.util.SparseArray;
import androidx.annotation.VisibleForTesting;
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 AUDIO_SIZE_KEY = "audio_size";
public static final String VIDEOS_SIZE_KEY = "videos_size";
public static final String IMAGES_SIZE_KEY = "images_size";
public static final String DOCUMENTS_AND_OTHER_SIZE_KEY = "documents_and_other_size";
public static final String TRASH_SIZE_KEY = "trash_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);
}
/** Returns cached storage result or null if it's not available. */
public SparseArray<StorageAsyncLoader.StorageResult> getCachedStorageResult() {
if (!isDataValid()) {
return null;
}
final long gamesSize = mSharedPreferences.getLong(GAME_APPS_SIZE_KEY, -1);
final long audioSize = mSharedPreferences.getLong(AUDIO_SIZE_KEY, -1);
final long videosSize = mSharedPreferences.getLong(VIDEOS_SIZE_KEY, -1);
final long imagesSize = mSharedPreferences.getLong(IMAGES_SIZE_KEY, -1);
final long documentsAndOtherSize =
mSharedPreferences.getLong(DOCUMENTS_AND_OTHER_SIZE_KEY, -1);
final long trashSize = mSharedPreferences.getLong(TRASH_SIZE_KEY, -1);
final long allAppsExceptGamesSize = mSharedPreferences.getLong(OTHER_APPS_SIZE_KEY, -1);
final long cacheSize = mSharedPreferences.getLong(CACHE_APPS_SIZE_KEY, -1);
if (gamesSize < 0
|| audioSize < 0
|| videosSize < 0
|| imagesSize < 0
|| documentsAndOtherSize < 0
|| trashSize < 0
|| allAppsExceptGamesSize < 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.StorageResult result = new StorageAsyncLoader.StorageResult();
result.gamesSize = gamesSize;
result.audioSize = audioSize;
result.videosSize = videosSize;
result.imagesSize = imagesSize;
result.documentsAndOtherSize = documentsAndOtherSize;
result.trashSize = trashSize;
result.allAppsExceptGamesSize = allAppsExceptGamesSize;
result.cacheSize = cacheSize;
result.externalStats = externalStats;
final SparseArray<StorageAsyncLoader.StorageResult> resultArray = new SparseArray<>();
resultArray.append(mUserId, result);
return resultArray;
}
public void cacheResult(
PrivateStorageInfo storageInfo, StorageAsyncLoader.StorageResult result) {
mSharedPreferences
.edit()
.putLong(FREE_BYTES_KEY, storageInfo.freeBytes)
.putLong(TOTAL_BYTES_KEY, storageInfo.totalBytes)
.putLong(GAME_APPS_SIZE_KEY, result.gamesSize)
.putLong(AUDIO_SIZE_KEY, result.audioSize)
.putLong(VIDEOS_SIZE_KEY, result.videosSize)
.putLong(IMAGES_SIZE_KEY, result.imagesSize)
.putLong(DOCUMENTS_AND_OTHER_SIZE_KEY, result.documentsAndOtherSize)
.putLong(TRASH_SIZE_KEY, result.trashSize)
.putLong(OTHER_APPS_SIZE_KEY, result.allAppsExceptGamesSize)
.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();
}
}
}

View File

@@ -53,9 +53,11 @@ public class SecondaryUserController extends AbstractPreferenceController implem
UserInfo mUser;
private @Nullable
StorageItemPreference mStoragePreference;
private PreferenceGroup mPreferenceGroup;
private Drawable mUserIcon;
private long mSize;
private long mTotalSizeBytes;
private boolean mIsVisible;
/**
* Adds the appropriate controllers to a controller list for handling all secondary users on
@@ -115,16 +117,15 @@ public class SecondaryUserController extends AbstractPreferenceController implem
if (mStoragePreference == null) {
mStoragePreference = new StorageItemPreference(screen.getContext());
PreferenceGroup group =
screen.findPreference(TARGET_PREFERENCE_GROUP_KEY);
mPreferenceGroup = screen.findPreference(TARGET_PREFERENCE_GROUP_KEY);
mStoragePreference.setTitle(mUser.name);
mStoragePreference.setKey(PREFERENCE_KEY_BASE + mUser.id);
if (mSize != SIZE_NOT_SET) {
mStoragePreference.setStorageSize(mSize, mTotalSizeBytes);
}
group.setVisible(true);
group.addPreference(mStoragePreference);
mPreferenceGroup.setVisible(mIsVisible);
mPreferenceGroup.addPreference(mStoragePreference);
maybeSetIcon();
}
}
@@ -168,6 +169,18 @@ public class SecondaryUserController extends AbstractPreferenceController implem
mTotalSizeBytes = totalSizeBytes;
}
/**
* Sets visibility of the PreferenceGroup of secondary user.
*
* @param visible Visibility of the PreferenceGroup.
*/
public void setPreferenceGroupVisible(boolean visible) {
mIsVisible = visible;
if (mPreferenceGroup != null) {
mPreferenceGroup.setVisible(mIsVisible);
}
}
@Override
public void handleResult(SparseArray<StorageAsyncLoader.StorageResult> stats) {
final StorageAsyncLoader.StorageResult result = stats.get(getUser().id);

View File

@@ -221,7 +221,15 @@ public class StorageItemPreferenceController extends AbstractPreferenceControlle
public void setVolume(VolumeInfo volume) {
mVolume = volume;
updateCategoryPreferencesVisibility();
if (mPublicStoragePreference != null) {
mPublicStoragePreference.setVisible(isValidPublicVolume());
}
// If isValidPrivateVolume() is true, these preferences will become visible at
// onLoadFinished.
if (!isValidPrivateVolume()) {
setPrivateStorageCategoryPreferencesVisibility(false);
}
}
// Stats data is only available on private volumes.
@@ -242,30 +250,28 @@ public class StorageItemPreferenceController extends AbstractPreferenceControlle
|| mVolume.getState() == VolumeInfo.STATE_MOUNTED_READ_ONLY);
}
private void updateCategoryPreferencesVisibility() {
@VisibleForTesting
void setPrivateStorageCategoryPreferencesVisibility(boolean visible) {
if (mScreen == null) {
return;
}
mPublicStoragePreference.setVisible(isValidPublicVolume());
mImagesPreference.setVisible(visible);
mVideosPreference.setVisible(visible);
mAudioPreference.setVisible(visible);
mAppsPreference.setVisible(visible);
mGamesPreference.setVisible(visible);
mSystemPreference.setVisible(visible);
mTrashPreference.setVisible(visible);
final boolean privateStoragePreferencesVisible = isValidPrivateVolume();
mImagesPreference.setVisible(privateStoragePreferencesVisible);
mVideosPreference.setVisible(privateStoragePreferencesVisible);
mAudioPreference.setVisible(privateStoragePreferencesVisible);
mAppsPreference.setVisible(privateStoragePreferencesVisible);
mGamesPreference.setVisible(privateStoragePreferencesVisible);
mDocumentsAndOtherPreference.setVisible(privateStoragePreferencesVisible);
mSystemPreference.setVisible(privateStoragePreferencesVisible);
mTrashPreference.setVisible(privateStoragePreferencesVisible);
if (privateStoragePreferencesVisible) {
// 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);
// 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 (sharedVolume == null || !sharedVolume.isMountedReadable()) {
mDocumentsAndOtherPreference.setVisible(false);
}
mDocumentsAndOtherPreference.setVisible(sharedVolume != null
&& sharedVolume.isMountedReadable());
} else {
mDocumentsAndOtherPreference.setVisible(false);
}
}
@@ -390,6 +396,7 @@ public class StorageItemPreferenceController extends AbstractPreferenceControlle
}
updatePrivateStorageCategoryPreferencesOrder();
setPrivateStorageCategoryPreferencesVisibility(true);
}
public void setUsedSize(long usedSizeBytes) {

View File

@@ -33,8 +33,6 @@ import android.view.View;
import androidx.recyclerview.widget.RecyclerView;
import com.android.settings.deviceinfo.storage.CachedStorageValuesHelper;
import com.android.settings.deviceinfo.storage.StorageAsyncLoader;
import com.android.settingslib.deviceinfo.PrivateStorageInfo;
import com.android.settingslib.drawer.CategoryKey;
@@ -72,47 +70,6 @@ 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<StorageAsyncLoader.StorageResult> result = new SparseArray<>();
when(helper.getCachedStorageResult()).thenReturn(result);
mFragment.setCachedStorageValuesHelper(helper);
mFragment.initializeCachedValues();
assertThat(mFragment.getPrivateStorageInfo()).isEqualTo(info);
assertThat(mFragment.getStorageResult()).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.getStorageResult()).isNull();
}
@Test
public void test_cacheProviderDoesntProvideValuesIfVolumeInfoMissing() {
CachedStorageValuesHelper helper = mock(CachedStorageValuesHelper.class);
SparseArray<StorageAsyncLoader.StorageResult> result = new SparseArray<>();
when(helper.getCachedStorageResult()).thenReturn(result);
mFragment.setCachedStorageValuesHelper(helper);
mFragment.initializeCachedValues();
assertThat(mFragment.getPrivateStorageInfo()).isNull();
assertThat(mFragment.getStorageResult()).isNull();
}
@Test
public void test_loadWhenQuotaOffIfVolumeInfoNotLoaded() {
View fakeView = mock(View.class, RETURNS_DEEP_STUBS);

View File

@@ -45,12 +45,6 @@ public class StorageItemPreferenceTest {
mPreference = new StorageItemPreference(mContext);
}
@Test
public void testBeforeLoad() {
assertThat(mPreference.getSummary())
.isEqualTo(mContext.getString(R.string.memory_calculating_size));
}
@Test
public void testAfterLoad() {
mPreference.setStorageSize(MEGABYTE_IN_BYTES * 10, MEGABYTE_IN_BYTES * 100);

View File

@@ -1,304 +0,0 @@
/*
* 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.AUDIO_SIZE_KEY;
import static com.android.settings.deviceinfo.storage.CachedStorageValuesHelper.CACHE_APPS_SIZE_KEY;
import static com.android.settings.deviceinfo.storage.CachedStorageValuesHelper.DOCUMENTS_AND_OTHER_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.IMAGES_SIZE_KEY;
import static com.android.settings.deviceinfo.storage.CachedStorageValuesHelper.OTHER_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.TRASH_SIZE_KEY;
import static com.android.settings.deviceinfo.storage.CachedStorageValuesHelper.USER_ID_KEY;
import static com.android.settings.deviceinfo.storage.CachedStorageValuesHelper.VIDEOS_SIZE_KEY;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.content.SharedPreferences;
import android.util.SparseArray;
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.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
@RunWith(RobolectricTestRunner.class)
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;
mSharedPreferences = mContext.getSharedPreferences(SHARED_PREFERENCES_NAME, 0);
mCachedValuesHelper = new CachedStorageValuesHelper(mContext, 0);
mCachedValuesHelper.mClock = mMockClock;
}
@Test
public void getCachedPrivateStorageInfo_cachedValuesAreLoaded() {
when(mMockClock.getCurrentTime()).thenReturn(10001L);
mSharedPreferences
.edit()
.putLong(GAME_APPS_SIZE_KEY, 0)
.putLong(AUDIO_SIZE_KEY, 10)
.putLong(VIDEOS_SIZE_KEY, 100)
.putLong(IMAGES_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();
final PrivateStorageInfo info = mCachedValuesHelper.getCachedPrivateStorageInfo();
assertThat(info.freeBytes).isEqualTo(1000L);
assertThat(info.totalBytes).isEqualTo(6000L);
}
@Test
public void getCachedStorageResult_cachedValuesAreLoaded() {
when(mMockClock.getCurrentTime()).thenReturn(10001L);
mSharedPreferences
.edit()
.putLong(GAME_APPS_SIZE_KEY, 1)
.putLong(AUDIO_SIZE_KEY, 10)
.putLong(VIDEOS_SIZE_KEY, 100)
.putLong(IMAGES_SIZE_KEY, 1000)
.putLong(DOCUMENTS_AND_OTHER_SIZE_KEY, 1001)
.putLong(TRASH_SIZE_KEY, 1002)
.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();
final SparseArray<StorageAsyncLoader.StorageResult> result =
mCachedValuesHelper.getCachedStorageResult();
StorageAsyncLoader.StorageResult primaryResult = result.get(0);
assertThat(primaryResult.gamesSize).isEqualTo(1L);
assertThat(primaryResult.audioSize).isEqualTo(10L);
assertThat(primaryResult.videosSize).isEqualTo(100L);
assertThat(primaryResult.imagesSize).isEqualTo(1000L);
assertThat(primaryResult.documentsAndOtherSize).isEqualTo(1001L);
assertThat(primaryResult.trashSize).isEqualTo(1002L);
assertThat(primaryResult.allAppsExceptGamesSize).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() {
when(mMockClock.getCurrentTime()).thenReturn(10000000L);
mSharedPreferences
.edit()
.putLong(GAME_APPS_SIZE_KEY, 0)
.putLong(AUDIO_SIZE_KEY, 10)
.putLong(VIDEOS_SIZE_KEY, 100)
.putLong(IMAGES_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();
final PrivateStorageInfo info = mCachedValuesHelper.getCachedPrivateStorageInfo();
assertThat(info).isNull();
}
@Test
public void getCachedStorageResult_nullIfDataIsStale() {
when(mMockClock.getCurrentTime()).thenReturn(10000000L);
mSharedPreferences
.edit()
.putLong(GAME_APPS_SIZE_KEY, 0)
.putLong(AUDIO_SIZE_KEY, 10)
.putLong(VIDEOS_SIZE_KEY, 100)
.putLong(IMAGES_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();
final SparseArray<StorageAsyncLoader.StorageResult> result =
mCachedValuesHelper.getCachedStorageResult();
assertThat(result).isNull();
}
@Test
public void getCachedPrivateStorageInfo_nullIfWrongUser() {
when(mMockClock.getCurrentTime()).thenReturn(10001L);
mSharedPreferences
.edit()
.putLong(GAME_APPS_SIZE_KEY, 0)
.putLong(AUDIO_SIZE_KEY, 10)
.putLong(VIDEOS_SIZE_KEY, 100)
.putLong(IMAGES_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();
final PrivateStorageInfo info = mCachedValuesHelper.getCachedPrivateStorageInfo();
assertThat(info).isNull();
}
@Test
public void getCachedStorageResult_nullIfWrongUser() {
when(mMockClock.getCurrentTime()).thenReturn(10001L);
mSharedPreferences
.edit()
.putLong(GAME_APPS_SIZE_KEY, 0)
.putLong(AUDIO_SIZE_KEY, 10)
.putLong(VIDEOS_SIZE_KEY, 100)
.putLong(IMAGES_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();
final SparseArray<StorageAsyncLoader.StorageResult> result =
mCachedValuesHelper.getCachedStorageResult();
assertThat(result).isNull();
}
@Test
public void getCachedPrivateStorageInfo_nullIfEmpty() {
final PrivateStorageInfo info = mCachedValuesHelper.getCachedPrivateStorageInfo();
assertThat(info).isNull();
}
@Test
public void getCachedStorageResult_nullIfEmpty() {
final SparseArray<StorageAsyncLoader.StorageResult> result =
mCachedValuesHelper.getCachedStorageResult();
assertThat(result).isNull();
}
@Test
public void cacheResult_succeeds() {
when(mMockClock.getCurrentTime()).thenReturn(10000L);
final StorageStatsSource.ExternalStorageStats externalStats =
new StorageStatsSource.ExternalStorageStats(22222L, 2L, 20L, 200L, 2000L);
final StorageAsyncLoader.StorageResult result =
new StorageAsyncLoader.StorageResult();
result.gamesSize = 1L;
result.audioSize = 10L;
result.videosSize = 100L;
result.imagesSize = 1000L;
result.allAppsExceptGamesSize = 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(AUDIO_SIZE_KEY, -1)).isEqualTo(10L);
assertThat(mSharedPreferences.getLong(VIDEOS_SIZE_KEY, -1)).isEqualTo(100L);
assertThat(mSharedPreferences.getLong(IMAGES_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);
}
}

View File

@@ -150,12 +150,6 @@ public class StorageItemPreferenceControllerTest {
return screen;
}
@Test
public void testUpdateStateWithInitialState() {
assertThat(mPreference.getSummary().toString())
.isEqualTo(mContext.getString(R.string.memory_calculating_size));
}
@Test
public void launchPublicStorageIntent_nonNullBrowseIntent_settingsIntent() {
final String fakeBrowseAction = "FAKE_BROWSE_ACTION";
@@ -398,16 +392,17 @@ public class StorageItemPreferenceControllerTest {
}
@Test
public void setVolume_updateFilePreferenceToHideAfterSettingVolume_hidePreference() {
public void setPrivateStorageCategoryPreferencesVisibility_updateFilePreferenceToHideAfterSettingVolume_hidePreference() {
when(mSvp.findEmulatedForPrivate(nullable(VolumeInfo.class))).thenReturn(mVolume);
when(mVolume.getType()).thenReturn(VolumeInfo.TYPE_PRIVATE);
when(mVolume.getState()).thenReturn(VolumeInfo.STATE_MOUNTED);
when(mVolume.isMountedReadable()).thenReturn(true);
mController.displayPreference(mPreferenceScreen);
when(mSvp.findEmulatedForPrivate(nullable(VolumeInfo.class))).thenReturn(null);
mController.setVolume(mVolume);
mController.setPrivateStorageCategoryPreferencesVisibility(true);
assertThat(mController.mDocumentsAndOtherPreference.isVisible()).isFalse();
}