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
This commit is contained in:
Daniel Nishi
2017-04-21 10:24:41 -07:00
parent 0cdade8a78
commit a16837769c
4 changed files with 175 additions and 28 deletions

View File

@@ -18,6 +18,7 @@ package com.android.settings.deviceinfo;
import android.app.Activity; import android.app.Activity;
import android.app.LoaderManager; import android.app.LoaderManager;
import android.app.usage.StorageStatsManager;
import android.content.Context; import android.content.Context;
import android.content.Loader; import android.content.Loader;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
@@ -29,6 +30,7 @@ import android.os.storage.VolumeInfo;
import android.provider.SearchIndexableResource; import android.provider.SearchIndexableResource;
import android.support.annotation.VisibleForTesting; import android.support.annotation.VisibleForTesting;
import android.util.SparseArray; import android.util.SparseArray;
import android.view.View;
import com.android.internal.logging.nano.MetricsProto; import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.R; 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.StorageItemPreferenceController;
import com.android.settings.deviceinfo.storage.StorageSummaryDonutPreferenceController; import com.android.settings.deviceinfo.storage.StorageSummaryDonutPreferenceController;
import com.android.settings.deviceinfo.storage.UserIconLoader; 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.BaseSearchIndexProvider;
import com.android.settings.search.Indexable; import com.android.settings.search.Indexable;
import com.android.settingslib.applications.StorageStatsSource; import com.android.settingslib.applications.StorageStatsSource;
import com.android.settingslib.deviceinfo.PrivateStorageInfo;
import com.android.settingslib.deviceinfo.StorageManagerVolumeProvider; import com.android.settingslib.deviceinfo.StorageManagerVolumeProvider;
import java.util.ArrayList; import java.util.ArrayList;
@@ -58,9 +62,12 @@ public class StorageDashboardFragment extends DashboardFragment
private static final String TAG = "StorageDashboardFrag"; private static final String TAG = "StorageDashboardFrag";
private static final int STORAGE_JOB_ID = 0; private static final int STORAGE_JOB_ID = 0;
private static final int ICON_JOB_ID = 1; 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 static final int OPTIONS_MENU_MIGRATE_DATA = 100;
private VolumeInfo mVolume; private VolumeInfo mVolume;
private PrivateStorageInfo mStorageInfo;
private SparseArray<StorageAsyncLoader.AppsStorageResult> mAppsResult;
private StorageSummaryDonutPreferenceController mSummaryController; private StorageSummaryDonutPreferenceController mSummaryController;
private StorageItemPreferenceController mPreferenceController; private StorageItemPreferenceController mPreferenceController;
@@ -81,29 +88,6 @@ public class StorageDashboardFragment extends DashboardFragment
} }
initializeOptionsMenu(activity); 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 @VisibleForTesting
@@ -115,11 +99,41 @@ public class StorageDashboardFragment extends DashboardFragment
activity.invalidateOptionsMenu(); activity.invalidateOptionsMenu();
} }
@Override
public void onViewCreated(View v, Bundle savedInstanceState) {
super.onViewCreated(v, savedInstanceState);
setLoading(true, false);
}
@Override @Override
public void onResume() { public void onResume() {
super.onResume(); super.onResume();
getLoaderManager().restartLoader(STORAGE_JOB_ID, Bundle.EMPTY, this); getLoaderManager().restartLoader(STORAGE_JOB_ID, Bundle.EMPTY, this);
getLoaderManager().initLoader(ICON_JOB_ID, Bundle.EMPTY, new IconLoaderCallbacks()); 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 @Override
@@ -224,8 +238,8 @@ public class StorageDashboardFragment extends DashboardFragment
@Override @Override
public void onLoadFinished(Loader<SparseArray<StorageAsyncLoader.AppsStorageResult>> loader, public void onLoadFinished(Loader<SparseArray<StorageAsyncLoader.AppsStorageResult>> loader,
SparseArray<StorageAsyncLoader.AppsStorageResult> data) { SparseArray<StorageAsyncLoader.AppsStorageResult> data) {
mPreferenceController.onLoadFinished(data.get(UserHandle.myUserId())); mAppsResult = data;
updateSecondaryUserControllers(mSecondaryUsers, data); onReceivedSizes();
} }
@Override @Override
@@ -260,4 +274,31 @@ public class StorageDashboardFragment extends DashboardFragment
@Override @Override
public void onLoaderReset(Loader<SparseArray<Drawable>> loader) {} public void onLoaderReset(Loader<SparseArray<Drawable>> loader) {}
} }
public final class VolumeSizeCallbacks
implements LoaderManager.LoaderCallbacks<PrivateStorageInfo> {
@Override
public Loader<PrivateStorageInfo> 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<PrivateStorageInfo> loader) {}
@Override
public void onLoadFinished(
Loader<PrivateStorageInfo> loader, PrivateStorageInfo privateStorageInfo) {
if (privateStorageInfo == null) {
getActivity().finish();
return;
}
mStorageInfo = privateStorageInfo;
onReceivedSizes();
}
}
} }

View File

@@ -34,6 +34,7 @@ import com.android.settingslib.deviceinfo.StorageVolumeProvider;
public class StorageSummaryDonutPreferenceController extends PreferenceController { public class StorageSummaryDonutPreferenceController extends PreferenceController {
private long mUsedBytes; private long mUsedBytes;
private long mTotalBytes; private long mTotalBytes;
private StorageSummaryDonutPreference mSummary;
public StorageSummaryDonutPreferenceController(Context context) { public StorageSummaryDonutPreferenceController(Context context) {
super(context); super(context);
@@ -41,9 +42,8 @@ public class StorageSummaryDonutPreferenceController extends PreferenceControlle
@Override @Override
public void displayPreference(PreferenceScreen screen) { public void displayPreference(PreferenceScreen screen) {
StorageSummaryDonutPreference summary = (StorageSummaryDonutPreference) mSummary = (StorageSummaryDonutPreference) screen.findPreference("pref_summary");
screen.findPreference("pref_summary"); mSummary.setEnabled(true);
summary.setEnabled(true);
} }
@Override @Override
@@ -61,6 +61,13 @@ public class StorageSummaryDonutPreferenceController extends PreferenceControlle
summary.setEnabled(true); summary.setEnabled(true);
} }
/** Invalidates the data on the view and re-renders. */
public void invalidateData() {
if (mSummary != null) {
updateState(mSummary);
}
}
@Override @Override
public boolean isAvailable() { public boolean isAvailable() {
return true; return true;
@@ -79,6 +86,7 @@ public class StorageSummaryDonutPreferenceController extends PreferenceControlle
public void updateBytes(long used, long total) { public void updateBytes(long used, long total) {
mUsedBytes = used; mUsedBytes = used;
mTotalBytes = total; mTotalBytes = total;
invalidateData();
} }
/** /**

View File

@@ -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<PrivateStorageInfo> {
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);
}
}

View File

@@ -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);
}
}