Hook up the storage item preferences to actual data.
This uses the same storage query implementation as the previous iteration of the Storage Settings. In b/32206268, a new API for querying this information will be added for querying this info. Once the new API has landed, a future patch will swap out the impl, but this should work for today. Bug: 33199077 Test: Settings Robo Tests Change-Id: I58763e8ee38aabbea533bc614268288e854ff8d4
This commit is contained in:
@@ -81,6 +81,8 @@ public class StorageDashboardFragment extends DashboardFragment {
|
||||
final long usedBytes = mTotalSize - mVolume.getPath().getFreeSpace();
|
||||
mSummaryController.updateBytes(usedBytes, mTotalSize);
|
||||
mPreferenceController.setVolume(mVolume);
|
||||
mPreferenceController.setSystemSize(systemSize);
|
||||
mPreferenceController.startMeasurement();
|
||||
|
||||
// Initialize the footer preference to go to the smart storage management.
|
||||
final FooterPreference pref = mFooterPreferenceMixin.createFooterPreference();
|
||||
@@ -119,8 +121,8 @@ public class StorageDashboardFragment extends DashboardFragment {
|
||||
controllers.add(mSummaryController);
|
||||
|
||||
StorageManager sm = context.getSystemService(StorageManager.class);
|
||||
mPreferenceController = new StorageItemPreferenceController(context, this, mVolume,
|
||||
new StorageManagerVolumeProvider(sm));
|
||||
mPreferenceController = new StorageItemPreferenceController(context, getLifecycle(), this,
|
||||
mVolume, new StorageManagerVolumeProvider(sm));
|
||||
controllers.add(mPreferenceController);
|
||||
controllers.add(new ManageStoragePreferenceController(context));
|
||||
return controllers;
|
||||
|
@@ -21,11 +21,14 @@ import android.content.ActivityNotFoundException;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.os.Environment;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
import android.os.storage.VolumeInfo;
|
||||
import android.provider.DocumentsContract;
|
||||
import android.support.annotation.VisibleForTesting;
|
||||
import android.support.v7.preference.Preference;
|
||||
import android.support.v7.preference.PreferenceScreen;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.settings.R;
|
||||
@@ -33,24 +36,56 @@ import com.android.settings.Settings;
|
||||
import com.android.settings.Utils;
|
||||
import com.android.settings.applications.ManageApplications;
|
||||
import com.android.settings.core.PreferenceController;
|
||||
import com.android.settings.core.lifecycle.Lifecycle;
|
||||
import com.android.settings.core.lifecycle.LifecycleObserver;
|
||||
import com.android.settings.core.lifecycle.events.OnDestroy;
|
||||
import com.android.settings.deviceinfo.StorageItemPreference;
|
||||
import com.android.settingslib.deviceinfo.StorageMeasurement;
|
||||
import com.android.settingslib.deviceinfo.StorageVolumeProvider;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
|
||||
/**
|
||||
* StorageItemPreferenceController handles the storage line items which summarize the storage
|
||||
* categorization breakdown.
|
||||
*/
|
||||
public class StorageItemPreferenceController extends PreferenceController {
|
||||
public class StorageItemPreferenceController extends PreferenceController
|
||||
implements StorageMeasurement.MeasurementReceiver, LifecycleObserver, OnDestroy {
|
||||
private static final String TAG = "StorageItemPreference";
|
||||
|
||||
@VisibleForTesting
|
||||
static final String PHOTO_KEY = "pref_photos_videos";
|
||||
@VisibleForTesting
|
||||
static final String AUDIO_KEY = "pref_music_audio";
|
||||
@VisibleForTesting
|
||||
static final String GAME_KEY = "pref_games";
|
||||
@VisibleForTesting
|
||||
static final String OTHER_APPS_KEY = "pref_other_apps";
|
||||
@VisibleForTesting
|
||||
static final String SYSTEM_KEY = "pref_system";
|
||||
@VisibleForTesting
|
||||
static final String FILES_KEY = "pref_files";
|
||||
|
||||
private final Fragment mFragment;
|
||||
private final StorageVolumeProvider mSvp;
|
||||
private VolumeInfo mVolume;
|
||||
private final int mUserId;
|
||||
private StorageMeasurement mMeasure;
|
||||
private long mSystemSize;
|
||||
private long mUsedSize;
|
||||
|
||||
private StorageItemPreferenceAlternate mPhotoPreference;
|
||||
private StorageItemPreferenceAlternate mAudioPreference;
|
||||
private StorageItemPreferenceAlternate mGamePreference;
|
||||
private StorageItemPreferenceAlternate mAppPreference;
|
||||
private StorageItemPreferenceAlternate mFilePreference;
|
||||
private StorageItemPreferenceAlternate mSystemPreference;
|
||||
|
||||
private static final String AUTHORITY_MEDIA = "com.android.providers.media.documents";
|
||||
|
||||
public StorageItemPreferenceController(Context context, Fragment hostFragment,
|
||||
VolumeInfo volume, StorageVolumeProvider svp) {
|
||||
public StorageItemPreferenceController(Context context, Lifecycle lifecycle,
|
||||
Fragment hostFragment, VolumeInfo volume, StorageVolumeProvider svp) {
|
||||
super(context);
|
||||
mFragment = hostFragment;
|
||||
mVolume = volume;
|
||||
@@ -58,6 +93,10 @@ public class StorageItemPreferenceController extends PreferenceController {
|
||||
|
||||
UserManager um = mContext.getSystemService(UserManager.class);
|
||||
mUserId = um.getUserHandle();
|
||||
|
||||
if (lifecycle != null) {
|
||||
lifecycle.addObserver(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -75,15 +114,15 @@ public class StorageItemPreferenceController extends PreferenceController {
|
||||
// After the intermediate views are built, swap them in.
|
||||
Intent intent = null;
|
||||
switch (preference.getKey()) {
|
||||
case "pref_photos_videos":
|
||||
case PHOTO_KEY:
|
||||
intent = getPhotosIntent();
|
||||
break;
|
||||
case "pref_music_audio":
|
||||
case AUDIO_KEY:
|
||||
intent = getAudioIntent();
|
||||
break;
|
||||
case "pref_games":
|
||||
case GAME_KEY:
|
||||
// TODO: Once app categorization is added, make this section.
|
||||
case "pref_other_apps":
|
||||
case OTHER_APPS_KEY:
|
||||
// Because we are likely constructed with a null volume, this is theoretically
|
||||
// possible.
|
||||
if (mVolume == null) {
|
||||
@@ -91,7 +130,7 @@ public class StorageItemPreferenceController extends PreferenceController {
|
||||
}
|
||||
intent = getAppsIntent();
|
||||
break;
|
||||
case "pref_files":
|
||||
case FILES_KEY:
|
||||
intent = getFilesIntent();
|
||||
break;
|
||||
}
|
||||
@@ -118,6 +157,81 @@ public class StorageItemPreferenceController extends PreferenceController {
|
||||
mVolume = volume;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDetailsChanged(StorageMeasurement.MeasurementDetails details) {
|
||||
final long imagesSize = totalValues(details, mUserId,
|
||||
Environment.DIRECTORY_DCIM,
|
||||
Environment.DIRECTORY_PICTURES,
|
||||
Environment.DIRECTORY_MOVIES);
|
||||
if (mPhotoPreference != null) {
|
||||
mPhotoPreference.setStorageSize(imagesSize);
|
||||
}
|
||||
|
||||
final long audioSize = totalValues(details, mUserId,
|
||||
Environment.DIRECTORY_MUSIC,
|
||||
Environment.DIRECTORY_ALARMS,
|
||||
Environment.DIRECTORY_NOTIFICATIONS,
|
||||
Environment.DIRECTORY_RINGTONES,
|
||||
Environment.DIRECTORY_PODCASTS);
|
||||
if (mAudioPreference != null) {
|
||||
mAudioPreference.setStorageSize(audioSize);
|
||||
}
|
||||
|
||||
if (mGamePreference != null) {
|
||||
mGamePreference.setStorageSize(0);
|
||||
}
|
||||
|
||||
final long appSize = details.appsSize.get(mUserId);
|
||||
if (mAppPreference != null) {
|
||||
mAppPreference.setStorageSize(appSize);
|
||||
}
|
||||
|
||||
if (mSystemPreference != null) {
|
||||
mSystemPreference.setStorageSize(mSystemSize);
|
||||
}
|
||||
|
||||
final long downloadsSize = totalValues(details, mUserId, Environment.DIRECTORY_DOWNLOADS);
|
||||
final long miscSize = details.miscSize.get(mUserId);
|
||||
if (mFilePreference != null) {
|
||||
mFilePreference.setStorageSize(downloadsSize + miscSize);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
if (mMeasure != null) {
|
||||
mMeasure.onDestroy();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void displayPreference(PreferenceScreen screen) {
|
||||
mPhotoPreference = (StorageItemPreferenceAlternate) screen.findPreference(PHOTO_KEY);
|
||||
mAudioPreference = (StorageItemPreferenceAlternate) screen.findPreference(AUDIO_KEY);
|
||||
mGamePreference = (StorageItemPreferenceAlternate) screen.findPreference(GAME_KEY);
|
||||
mAppPreference = (StorageItemPreferenceAlternate) screen.findPreference(OTHER_APPS_KEY);
|
||||
mSystemPreference = (StorageItemPreferenceAlternate) screen.findPreference(SYSTEM_KEY);
|
||||
mFilePreference = (StorageItemPreferenceAlternate) screen.findPreference(FILES_KEY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Begins an asynchronous storage measurement task for the preferences.
|
||||
*/
|
||||
public void startMeasurement() {
|
||||
//TODO: When the GID-based measurement system is completed, swap in the GID impl.
|
||||
mMeasure = new StorageMeasurement(mContext, mVolume, mSvp.findEmulatedForPrivate(mVolume));
|
||||
mMeasure.setReceiver(this);
|
||||
mMeasure.forceMeasure();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the system size for the system size preference.
|
||||
* @param systemSize the size of the system in bytes
|
||||
*/
|
||||
public void setSystemSize(long systemSize) {
|
||||
mSystemSize = systemSize;
|
||||
}
|
||||
|
||||
private Intent getPhotosIntent() {
|
||||
Intent intent = new Intent(DocumentsContract.ACTION_BROWSE);
|
||||
intent.setData(DocumentsContract.buildRootUri(AUTHORITY_MEDIA, "images_root"));
|
||||
@@ -160,4 +274,20 @@ public class StorageItemPreferenceController extends PreferenceController {
|
||||
Log.w(TAG, "No activity found for " + intent);
|
||||
}
|
||||
}
|
||||
|
||||
private static long totalValues(StorageMeasurement.MeasurementDetails details, int userId,
|
||||
String... keys) {
|
||||
long total = 0;
|
||||
HashMap<String, Long> map = details.mediaSize.get(userId);
|
||||
if (map != null) {
|
||||
for (String key : keys) {
|
||||
if (map.containsKey(key)) {
|
||||
total += map.get(key);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Log.w(TAG, "MeasurementDetails mediaSize array does not have key for user " + userId);
|
||||
}
|
||||
return total;
|
||||
}
|
||||
}
|
||||
|
@@ -18,16 +18,20 @@ package com.android.settings.deviceinfo.storage;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.app.Fragment;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Environment;
|
||||
import android.os.UserHandle;
|
||||
import android.os.storage.VolumeInfo;
|
||||
import android.provider.DocumentsContract;
|
||||
import android.support.v7.preference.PreferenceScreen;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import com.android.settings.R;
|
||||
@@ -36,6 +40,7 @@ import com.android.settings.SettingsRobolectricTestRunner;
|
||||
import com.android.settings.SubSettings;
|
||||
import com.android.settings.TestConfig;
|
||||
import com.android.settings.applications.ManageApplications;
|
||||
import com.android.settingslib.deviceinfo.StorageMeasurement;
|
||||
import com.android.settingslib.deviceinfo.StorageVolumeProvider;
|
||||
|
||||
import org.junit.Before;
|
||||
@@ -44,13 +49,22 @@ import org.junit.runner.RunWith;
|
||||
import org.mockito.Answers;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
import org.robolectric.annotation.Config;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
@RunWith(SettingsRobolectricTestRunner.class)
|
||||
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
|
||||
public class StorageItemPreferenceControllerTest {
|
||||
/**
|
||||
* In O, this will change to 1000 instead of 1024 due to the formatter properly defining a
|
||||
* kilobyte.
|
||||
*/
|
||||
private static long KILOBYTE = 1024L;
|
||||
|
||||
private Context mContext;
|
||||
private VolumeInfo mVolume;
|
||||
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
|
||||
@@ -65,12 +79,15 @@ public class StorageItemPreferenceControllerTest {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mVolume = new VolumeInfo("id", 0, null, "id");
|
||||
mContext = RuntimeEnvironment.application;
|
||||
mController = new StorageItemPreferenceController(mContext, mFragment, mVolume, mSvp);
|
||||
// Note: null is passed as the Lifecycle because we are handling it outside of the normal
|
||||
// Settings fragment lifecycle for test purposes.
|
||||
mController = new StorageItemPreferenceController(mContext, null, mFragment, mVolume, mSvp);
|
||||
mPreference = new StorageItemPreferenceAlternate(mContext);
|
||||
|
||||
// Inflate the preference and the widget.
|
||||
LayoutInflater inflater = LayoutInflater.from(mContext);
|
||||
inflater.inflate(mPreference.getLayoutResource(), new LinearLayout(mContext), false);
|
||||
final View view = inflater.inflate(
|
||||
mPreference.getLayoutResource(), new LinearLayout(mContext), false);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -142,4 +159,46 @@ public class StorageItemPreferenceControllerTest {
|
||||
assertThat(intent.getAction()).isEqualTo(browseIntent.getAction());
|
||||
assertThat(intent.getData()).isEqualTo(browseIntent.getData());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMeasurementCompletedUpdatesPreferences() {
|
||||
StorageItemPreferenceAlternate audio = new StorageItemPreferenceAlternate(mContext);
|
||||
StorageItemPreferenceAlternate image = new StorageItemPreferenceAlternate(mContext);
|
||||
StorageItemPreferenceAlternate games = new StorageItemPreferenceAlternate(mContext);
|
||||
StorageItemPreferenceAlternate apps = new StorageItemPreferenceAlternate(mContext);
|
||||
StorageItemPreferenceAlternate system = new StorageItemPreferenceAlternate(mContext);
|
||||
StorageItemPreferenceAlternate files = new StorageItemPreferenceAlternate(mContext);
|
||||
PreferenceScreen screen = mock(PreferenceScreen.class);
|
||||
when(screen.findPreference(
|
||||
Mockito.eq(StorageItemPreferenceController.AUDIO_KEY))).thenReturn(audio);
|
||||
when(screen.findPreference(
|
||||
Mockito.eq(StorageItemPreferenceController.PHOTO_KEY))).thenReturn(image);
|
||||
when(screen.findPreference(
|
||||
Mockito.eq(StorageItemPreferenceController.GAME_KEY))).thenReturn(games);
|
||||
when(screen.findPreference(
|
||||
Mockito.eq(StorageItemPreferenceController.OTHER_APPS_KEY))).thenReturn(apps);
|
||||
when(screen.findPreference(
|
||||
Mockito.eq(StorageItemPreferenceController.SYSTEM_KEY))).thenReturn(system);
|
||||
when(screen.findPreference(
|
||||
Mockito.eq(StorageItemPreferenceController.FILES_KEY))).thenReturn(files);
|
||||
mController.displayPreference(screen);
|
||||
|
||||
StorageMeasurement.MeasurementDetails details = new StorageMeasurement.MeasurementDetails();
|
||||
details.appsSize.put(0, KILOBYTE);
|
||||
HashMap<String, Long> mediaSizes = new HashMap<>();
|
||||
mediaSizes.put(Environment.DIRECTORY_PICTURES, KILOBYTE * 2);
|
||||
mediaSizes.put(Environment.DIRECTORY_MOVIES, KILOBYTE * 3);
|
||||
mediaSizes.put(Environment.DIRECTORY_MUSIC, KILOBYTE * 4);
|
||||
mediaSizes.put(Environment.DIRECTORY_DOWNLOADS, KILOBYTE * 5);
|
||||
details.mediaSize.put(0, mediaSizes);
|
||||
mController.setSystemSize(KILOBYTE * 6);
|
||||
mController.onDetailsChanged(details);
|
||||
|
||||
assertThat(audio.getSummary().toString()).isEqualTo("4.00KB");
|
||||
assertThat(image.getSummary().toString()).isEqualTo("5.00KB");
|
||||
assertThat(games.getSummary().toString()).isEqualTo("0");
|
||||
assertThat(apps.getSummary().toString()).isEqualTo("1.00KB");
|
||||
assertThat(system.getSummary().toString()).isEqualTo("6.00KB");
|
||||
assertThat(files.getSummary().toString()).isEqualTo("5.00KB");
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user