Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 88480919 authored by Daniel Nishi's avatar Daniel Nishi
Browse files

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
parent 8cc6f9f7
Loading
Loading
Loading
Loading
+4 −2
Original line number Diff line number Diff line
@@ -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;
+138 −8
Original line number Diff line number Diff line
@@ -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;
    }
}
+61 −2
Original line number Diff line number Diff line
@@ -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");
    }
}
 No newline at end of file