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

Commit cad29591 authored by Daniel Nishi's avatar Daniel Nishi Committed by android-build-merger
Browse files

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

am: 7fae6c67

Change-Id: I5e29852872dd08e0e5bb3f1822127879dc354319
parents 22fc0975 7fae6c67
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.