From a16837769c88feac2b61f3174ac256573d275f3e Mon Sep 17 00:00:00 2001 From: Daniel Nishi Date: Fri, 21 Apr 2017 10:24:41 -0700 Subject: [PATCH] Make the storage free/total sizes consistent. We were using a different calculation in the top level view compared to within the Storage settings. Technically, both are correct (one of them is aware that we're considering cache as free, one does not). This patch aligns us on the cache as free strategy. Change-Id: I9ac26683a4d2a30b77a1da534aa2ddd3d4da6657 Fixes: 37175551 Test: Settings robotest --- .../deviceinfo/StorageDashboardFragment.java | 91 ++++++++++++++----- ...orageSummaryDonutPreferenceController.java | 14 ++- .../deviceinfo/storage/VolumeSizesLoader.java | 68 ++++++++++++++ .../storage/VolumeSizesLoaderTest.java | 30 ++++++ 4 files changed, 175 insertions(+), 28 deletions(-) create mode 100644 src/com/android/settings/deviceinfo/storage/VolumeSizesLoader.java create mode 100644 tests/robotests/src/com/android/settings/deviceinfo/storage/VolumeSizesLoaderTest.java diff --git a/src/com/android/settings/deviceinfo/StorageDashboardFragment.java b/src/com/android/settings/deviceinfo/StorageDashboardFragment.java index 2a5ac17bc16..57f73455d30 100644 --- a/src/com/android/settings/deviceinfo/StorageDashboardFragment.java +++ b/src/com/android/settings/deviceinfo/StorageDashboardFragment.java @@ -18,6 +18,7 @@ package com.android.settings.deviceinfo; import android.app.Activity; import android.app.LoaderManager; +import android.app.usage.StorageStatsManager; import android.content.Context; import android.content.Loader; import android.graphics.drawable.Drawable; @@ -29,6 +30,7 @@ import android.os.storage.VolumeInfo; import android.provider.SearchIndexableResource; import android.support.annotation.VisibleForTesting; import android.util.SparseArray; +import android.view.View; import com.android.internal.logging.nano.MetricsProto; import com.android.settings.R; @@ -44,9 +46,11 @@ import com.android.settings.deviceinfo.storage.StorageAsyncLoader; import com.android.settings.deviceinfo.storage.StorageItemPreferenceController; import com.android.settings.deviceinfo.storage.StorageSummaryDonutPreferenceController; import com.android.settings.deviceinfo.storage.UserIconLoader; +import com.android.settings.deviceinfo.storage.VolumeSizesLoader; import com.android.settings.search.BaseSearchIndexProvider; import com.android.settings.search.Indexable; import com.android.settingslib.applications.StorageStatsSource; +import com.android.settingslib.deviceinfo.PrivateStorageInfo; import com.android.settingslib.deviceinfo.StorageManagerVolumeProvider; import java.util.ArrayList; @@ -58,9 +62,12 @@ public class StorageDashboardFragment extends DashboardFragment private static final String TAG = "StorageDashboardFrag"; private static final int STORAGE_JOB_ID = 0; private static final int ICON_JOB_ID = 1; + private static final int VOLUME_SIZE_JOB_ID = 2; private static final int OPTIONS_MENU_MIGRATE_DATA = 100; private VolumeInfo mVolume; + private PrivateStorageInfo mStorageInfo; + private SparseArray mAppsResult; private StorageSummaryDonutPreferenceController mSummaryController; private StorageItemPreferenceController mPreferenceController; @@ -81,29 +88,6 @@ public class StorageDashboardFragment extends DashboardFragment } initializeOptionsMenu(activity); - - final long sharedDataSize = mVolume.getPath().getTotalSpace(); - long totalSize = sm.getPrimaryStorageSize(); - long systemSize = totalSize - sharedDataSize; - - if (totalSize <= 0) { - totalSize = sharedDataSize; - systemSize = 0; - } - - final long usedBytes = totalSize - mVolume.getPath().getFreeSpace(); - mSummaryController.updateBytes(usedBytes, totalSize); - mPreferenceController.setVolume(mVolume); - mPreferenceController.setUsedSize(usedBytes); - mPreferenceController.setTotalSize(totalSize); - for (int i = 0, size = mSecondaryUsers.size(); i < size; i++) { - PreferenceController controller = mSecondaryUsers.get(i); - if (controller instanceof SecondaryUserController) { - SecondaryUserController userController = (SecondaryUserController) controller; - userController.setTotalSize(totalSize); - - } - } } @VisibleForTesting @@ -115,11 +99,41 @@ public class StorageDashboardFragment extends DashboardFragment activity.invalidateOptionsMenu(); } + @Override + public void onViewCreated(View v, Bundle savedInstanceState) { + super.onViewCreated(v, savedInstanceState); + setLoading(true, false); + } + @Override public void onResume() { super.onResume(); getLoaderManager().restartLoader(STORAGE_JOB_ID, Bundle.EMPTY, this); getLoaderManager().initLoader(ICON_JOB_ID, Bundle.EMPTY, new IconLoaderCallbacks()); + getLoaderManager().initLoader(VOLUME_SIZE_JOB_ID, Bundle.EMPTY, new VolumeSizeCallbacks()); + } + + private void onReceivedSizes() { + if (mStorageInfo == null || mAppsResult == null) { + return; + } + + long privateUsedBytes = mStorageInfo.totalBytes - mStorageInfo.freeBytes; + mSummaryController.updateBytes(privateUsedBytes, mStorageInfo.totalBytes); + mPreferenceController.setVolume(mVolume); + mPreferenceController.setUsedSize(privateUsedBytes); + mPreferenceController.setTotalSize(mStorageInfo.totalBytes); + for (int i = 0, size = mSecondaryUsers.size(); i < size; i++) { + PreferenceController controller = mSecondaryUsers.get(i); + if (controller instanceof SecondaryUserController) { + SecondaryUserController userController = (SecondaryUserController) controller; + userController.setTotalSize(mStorageInfo.totalBytes); + } + } + + mPreferenceController.onLoadFinished(mAppsResult.get(UserHandle.myUserId())); + updateSecondaryUserControllers(mSecondaryUsers, mAppsResult); + setLoading(false, true); } @Override @@ -224,8 +238,8 @@ public class StorageDashboardFragment extends DashboardFragment @Override public void onLoadFinished(Loader> loader, SparseArray data) { - mPreferenceController.onLoadFinished(data.get(UserHandle.myUserId())); - updateSecondaryUserControllers(mSecondaryUsers, data); + mAppsResult = data; + onReceivedSizes(); } @Override @@ -260,4 +274,31 @@ public class StorageDashboardFragment extends DashboardFragment @Override public void onLoaderReset(Loader> loader) {} } + + public final class VolumeSizeCallbacks + implements LoaderManager.LoaderCallbacks { + @Override + public Loader onCreateLoader(int id, Bundle args) { + Context context = getContext(); + StorageManager sm = context.getSystemService(StorageManager.class); + StorageManagerVolumeProvider smvp = new StorageManagerVolumeProvider(sm); + final StorageStatsManager stats = context.getSystemService(StorageStatsManager.class); + return new VolumeSizesLoader(context, smvp, stats, mVolume); + } + + @Override + public void onLoaderReset(Loader loader) {} + + @Override + public void onLoadFinished( + Loader loader, PrivateStorageInfo privateStorageInfo) { + if (privateStorageInfo == null) { + getActivity().finish(); + return; + } + + mStorageInfo = privateStorageInfo; + onReceivedSizes(); + } + } } diff --git a/src/com/android/settings/deviceinfo/storage/StorageSummaryDonutPreferenceController.java b/src/com/android/settings/deviceinfo/storage/StorageSummaryDonutPreferenceController.java index 890d99e2845..91c4a6b523b 100644 --- a/src/com/android/settings/deviceinfo/storage/StorageSummaryDonutPreferenceController.java +++ b/src/com/android/settings/deviceinfo/storage/StorageSummaryDonutPreferenceController.java @@ -34,6 +34,7 @@ import com.android.settingslib.deviceinfo.StorageVolumeProvider; public class StorageSummaryDonutPreferenceController extends PreferenceController { private long mUsedBytes; private long mTotalBytes; + private StorageSummaryDonutPreference mSummary; public StorageSummaryDonutPreferenceController(Context context) { super(context); @@ -41,9 +42,8 @@ public class StorageSummaryDonutPreferenceController extends PreferenceControlle @Override public void displayPreference(PreferenceScreen screen) { - StorageSummaryDonutPreference summary = (StorageSummaryDonutPreference) - screen.findPreference("pref_summary"); - summary.setEnabled(true); + mSummary = (StorageSummaryDonutPreference) screen.findPreference("pref_summary"); + mSummary.setEnabled(true); } @Override @@ -61,6 +61,13 @@ public class StorageSummaryDonutPreferenceController extends PreferenceControlle summary.setEnabled(true); } + /** Invalidates the data on the view and re-renders. */ + public void invalidateData() { + if (mSummary != null) { + updateState(mSummary); + } + } + @Override public boolean isAvailable() { return true; @@ -79,6 +86,7 @@ public class StorageSummaryDonutPreferenceController extends PreferenceControlle public void updateBytes(long used, long total) { mUsedBytes = used; mTotalBytes = total; + invalidateData(); } /** diff --git a/src/com/android/settings/deviceinfo/storage/VolumeSizesLoader.java b/src/com/android/settings/deviceinfo/storage/VolumeSizesLoader.java new file mode 100644 index 00000000000..720f1512b59 --- /dev/null +++ b/src/com/android/settings/deviceinfo/storage/VolumeSizesLoader.java @@ -0,0 +1,68 @@ +/* + * 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.app.usage.StorageStatsManager; +import android.content.Context; +import android.os.storage.VolumeInfo; +import android.support.annotation.VisibleForTesting; + +import com.android.settings.utils.AsyncLoader; +import com.android.settingslib.deviceinfo.PrivateStorageInfo; +import com.android.settingslib.deviceinfo.StorageVolumeProvider; + +import java.io.IOException; + +public class VolumeSizesLoader extends AsyncLoader { + private StorageVolumeProvider mVolumeProvider; + private StorageStatsManager mStats; + private VolumeInfo mVolume; + + public VolumeSizesLoader( + Context context, + StorageVolumeProvider volumeProvider, + StorageStatsManager stats, + VolumeInfo volume) { + super(context); + mVolumeProvider = volumeProvider; + mStats = stats; + mVolume = volume; + } + + @Override + protected void onDiscardResult(PrivateStorageInfo result) {} + + @Override + public PrivateStorageInfo loadInBackground() { + PrivateStorageInfo volumeSizes; + try { + volumeSizes = getVolumeSize(mVolumeProvider, mStats, mVolume); + } catch (IOException e) { + return null; + } + return volumeSizes; + } + + @VisibleForTesting + static PrivateStorageInfo getVolumeSize( + StorageVolumeProvider storageVolumeProvider, StorageStatsManager stats, VolumeInfo info) + throws IOException { + long privateTotalBytes = storageVolumeProvider.getTotalBytes(stats, info); + long privateFreeBytes = storageVolumeProvider.getFreeBytes(stats, info); + return new PrivateStorageInfo(privateFreeBytes, privateTotalBytes); + } +} diff --git a/tests/robotests/src/com/android/settings/deviceinfo/storage/VolumeSizesLoaderTest.java b/tests/robotests/src/com/android/settings/deviceinfo/storage/VolumeSizesLoaderTest.java new file mode 100644 index 00000000000..3f9ccaf1009 --- /dev/null +++ b/tests/robotests/src/com/android/settings/deviceinfo/storage/VolumeSizesLoaderTest.java @@ -0,0 +1,30 @@ +package com.android.settings.deviceinfo.storage; + +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import android.os.storage.VolumeInfo; + +import com.android.settingslib.deviceinfo.PrivateStorageInfo; +import com.android.settingslib.deviceinfo.StorageVolumeProvider; + +import static com.google.common.truth.Truth.assertThat; + +import org.junit.Test; + +public class VolumeSizesLoaderTest { + @Test + public void getVolumeSize_getsValidSizes() throws Exception { + VolumeInfo info = mock(VolumeInfo.class); + StorageVolumeProvider storageVolumeProvider = mock(StorageVolumeProvider.class); + when(storageVolumeProvider.getTotalBytes(any(), any())).thenReturn(10000L); + when(storageVolumeProvider.getFreeBytes(any(), any())).thenReturn(1000L); + + PrivateStorageInfo storageInfo = + VolumeSizesLoader.getVolumeSize(storageVolumeProvider, null, info); + + assertThat(storageInfo.freeBytes).isEqualTo(1000L); + assertThat(storageInfo.totalBytes).isEqualTo(10000L); + } +}