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

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

Merge "Storage Settings hides categories when loading" into sc-dev

parents d9aa0b07 51b3e7a0
Loading
Loading
Loading
Loading
+1 −2
Original line number Diff line number Diff line
@@ -24,8 +24,7 @@
        android:order="4"
        android:title="@string/storage_free_up_space_title"
        android:summary="@string/storage_free_up_space_summary"
        android:icon="@drawable/ic_files_go_round"
        settings:allowDividerAbove="true"/>
        android:icon="@drawable/ic_files_go_round"/>
    <!-- Preference order 100~200 are 'ONLY' for storage category preferences below. -->
    <Preference
        android:key="pref_public_storage"
+24 −39
Original line number Diff line number Diff line
@@ -37,7 +37,6 @@ import com.android.settings.R;
import com.android.settings.Utils;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.dashboard.profileselector.ProfileSelectFragment;
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.StorageEntry;
@@ -54,6 +53,7 @@ import com.android.settingslib.deviceinfo.StorageManagerVolumeProvider;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

/**
 * Storage Settings main UI is composed by 3 fragments:
@@ -85,7 +85,6 @@ public class StorageCategoryFragment extends DashboardFragment
    private StorageEntry mSelectedStorageEntry;
    private PrivateStorageInfo mStorageInfo;
    private SparseArray<StorageAsyncLoader.StorageResult> mAppsResult;
    private CachedStorageValuesHelper mCachedStorageValuesHelper;

    private StorageItemPreferenceController mPreferenceController;
    private List<AbstractPreferenceController> mSecondaryUsers;
@@ -104,6 +103,10 @@ public class StorageCategoryFragment extends DashboardFragment
            return;
        }

        // To prevent flicker, hides secondary users preference.
        // onReceivedSizes will set it visible for private storage.
        setSecondaryUsersVisible(false);

        if (!mSelectedStorageEntry.isMounted()) {
            // Set null volume to hide category stats.
            mPreferenceController.setVolume(null);
@@ -114,6 +117,10 @@ public class StorageCategoryFragment extends DashboardFragment
            mAppsResult = null;
            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()
@@ -157,7 +164,6 @@ public class StorageCategoryFragment extends DashboardFragment
    @Override
    public void onViewCreated(View v, Bundle savedInstanceState) {
        super.onViewCreated(v, savedInstanceState);
        initializeCacheProvider();

        EntityHeaderController.newInstance(getActivity(), this /*fragment*/,
                null /* header view */)
@@ -184,6 +190,10 @@ public class StorageCategoryFragment extends DashboardFragment
            return;
        }

        if (getView().findViewById(R.id.loading_container).getVisibility() == View.VISIBLE) {
            setLoading(false /* loading */, true /* animate */);
        }

        final long privateUsedBytes = mStorageInfo.totalBytes - mStorageInfo.freeBytes;
        mPreferenceController.setVolume(mSelectedStorageEntry.getVolumeInfo());
        mPreferenceController.setUsedSize(privateUsedBytes);
@@ -198,10 +208,7 @@ public class StorageCategoryFragment extends DashboardFragment

        mPreferenceController.onLoadFinished(mAppsResult, mUserId);
        updateSecondaryUserControllers(mSecondaryUsers, mAppsResult);

        if (getView().findViewById(R.id.loading_container).getVisibility() == View.VISIBLE) {
            setLoading(false, true);
        }
        setSecondaryUsersVisible(true);
    }

    @Override
@@ -263,7 +270,6 @@ public class StorageCategoryFragment extends DashboardFragment
    public void onLoadFinished(Loader<SparseArray<StorageAsyncLoader.StorageResult>> loader,
            SparseArray<StorageAsyncLoader.StorageResult> data) {
        mAppsResult = data;
        maybeCacheFreshValues();
        onReceivedSizes();
    }

@@ -286,11 +292,6 @@ public class StorageCategoryFragment extends DashboardFragment
        return false;
    }

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

    @VisibleForTesting
    public PrivateStorageInfo getPrivateStorageInfo() {
        return mStorageInfo;
@@ -311,19 +312,6 @@ public class StorageCategoryFragment extends DashboardFragment
        mAppsResult = info;
    }

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

        mStorageInfo = info;
        mAppsResult = loaderResult;
    }

    /**
     * Activate loading UI and animation if it's necessary.
     */
@@ -337,24 +325,22 @@ public class StorageCategoryFragment extends DashboardFragment
        }
    }

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

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

    private boolean isQuotaSupported() {
        return mSelectedStorageEntry.isMounted()
                && getActivity().getSystemService(StorageStatsManager.class)
                        .isQuotaSupported(mSelectedStorageEntry.getFsUuid());
    }

    private void setSecondaryUsersVisible(boolean visible) {
        final Optional<SecondaryUserController> secondaryUserController = mSecondaryUsers.stream()
                .filter(controller -> controller instanceof SecondaryUserController)
                .map(controller -> (SecondaryUserController) controller)
                .findAny();
        if (secondaryUserController.isPresent()) {
            secondaryUserController.get().setPreferenceGroupVisible(visible);
        }
    }

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

            mStorageInfo = privateStorageInfo;
            maybeCacheFreshValues();
            onReceivedSizes();
        }
    }
+24 −39
Original line number Diff line number Diff line
@@ -44,7 +44,6 @@ import com.android.settings.R;
import com.android.settings.Utils;
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.DiskInitFragment;
import com.android.settings.deviceinfo.storage.SecondaryUserController;
import com.android.settings.deviceinfo.storage.StorageAsyncLoader;
@@ -68,6 +67,7 @@ import com.android.settingslib.search.SearchIndexable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;

/**
 * Storage Settings main UI is composed by 3 fragments:
@@ -101,7 +101,6 @@ public class StorageDashboardFragment extends DashboardFragment
    private StorageEntry mSelectedStorageEntry;
    private PrivateStorageInfo mStorageInfo;
    private SparseArray<StorageAsyncLoader.StorageResult> mAppsResult;
    private CachedStorageValuesHelper mCachedStorageValuesHelper;

    private StorageItemPreferenceController mPreferenceController;
    private VolumeOptionMenuController mOptionMenuController;
@@ -232,6 +231,10 @@ public class StorageDashboardFragment extends DashboardFragment
        mOptionMenuController.setSelectedStorageEntry(mSelectedStorageEntry);
        getActivity().invalidateOptionsMenu();

        // To prevent flicker, hides secondary users preference.
        // onReceivedSizes will set it visible for private storage.
        setSecondaryUsersVisible(false);

        if (!mSelectedStorageEntry.isMounted()) {
            // Set null volume to hide category stats.
            mPreferenceController.setVolume(null);
@@ -242,6 +245,10 @@ public class StorageDashboardFragment extends DashboardFragment
            mAppsResult = null;
            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()
@@ -316,7 +323,6 @@ public class StorageDashboardFragment extends DashboardFragment
    @Override
    public void onViewCreated(View v, Bundle savedInstanceState) {
        super.onViewCreated(v, savedInstanceState);
        initializeCacheProvider();

        EntityHeaderController.newInstance(getActivity(), this /*fragment*/,
                null /* header view */)
@@ -355,6 +361,10 @@ public class StorageDashboardFragment extends DashboardFragment
            return;
        }

        if (getView().findViewById(R.id.loading_container).getVisibility() == View.VISIBLE) {
            setLoading(false /* loading */, true /* animate */);
        }

        final long privateUsedBytes = mStorageInfo.totalBytes - mStorageInfo.freeBytes;
        mPreferenceController.setVolume(mSelectedStorageEntry.getVolumeInfo());
        mPreferenceController.setUsedSize(privateUsedBytes);
@@ -369,10 +379,7 @@ public class StorageDashboardFragment extends DashboardFragment

        mPreferenceController.onLoadFinished(mAppsResult, mUserId);
        updateSecondaryUserControllers(mSecondaryUsers, mAppsResult);

        if (getView().findViewById(R.id.loading_container).getVisibility() == View.VISIBLE) {
            setLoading(false, true);
        }
        setSecondaryUsersVisible(true);
    }

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

@@ -486,11 +492,6 @@ public class StorageDashboardFragment extends DashboardFragment
        return false;
    }

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

    @VisibleForTesting
    public PrivateStorageInfo getPrivateStorageInfo() {
        return mStorageInfo;
@@ -511,19 +512,6 @@ public class StorageDashboardFragment extends DashboardFragment
        mAppsResult = info;
    }

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

        mStorageInfo = info;
        mAppsResult = loaderResult;
    }

    /**
     * Activate loading UI and animation if it's necessary.
     */
@@ -537,24 +525,22 @@ public class StorageDashboardFragment extends DashboardFragment
        }
    }

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

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

    private boolean isQuotaSupported() {
        return mSelectedStorageEntry.isMounted()
                && getActivity().getSystemService(StorageStatsManager.class)
                        .isQuotaSupported(mSelectedStorageEntry.getFsUuid());
    }

    private void setSecondaryUsersVisible(boolean visible) {
        final Optional<SecondaryUserController> secondaryUserController = mSecondaryUsers.stream()
                .filter(controller -> controller instanceof SecondaryUserController)
                .map(controller -> (SecondaryUserController) controller)
                .findAny();
        if (secondaryUserController.isPresent()) {
            secondaryUserController.get().setPreferenceGroupVisible(visible);
        }
    }

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

            mStorageInfo = privateStorageInfo;
            maybeCacheFreshValues();
            onReceivedSizes();
        }
    }
+0 −1
Original line number Diff line number Diff line
@@ -43,7 +43,6 @@ public class StorageItemPreference extends Preference {
    public StorageItemPreference(Context context, AttributeSet attrs) {
        super(context, attrs);
        setLayoutResource(R.layout.storage_item);
        setSummary(R.string.memory_calculating_size);
    }

    public void setStorageSize(long size, long total) {
+0 −184
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.util.SparseArray;

import androidx.annotation.VisibleForTesting;

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 AUDIO_SIZE_KEY = "audio_size";
    public static final String VIDEOS_SIZE_KEY = "videos_size";
    public static final String IMAGES_SIZE_KEY = "images_size";
    public static final String DOCUMENTS_AND_OTHER_SIZE_KEY = "documents_and_other_size";
    public static final String TRASH_SIZE_KEY = "trash_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);
    }

    /** Returns cached storage result or null if it's not available. */
    public SparseArray<StorageAsyncLoader.StorageResult> getCachedStorageResult() {
        if (!isDataValid()) {
            return null;
        }
        final long gamesSize = mSharedPreferences.getLong(GAME_APPS_SIZE_KEY, -1);
        final long audioSize = mSharedPreferences.getLong(AUDIO_SIZE_KEY, -1);
        final long videosSize = mSharedPreferences.getLong(VIDEOS_SIZE_KEY, -1);
        final long imagesSize = mSharedPreferences.getLong(IMAGES_SIZE_KEY, -1);
        final long documentsAndOtherSize =
                mSharedPreferences.getLong(DOCUMENTS_AND_OTHER_SIZE_KEY, -1);
        final long trashSize = mSharedPreferences.getLong(TRASH_SIZE_KEY, -1);
        final long allAppsExceptGamesSize = mSharedPreferences.getLong(OTHER_APPS_SIZE_KEY, -1);
        final long cacheSize = mSharedPreferences.getLong(CACHE_APPS_SIZE_KEY, -1);
        if (gamesSize < 0
                || audioSize < 0
                || videosSize < 0
                || imagesSize < 0
                || documentsAndOtherSize < 0
                || trashSize < 0
                || allAppsExceptGamesSize < 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.StorageResult result = new StorageAsyncLoader.StorageResult();
        result.gamesSize = gamesSize;
        result.audioSize = audioSize;
        result.videosSize = videosSize;
        result.imagesSize = imagesSize;
        result.documentsAndOtherSize = documentsAndOtherSize;
        result.trashSize = trashSize;
        result.allAppsExceptGamesSize = allAppsExceptGamesSize;
        result.cacheSize = cacheSize;
        result.externalStats = externalStats;
        final SparseArray<StorageAsyncLoader.StorageResult> resultArray = new SparseArray<>();
        resultArray.append(mUserId, result);
        return resultArray;
    }

    public void cacheResult(
            PrivateStorageInfo storageInfo, StorageAsyncLoader.StorageResult result) {
        mSharedPreferences
                .edit()
                .putLong(FREE_BYTES_KEY, storageInfo.freeBytes)
                .putLong(TOTAL_BYTES_KEY, storageInfo.totalBytes)
                .putLong(GAME_APPS_SIZE_KEY, result.gamesSize)
                .putLong(AUDIO_SIZE_KEY, result.audioSize)
                .putLong(VIDEOS_SIZE_KEY, result.videosSize)
                .putLong(IMAGES_SIZE_KEY, result.imagesSize)
                .putLong(DOCUMENTS_AND_OTHER_SIZE_KEY, result.documentsAndOtherSize)
                .putLong(TRASH_SIZE_KEY, result.trashSize)
                .putLong(OTHER_APPS_SIZE_KEY, result.allAppsExceptGamesSize)
                .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();
        }
    }
}
Loading