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

Commit 7fae6c67 authored by Daniel Nishi's avatar Daniel Nishi Committed by Android (Google) Code Review
Browse files

Merge "Cache storage values for fast loading." into oc-mr1-dev

parents 40b8d3d2 fb302de0
Loading
Loading
Loading
Loading
+50 −1
Original line number Diff line number Diff line
@@ -40,6 +40,7 @@ import com.android.settings.applications.UserManagerWrapper;
import com.android.settings.applications.UserManagerWrapperImpl;
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.SecondaryUserController;
import com.android.settings.deviceinfo.storage.StorageAsyncLoader;
import com.android.settings.deviceinfo.storage.StorageItemPreferenceController;
@@ -68,6 +69,7 @@ public class StorageDashboardFragment extends DashboardFragment
    private VolumeInfo mVolume;
    private PrivateStorageInfo mStorageInfo;
    private SparseArray<StorageAsyncLoader.AppsStorageResult> mAppsResult;
    private CachedStorageValuesHelper mCachedStorageValuesHelper;

    private StorageSummaryDonutPreferenceController mSummaryController;
    private StorageItemPreferenceController mPreferenceController;
@@ -102,8 +104,11 @@ public class StorageDashboardFragment extends DashboardFragment
    @Override
    public void onViewCreated(View v, Bundle savedInstanceState) {
        super.onViewCreated(v, savedInstanceState);
        initializeCacheProvider();
        if (mAppsResult == null || mStorageInfo == null) {
            setLoading(true, false);
        }
    }

    @Override
    public void onResume() {
@@ -249,6 +254,7 @@ public class StorageDashboardFragment extends DashboardFragment
    public void onLoadFinished(Loader<SparseArray<StorageAsyncLoader.AppsStorageResult>> loader,
            SparseArray<StorageAsyncLoader.AppsStorageResult> data) {
        mAppsResult = data;
        maybeCacheFreshValues();
        onReceivedSizes();
    }

@@ -256,6 +262,48 @@ public class StorageDashboardFragment extends DashboardFragment
    public void onLoaderReset(Loader<SparseArray<StorageAsyncLoader.AppsStorageResult>> loader) {
    }

    @VisibleForTesting
    public void setCachedStorageValuesHelper(CachedStorageValuesHelper helper) {
        mCachedStorageValuesHelper = helper;
    }

    @VisibleForTesting
    public PrivateStorageInfo getPrivateStorageInfo() {
        return mStorageInfo;
    }

    @VisibleForTesting
    public SparseArray<StorageAsyncLoader.AppsStorageResult> getAppsStorageResult() {
        return mAppsResult;
    }

    @VisibleForTesting
    public void initializeCachedValues() {
        PrivateStorageInfo info = mCachedStorageValuesHelper.getCachedPrivateStorageInfo();
        SparseArray<StorageAsyncLoader.AppsStorageResult> loaderResult =
                mCachedStorageValuesHelper.getCachedAppsStorageResult();
        if (info == null || loaderResult == null) {
            return;
        }

        mStorageInfo = info;
        mAppsResult = loaderResult;
    }

    private void initializeCacheProvider() {
        mCachedStorageValuesHelper =
                new CachedStorageValuesHelper(getContext(), UserHandle.myUserId());
        initializeCachedValues();
        onReceivedSizes();
    }

    private void maybeCacheFreshValues() {
        if (mStorageInfo != null && mAppsResult != null) {
            mCachedStorageValuesHelper.cacheResult(
                    mStorageInfo, mAppsResult.get(UserHandle.myUserId()));
        }
    }

    /**
     * IconLoaderCallbacks exists because StorageDashboardFragment already implements
     * LoaderCallbacks for a different type.
@@ -308,6 +356,7 @@ public class StorageDashboardFragment extends DashboardFragment
            }

            mStorageInfo = privateStorageInfo;
            maybeCacheFreshValues();
            onReceivedSizes();
        }
    }
+172 −0
Original line number Diff line number Diff line
/*
 * 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.support.annotation.VisibleForTesting;
import android.util.SparseArray;

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 MUSIC_APPS_SIZE_KEY = "music_apps_size";
    public static final String VIDEO_APPS_SIZE_KEY = "video_apps_size";
    public static final String PHOTO_APPS_SIZE_KEY = "photo_apps_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);
    }

    public SparseArray<StorageAsyncLoader.AppsStorageResult> getCachedAppsStorageResult() {
        if (!isDataValid()) {
            return null;
        }
        final long gamesSize = mSharedPreferences.getLong(GAME_APPS_SIZE_KEY, -1);
        final long musicAppsSize = mSharedPreferences.getLong(MUSIC_APPS_SIZE_KEY, -1);
        final long videoAppsSize = mSharedPreferences.getLong(VIDEO_APPS_SIZE_KEY, -1);
        final long photoAppSize = mSharedPreferences.getLong(PHOTO_APPS_SIZE_KEY, -1);
        final long otherAppsSize = mSharedPreferences.getLong(OTHER_APPS_SIZE_KEY, -1);
        final long cacheSize = mSharedPreferences.getLong(CACHE_APPS_SIZE_KEY, -1);
        if (gamesSize < 0
                || musicAppsSize < 0
                || videoAppsSize < 0
                || photoAppSize < 0
                || otherAppsSize < 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.AppsStorageResult result =
                new StorageAsyncLoader.AppsStorageResult();
        result.gamesSize = gamesSize;
        result.musicAppsSize = musicAppsSize;
        result.videoAppsSize = videoAppsSize;
        result.photosAppsSize = photoAppSize;
        result.otherAppsSize = otherAppsSize;
        result.cacheSize = cacheSize;
        result.externalStats = externalStats;
        final SparseArray<StorageAsyncLoader.AppsStorageResult> resultArray = new SparseArray<>();
        resultArray.append(mUserId, result);
        return resultArray;
    }

    public void cacheResult(
            PrivateStorageInfo storageInfo, StorageAsyncLoader.AppsStorageResult result) {
        mSharedPreferences
                .edit()
                .putLong(FREE_BYTES_KEY, storageInfo.freeBytes)
                .putLong(TOTAL_BYTES_KEY, storageInfo.totalBytes)
                .putLong(GAME_APPS_SIZE_KEY, result.gamesSize)
                .putLong(MUSIC_APPS_SIZE_KEY, result.musicAppsSize)
                .putLong(VIDEO_APPS_SIZE_KEY, result.videoAppsSize)
                .putLong(PHOTO_APPS_SIZE_KEY, result.photosAppsSize)
                .putLong(OTHER_APPS_SIZE_KEY, result.otherAppsSize)
                .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();
        }
    }
}
+46 −0
Original line number Diff line number Diff line
@@ -20,13 +20,18 @@ import static com.google.common.truth.Truth.assertThat;

import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import android.app.Activity;
import android.os.storage.StorageManager;
import android.provider.SearchIndexableResource;
import android.util.SparseArray;

import com.android.settings.deviceinfo.storage.CachedStorageValuesHelper;
import com.android.settings.deviceinfo.storage.StorageAsyncLoader;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.TestConfig;
import com.android.settingslib.deviceinfo.PrivateStorageInfo;
import com.android.settingslib.drawer.CategoryKey;

import org.junit.Before;
@@ -68,6 +73,47 @@ 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.AppsStorageResult> result = new SparseArray<>();
        when(helper.getCachedAppsStorageResult()).thenReturn(result);

        mFragment.setCachedStorageValuesHelper(helper);
        mFragment.initializeCachedValues();

        assertThat(mFragment.getPrivateStorageInfo()).isEqualTo(info);
        assertThat(mFragment.getAppsStorageResult()).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.getAppsStorageResult()).isNull();
    }

    @Test
    public void test_cacheProviderDoesntProvideValuesIfVolumeInfoMissing() {
        CachedStorageValuesHelper helper = mock(CachedStorageValuesHelper.class);
        SparseArray<StorageAsyncLoader.AppsStorageResult> result = new SparseArray<>();
        when(helper.getCachedAppsStorageResult()).thenReturn(result);

        mFragment.setCachedStorageValuesHelper(helper);
        mFragment.initializeCachedValues();

        assertThat(mFragment.getPrivateStorageInfo()).isNull();
        assertThat(mFragment.getAppsStorageResult()).isNull();
    }

    @Test
    public void testSearchIndexProvider_shouldIndexResource() {
        final List<SearchIndexableResource> indexRes =
+295 −0

File added.

Preview size limit exceeded, changes collapsed.