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

Commit d3cb79a1 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Cache mechanism for Storage page" into tm-dev

parents 4003526d c23be3fa
Loading
Loading
Loading
Loading
+47 −9
Original line number Diff line number Diff line
@@ -47,6 +47,7 @@ import com.android.settings.deviceinfo.storage.AutomaticStorageManagementSwitchP
import com.android.settings.deviceinfo.storage.DiskInitFragment;
import com.android.settings.deviceinfo.storage.SecondaryUserController;
import com.android.settings.deviceinfo.storage.StorageAsyncLoader;
import com.android.settings.deviceinfo.storage.StorageCacheHelper;
import com.android.settings.deviceinfo.storage.StorageEntry;
import com.android.settings.deviceinfo.storage.StorageItemPreferenceController;
import com.android.settings.deviceinfo.storage.StorageSelectionPreferenceController;
@@ -109,6 +110,8 @@ public class StorageDashboardFragment extends DashboardFragment
    private boolean mIsWorkProfile;
    private int mUserId;
    private Preference mFreeUpSpacePreference;
    private boolean mIsLoadedFromCache;
    private StorageCacheHelper mStorageCacheHelper;

    private final StorageEventListener mStorageEventListener = new StorageEventListener() {
        @Override
@@ -239,15 +242,27 @@ public class StorageDashboardFragment extends DashboardFragment
            mPreferenceController.setVolume(null);
            return;
        }

        if (mStorageCacheHelper.hasCachedSizeInfo() && mSelectedStorageEntry.isPrivate()) {
            StorageCacheHelper.StorageCache cachedData = mStorageCacheHelper.retrieveCachedSize();
            mPreferenceController.setVolume(mSelectedStorageEntry.getVolumeInfo());
            mPreferenceController.setUsedSize(cachedData.usedSize);
            mPreferenceController.setTotalSize(cachedData.totalSize);
        }

        if (mSelectedStorageEntry.isPrivate()) {
            mStorageInfo = null;
            mAppsResult = null;
            // Hide the loading spinner if there is cached data.
            if (mStorageCacheHelper.hasCachedSizeInfo()) {
                //TODO(b/220259287): apply cache mechanism to secondary user
                mPreferenceController.onLoadFinished(mAppsResult, mUserId);
            } else {
                maybeSetLoading(isQuotaSupported());

                // To prevent flicker, sets null volume to hide category preferences.
                // onReceivedSizes will setVolume with the volume of selected storage.
                mPreferenceController.setVolume(null);

            }
            // Stats data is only available on private volumes.
            getLoaderManager().restartLoader(STORAGE_JOB_ID, Bundle.EMPTY, this);
            getLoaderManager()
@@ -277,6 +292,16 @@ public class StorageDashboardFragment extends DashboardFragment

        initializePreference();
        initializeOptionsMenu(activity);

        if (mStorageCacheHelper.hasCachedSizeInfo()) {
            mIsLoadedFromCache = true;
            mStorageEntries.clear();
            mStorageEntries.addAll(
                    StorageUtils.getAllStorageEntries(getContext(), mStorageManager));
            refreshUi();
            updateSecondaryUserControllers(mSecondaryUsers, mAppsResult);
            setSecondaryUsersVisible(true);
        }
    }

    private void initializePreference() {
@@ -291,6 +316,7 @@ public class StorageDashboardFragment extends DashboardFragment
        mUserManager = context.getSystemService(UserManager.class);
        mIsWorkProfile = false;
        mUserId = UserHandle.myUserId();
        mStorageCacheHelper = new StorageCacheHelper(getContext(), mUserId);

        super.onAttach(context);
        use(AutomaticStorageManagementSwitchPreferenceController.class).setFragmentManager(
@@ -323,9 +349,14 @@ public class StorageDashboardFragment extends DashboardFragment
    public void onResume() {
        super.onResume();

        if (mIsLoadedFromCache) {
            mIsLoadedFromCache = false;
        } else {
            mStorageEntries.clear();
        mStorageEntries.addAll(StorageUtils.getAllStorageEntries(getContext(), mStorageManager));
            mStorageEntries.addAll(
                    StorageUtils.getAllStorageEntries(getContext(), mStorageManager));
            refreshUi();
        }
        mStorageManager.registerListener(mStorageEventListener);
    }

@@ -333,6 +364,11 @@ public class StorageDashboardFragment extends DashboardFragment
    public void onPause() {
        super.onPause();
        mStorageManager.unregisterListener(mStorageEventListener);
        // Destroy the data loaders to prevent unnecessary data loading when switching back to the
        // page.
        getLoaderManager().destroyLoader(STORAGE_JOB_ID);
        getLoaderManager().destroyLoader(ICON_JOB_ID);
        getLoaderManager().destroyLoader(VOLUME_SIZE_JOB_ID);
    }

    @Override
@@ -359,6 +395,8 @@ public class StorageDashboardFragment extends DashboardFragment
        mPreferenceController.setVolume(mSelectedStorageEntry.getVolumeInfo());
        mPreferenceController.setUsedSize(privateUsedBytes);
        mPreferenceController.setTotalSize(mStorageInfo.totalBytes);
        // Cache total size and used size
        mStorageCacheHelper.cacheTotalSizeAndUsedSize(mStorageInfo.totalBytes, privateUsedBytes);
        for (int i = 0, size = mSecondaryUsers.size(); i < size; i++) {
            final AbstractPreferenceController controller = mSecondaryUsers.get(i);
            if (controller instanceof SecondaryUserController) {
+1 −1
Original line number Diff line number Diff line
@@ -66,7 +66,7 @@ public class StorageItemPreference extends Preference {
            return;

        mProgressBar.setMax(PROGRESS_MAX);
        mProgressBar.setProgress(mProgressPercent);
        mProgressBar.setProgress(mProgressPercent, true /* animate */);
    }

    @Override
+3 −0
Original line number Diff line number Diff line
@@ -183,6 +183,9 @@ public class SecondaryUserController extends AbstractPreferenceController implem

    @Override
    public void handleResult(SparseArray<StorageAsyncLoader.StorageResult> stats) {
        if (stats == null) {
            return;
        }
        final StorageAsyncLoader.StorageResult result = stats.get(getUser().id);
        if (result != null) {
            setSize(result.externalStats.totalBytes);
+115 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2022 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;

/**
 * A utility class to cache and restore the storage size information.
 */
public class StorageCacheHelper {

    private static final String SHARED_PREFERENCE_NAME = "StorageCache";
    private static final String TOTAL_SIZE_KEY = "total_size_key";
    private static final String USED_SIZE_KEY = "used_size_key";
    private static final String IMAGES_SIZE_KEY = "images_size_key";
    private static final String VIDEOS_SIZE_KEY = "videos_size_key";
    private static final String AUDIO_SIZE_KEY = "audio_size_key";
    private static final String APPS_SIZE_KEY = "apps_size_key";
    private static final String GAMES_SIZE_KEY = "games_size_key";
    private static final String DOCUMENTS_AND_OTHER_SIZE_KEY = "documents_and_other_size_key";
    private static final String TRASH_SIZE_KEY = "trash_size_key";
    private static final String SYSTEM_SIZE_KEY = "system_size_key";

    private final SharedPreferences mSharedPreferences;

    public StorageCacheHelper(Context context, int userId) {
        String sharedPrefName = SHARED_PREFERENCE_NAME + userId;
        mSharedPreferences = context.getSharedPreferences(sharedPrefName, Context.MODE_PRIVATE);
    }

    /**
     * Returns true if there's a cached size info.
     */
    public boolean hasCachedSizeInfo() {
        return mSharedPreferences.getAll().size() > 0;
    }

    /**
     * Cache the size info
     * @param data a data about the file size info.
     */
    public void cacheSizeInfo(StorageCache data) {
        mSharedPreferences
                .edit()
                .putLong(IMAGES_SIZE_KEY, data.imagesSize)
                .putLong(VIDEOS_SIZE_KEY, data.videosSize)
                .putLong(AUDIO_SIZE_KEY, data.audioSize)
                .putLong(APPS_SIZE_KEY, data.allAppsExceptGamesSize)
                .putLong(GAMES_SIZE_KEY, data.gamesSize)
                .putLong(DOCUMENTS_AND_OTHER_SIZE_KEY, data.documentsAndOtherSize)
                .putLong(TRASH_SIZE_KEY, data.trashSize)
                .putLong(SYSTEM_SIZE_KEY, data.systemSize)
                .apply();
    }

    /**
     * Cache total size and used size
     */
    public void cacheTotalSizeAndUsedSize(long totalSize, long usedSize) {
        mSharedPreferences
                .edit()
                .putLong(TOTAL_SIZE_KEY, totalSize)
                .putLong(USED_SIZE_KEY, usedSize)
                .apply();
    }

    /**
     * Returns a cached data about all file size information.
     */
    public StorageCache retrieveCachedSize() {
        StorageCache result = new StorageCache();
        result.totalSize = mSharedPreferences.getLong(TOTAL_SIZE_KEY, 0);
        result.usedSize = mSharedPreferences.getLong(USED_SIZE_KEY, 0);
        result.imagesSize = mSharedPreferences.getLong(IMAGES_SIZE_KEY, 0);
        result.videosSize = mSharedPreferences.getLong(VIDEOS_SIZE_KEY, 0);
        result.audioSize = mSharedPreferences.getLong(AUDIO_SIZE_KEY, 0);
        result.allAppsExceptGamesSize = mSharedPreferences.getLong(APPS_SIZE_KEY, 0);
        result.gamesSize = mSharedPreferences.getLong(GAMES_SIZE_KEY, 0);
        result.documentsAndOtherSize = mSharedPreferences.getLong(DOCUMENTS_AND_OTHER_SIZE_KEY, 0);
        result.trashSize = mSharedPreferences.getLong(TRASH_SIZE_KEY, 0);
        result.systemSize = mSharedPreferences.getLong(SYSTEM_SIZE_KEY, 0);
        return result;
    }

    /**
     *  All the cached data about the file size information.
     */
    public static class StorageCache {
        public long totalSize;
        public long usedSize;
        public long gamesSize;
        public long allAppsExceptGamesSize;
        public long audioSize;
        public long imagesSize;
        public long videosSize;
        public long documentsAndOtherSize;
        public long trashSize;
        public long systemSize;
    }
}
+76 −36
Original line number Diff line number Diff line
@@ -34,6 +34,7 @@ import android.util.Log;
import android.util.SparseArray;
import android.widget.Toast;

import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import androidx.fragment.app.Fragment;
import androidx.preference.Preference;
@@ -135,7 +136,11 @@ public class StorageItemPreferenceController extends AbstractPreferenceControlle

    private boolean mIsWorkProfile;

    private static final String AUTHORITY_MEDIA = "com.android.providers.media.documents";
    private StorageCacheHelper mStorageCacheHelper;
    // The mIsDocumentsPrefShown being used here is to prevent a flicker problem from displaying
    // the Document entry.
    private boolean mIsDocumentsPrefShown;
    private boolean mIsPreferenceOrderedBySize;

    public StorageItemPreferenceController(Context context, Fragment hostFragment,
            VolumeInfo volume, StorageVolumeProvider svp, boolean isWorkProfile) {
@@ -148,6 +153,8 @@ public class StorageItemPreferenceController extends AbstractPreferenceControlle
        mIsWorkProfile = isWorkProfile;
        mMetricsFeatureProvider = FeatureFactory.getFactory(context).getMetricsFeatureProvider();
        mUserId = getCurrentUserId();
        mIsDocumentsPrefShown = isDocumentsPrefShown();
        mStorageCacheHelper = new StorageCacheHelper(mContext, mUserId);

        mImagesUri = Uri.parse(context.getResources()
                .getString(R.string.config_images_storage_category_uri));
@@ -267,14 +274,17 @@ public class StorageItemPreferenceController extends AbstractPreferenceControlle
        // If we don't have a shared volume for our internal storage (or the shared volume isn't
        // mounted as readable for whatever reason), we should hide the File preference.
        if (visible) {
            final VolumeInfo sharedVolume = mSvp.findEmulatedForPrivate(mVolume);
            mDocumentsAndOtherPreference.setVisible(sharedVolume != null
                    && sharedVolume.isMountedReadable());
            mDocumentsAndOtherPreference.setVisible(mIsDocumentsPrefShown);
        } else {
            mDocumentsAndOtherPreference.setVisible(false);
        }
    }

    private boolean isDocumentsPrefShown() {
        VolumeInfo sharedVolume = mSvp.findEmulatedForPrivate(mVolume);
        return sharedVolume != null && sharedVolume.isMountedReadable();
    }

    private void updatePrivateStorageCategoryPreferencesOrder() {
        if (mScreen == null || !isValidPrivateVolume()) {
            return;
@@ -360,19 +370,54 @@ public class StorageItemPreferenceController extends AbstractPreferenceControlle
        mTrashPreference = screen.findPreference(TRASH_KEY);
    }

    /** Fragments use it to set storage result and update UI of this controller. */
    public void onLoadFinished(SparseArray<StorageAsyncLoader.StorageResult> result, int userId) {
        final StorageAsyncLoader.StorageResult data = result.get(userId);
    /**
     * Fragments use it to set storage result and update UI of this controller.
     * @param result The StorageResult from StorageAsyncLoader. This allows a nullable result.
     *               When it's null, the cached storage size info will be used instead.
     * @param userId User ID to get the storage size info
     */
    public void onLoadFinished(@Nullable SparseArray<StorageAsyncLoader.StorageResult> result,
            int userId) {
        // Calculate the size info for each category
        StorageCacheHelper.StorageCache storageCache = getSizeInfo(result, userId);
        // Set size info to each preference
        mImagesPreference.setStorageSize(storageCache.imagesSize, mTotalSize);
        mVideosPreference.setStorageSize(storageCache.videosSize, mTotalSize);
        mAudioPreference.setStorageSize(storageCache.audioSize, mTotalSize);
        mAppsPreference.setStorageSize(storageCache.allAppsExceptGamesSize, mTotalSize);
        mGamesPreference.setStorageSize(storageCache.gamesSize, mTotalSize);
        mDocumentsAndOtherPreference.setStorageSize(storageCache.documentsAndOtherSize, mTotalSize);
        mTrashPreference.setStorageSize(storageCache.trashSize, mTotalSize);
        if (mSystemPreference != null) {
            mSystemPreference.setStorageSize(storageCache.systemSize, mTotalSize);
        }
        // Cache the size info
        if (result != null) {
            mStorageCacheHelper.cacheSizeInfo(storageCache);
        }

        mImagesPreference.setStorageSize(data.imagesSize, mTotalSize);
        mVideosPreference.setStorageSize(data.videosSize, mTotalSize);
        mAudioPreference.setStorageSize(data.audioSize, mTotalSize);
        mAppsPreference.setStorageSize(data.allAppsExceptGamesSize, mTotalSize);
        mGamesPreference.setStorageSize(data.gamesSize, mTotalSize);
        mDocumentsAndOtherPreference.setStorageSize(data.documentsAndOtherSize, mTotalSize);
        mTrashPreference.setStorageSize(data.trashSize, mTotalSize);
        // Sort the preference according to size info in descending order
        if (!mIsPreferenceOrderedBySize) {
            updatePrivateStorageCategoryPreferencesOrder();
            mIsPreferenceOrderedBySize = true;
        }
        setPrivateStorageCategoryPreferencesVisibility(true);
    }

        if (mSystemPreference != null) {
    private StorageCacheHelper.StorageCache getSizeInfo(
            SparseArray<StorageAsyncLoader.StorageResult> result, int userId) {
        if (result == null) {
            return mStorageCacheHelper.retrieveCachedSize();
        }
        StorageAsyncLoader.StorageResult data = result.get(userId);
        StorageCacheHelper.StorageCache storageCache = new StorageCacheHelper.StorageCache();
        storageCache.imagesSize = data.imagesSize;
        storageCache.videosSize = data.videosSize;
        storageCache.audioSize = data.audioSize;
        storageCache.allAppsExceptGamesSize = data.allAppsExceptGamesSize;
        storageCache.gamesSize = data.gamesSize;
        storageCache.documentsAndOtherSize = data.documentsAndOtherSize;
        storageCache.trashSize = data.trashSize;
        // Everything else that hasn't already been attributed is tracked as
        // belonging to system.
        long attributedSize = 0;
@@ -388,14 +433,9 @@ public class StorageItemPreferenceController extends AbstractPreferenceControlle
                            + otherData.allAppsExceptGamesSize;
            attributedSize -= otherData.duplicateCodeSize;
        }

            final long systemSize = Math.max(DataUnit.GIBIBYTES.toBytes(1),
        storageCache.systemSize = Math.max(DataUnit.GIBIBYTES.toBytes(1),
                mUsedBytes - attributedSize);
            mSystemPreference.setStorageSize(systemSize, mTotalSize);
        }

        updatePrivateStorageCategoryPreferencesOrder();
        setPrivateStorageCategoryPreferencesVisibility(true);
        return storageCache;
    }

    public void setUsedSize(long usedSizeBytes) {
Loading