From c80b3ab718af6bf0c1fa423007944a04da07e2d5 Mon Sep 17 00:00:00 2001 From: Silin Huang Date: Thu, 13 May 2021 23:59:33 -0700 Subject: [PATCH 1/6] Expose Lock screen settings page. Test: atest Bug: 188105349 Change-Id: I7646f712608076037634c26d2334de4367b4452b --- AndroidManifest.xml | 14 ++++++++++++++ src/com/android/settings/Settings.java | 4 ++++ 2 files changed, 18 insertions(+) diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 61c0c4ea2db..5abe8906274 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -1078,6 +1078,20 @@ android:value="true" /> + + + + + + + + + Date: Mon, 17 May 2021 12:44:29 +0800 Subject: [PATCH 2/6] =?UTF-8?q?Fix=20=E2=80=9CLearn=20more=E2=80=9D=20link?= =?UTF-8?q?=20not=20working=20on=20Magnification=20shortcut=20page=20from?= =?UTF-8?q?=20Vision=20Settings?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Root cause: It does not allow to start another activity before SuW Completed. We should not show link for users. Solution: Remove the link Bug: 188034493 Test: Manual testing Change-Id: I25d3eb3d02a2b992411ea7b73308f3e3503cd70a --- ...ScreenMagnificationPreferenceFragmentForSetupWizard.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragmentForSetupWizard.java b/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragmentForSetupWizard.java index 86ead5c681c..016ac059873 100644 --- a/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragmentForSetupWizard.java +++ b/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragmentForSetupWizard.java @@ -44,6 +44,12 @@ public class ToggleScreenMagnificationPreferenceFragmentForSetupWizard super.onStop(); } + @Override + public int getHelpResource() { + // Hides help center in action bar and footer bar in SuW + return 0; + } + @Override public void onViewCreated(View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); From 79889460ae529f8830fb107dcd2b6a91d264ac30 Mon Sep 17 00:00:00 2001 From: menghanli Date: Mon, 17 May 2021 13:41:39 +0800 Subject: [PATCH 3/6] Remove above divider of main switch Problem: The main switch won't be the ceiling preference. It has chance to show the divider if another preference won't disable the below divider. Solution: Remove the above divider. Bug: 186066199 Test: Test: Manual testing Change-Id: I49893fa71b016f82dce9f402d47c86ec3df20a54 --- .../android/settings/widget/SettingsMainSwitchPreference.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/com/android/settings/widget/SettingsMainSwitchPreference.java b/src/com/android/settings/widget/SettingsMainSwitchPreference.java index f627e31cc2d..04317a8c48d 100644 --- a/src/com/android/settings/widget/SettingsMainSwitchPreference.java +++ b/src/com/android/settings/widget/SettingsMainSwitchPreference.java @@ -74,7 +74,7 @@ public class SettingsMainSwitchPreference extends TwoStatePreference { public void onBindViewHolder(PreferenceViewHolder holder) { super.onBindViewHolder(holder); - holder.setDividerAllowedAbove(true); + holder.setDividerAllowedAbove(false); holder.setDividerAllowedBelow(false); mMainSwitchBar = (SettingsMainSwitchBar) holder.findViewById(R.id.main_switch_bar); From c0b5ba5225609d4d3f3d8ed1200875a1446c8c6d Mon Sep 17 00:00:00 2001 From: Arc Wang Date: Thu, 6 May 2021 21:20:21 +0800 Subject: [PATCH 4/6] Storage Settings shift profile selection tab position In this change, Storage Settings main UI is composed by 3 fragments. StorageDashboardFragment only shows when there is only personal profile for current user. ProfileSelectStorageFragment (controls preferences above profile tab) and StorageDashboardNoHeaderFragment (controls preferences below profile tab) only show when current user has installed work profile. Bug: 174964885 Test: atest com.android.settings.deviceinfo atest com.android.settings.deviceinfo.storage make RunSettingsRoboTests -j ROBOTEST_FILTER=com.android.settings.deviceinfo make RunSettingsRoboTests -j ROBOTEST_FILTER=com.android.settings.deviceinfo.storage Change-Id: I50dea2fbcae39a1488e648f3ca615f54840e19d5 --- res/xml/storage_category_fragment.xml | 80 ++++ res/xml/storage_dashboard_fragment.xml | 5 +- res/xml/storage_dashboard_header_fragment.xml | 42 ++ res/xml/storage_profile_fragment.xml | 52 --- .../ProfileSelectStorageFragment.java | 279 +++++++++++- .../deviceinfo/StorageCategoryFragment.java | 415 ++++++++++++++++++ .../deviceinfo/StorageDashboardFragment.java | 102 ++--- .../deviceinfo/storage/StorageUtils.java | 57 +++ .../exempt_not_implementing_index_provider | 1 + .../ProfileSelectStorageFragmentTest.java | 59 +++ 10 files changed, 967 insertions(+), 125 deletions(-) create mode 100644 res/xml/storage_category_fragment.xml create mode 100644 res/xml/storage_dashboard_header_fragment.xml delete mode 100644 res/xml/storage_profile_fragment.xml create mode 100644 src/com/android/settings/deviceinfo/StorageCategoryFragment.java create mode 100644 tests/unit/src/com/android/settings/dashboard/profileselector/ProfileSelectStorageFragmentTest.java diff --git a/res/xml/storage_category_fragment.xml b/res/xml/storage_category_fragment.xml new file mode 100644 index 00000000000..8ac9e940f86 --- /dev/null +++ b/res/xml/storage_category_fragment.xml @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + diff --git a/res/xml/storage_dashboard_fragment.xml b/res/xml/storage_dashboard_fragment.xml index 71d07127aa3..49db958cde3 100644 --- a/res/xml/storage_dashboard_fragment.xml +++ b/res/xml/storage_dashboard_fragment.xml @@ -18,7 +18,6 @@ xmlns:android="http://schemas.android.com/apk/res/android" xmlns:settings="http://schemas.android.com/apk/res-auto" android:title="@string/storage_settings" - android:orderingFromXml="false" settings:keywords="@string/keywords_storage"> + android:icon="@drawable/ic_files_go_round" + settings:allowDividerAbove="true"/> + + + + + + diff --git a/res/xml/storage_profile_fragment.xml b/res/xml/storage_profile_fragment.xml deleted file mode 100644 index a12bdd53c41..00000000000 --- a/res/xml/storage_profile_fragment.xml +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - - - - - - - diff --git a/src/com/android/settings/dashboard/profileselector/ProfileSelectStorageFragment.java b/src/com/android/settings/dashboard/profileselector/ProfileSelectStorageFragment.java index 9e505e3607f..c4ff91b767b 100644 --- a/src/com/android/settings/dashboard/profileselector/ProfileSelectStorageFragment.java +++ b/src/com/android/settings/dashboard/profileselector/ProfileSelectStorageFragment.java @@ -16,32 +16,301 @@ package com.android.settings.dashboard.profileselector; +import android.app.Activity; +import android.app.settings.SettingsEnums; +import android.content.Context; import android.os.Bundle; +import android.os.storage.DiskInfo; +import android.os.storage.StorageEventListener; +import android.os.storage.StorageManager; +import android.os.storage.VolumeInfo; +import android.os.storage.VolumeRecord; +import android.text.TextUtils; +import androidx.annotation.VisibleForTesting; import androidx.fragment.app.Fragment; -import com.android.settings.deviceinfo.StorageDashboardFragment; +import com.android.settings.R; +import com.android.settings.Utils; +import com.android.settings.deviceinfo.StorageCategoryFragment; +import com.android.settings.deviceinfo.VolumeOptionMenuController; +import com.android.settings.deviceinfo.storage.AutomaticStorageManagementSwitchPreferenceController; +import com.android.settings.deviceinfo.storage.DiskInitFragment; +import com.android.settings.deviceinfo.storage.StorageEntry; +import com.android.settings.deviceinfo.storage.StorageSelectionPreferenceController; +import com.android.settings.deviceinfo.storage.StorageUsageProgressBarPreferenceController; +import com.android.settings.deviceinfo.storage.StorageUtils; + +import java.util.ArrayList; +import java.util.List; /** - * Storage Settings page for personal/managed profile. + * Storage Settings main UI is composed by 3 fragments: + * + * StorageDashboardFragment only shows when there is only personal profile for current user. + * + * ProfileSelectStorageFragment (controls preferences above profile tab) and + * StorageCategoryFragment (controls preferences below profile tab) only show when current + * user has installed work profile. + * + * ProfileSelectStorageFragment and StorageCategoryFragment have many similar or the same + * code as StorageDashboardFragment. Remember to sync code between these fragments when you have to + * change Storage Settings. */ public class ProfileSelectStorageFragment extends ProfileSelectFragment { + private static final String TAG = "ProfileSelStorageFrag"; + private static final String SELECTED_STORAGE_ENTRY_KEY = "selected_storage_entry_key"; + + private StorageManager mStorageManager; + + private final List mStorageEntries = new ArrayList<>(); + private StorageEntry mSelectedStorageEntry; + private Fragment[] mFragments; + + private StorageSelectionPreferenceController mStorageSelectionController; + private StorageUsageProgressBarPreferenceController mStorageUsageProgressBarController; + private VolumeOptionMenuController mOptionMenuController; + + private final StorageEventListener mStorageEventListener = new StorageEventListener() { + @Override + public void onVolumeStateChanged(VolumeInfo volumeInfo, int oldState, int newState) { + if (!StorageUtils.isStorageSettingsInterestedVolume(volumeInfo)) { + return; + } + + final StorageEntry changedStorageEntry = new StorageEntry(getContext(), volumeInfo); + switch (volumeInfo.getState()) { + case VolumeInfo.STATE_MOUNTED: + case VolumeInfo.STATE_MOUNTED_READ_ONLY: + case VolumeInfo.STATE_UNMOUNTABLE: + // Add mounted or unmountable storage in the list and show it on spinner. + // Unmountable storages are the storages which has a problem format and android + // is not able to mount it automatically. + // Users can format an unmountable storage by the UI and then use the storage. + mStorageEntries.removeIf(storageEntry -> { + return storageEntry.equals(changedStorageEntry); + }); + mStorageEntries.add(changedStorageEntry); + if (changedStorageEntry.equals(mSelectedStorageEntry)) { + mSelectedStorageEntry = changedStorageEntry; + } + refreshUi(); + break; + case VolumeInfo.STATE_REMOVED: + case VolumeInfo.STATE_UNMOUNTED: + case VolumeInfo.STATE_BAD_REMOVAL: + case VolumeInfo.STATE_EJECTING: + // Remove removed storage from list and don't show it on spinner. + if (mStorageEntries.remove(changedStorageEntry)) { + if (changedStorageEntry.equals(mSelectedStorageEntry)) { + mSelectedStorageEntry = + StorageEntry.getDefaultInternalStorageEntry(getContext()); + } + refreshUi(); + } + break; + default: + // Do nothing. + } + } + + @Override + public void onVolumeRecordChanged(VolumeRecord volumeRecord) { + if (StorageUtils.isVolumeRecordMissed(mStorageManager, volumeRecord)) { + // VolumeRecord is a metadata of VolumeInfo, if a VolumeInfo is missing + // (e.g., internal SD card is removed.) show the missing storage to users, + // users can insert the SD card or manually forget the storage from the device. + final StorageEntry storageEntry = new StorageEntry(volumeRecord); + if (!mStorageEntries.contains(storageEntry)) { + mStorageEntries.add(storageEntry); + refreshUi(); + } + } else { + // Find mapped VolumeInfo and replace with existing one for something changed. + // (e.g., Renamed.) + final VolumeInfo mappedVolumeInfo = + mStorageManager.findVolumeByUuid(volumeRecord.getFsUuid()); + if (mappedVolumeInfo == null) { + return; + } + + final boolean removeMappedStorageEntry = mStorageEntries.removeIf(storageEntry -> + storageEntry.isVolumeInfo() + && TextUtils.equals(storageEntry.getFsUuid(), volumeRecord.getFsUuid()) + ); + if (removeMappedStorageEntry) { + mStorageEntries.add(new StorageEntry(getContext(), mappedVolumeInfo)); + refreshUi(); + } + } + } + + @Override + public void onVolumeForgotten(String fsUuid) { + final StorageEntry storageEntry = new StorageEntry( + new VolumeRecord(VolumeInfo.TYPE_PUBLIC, fsUuid)); + if (mStorageEntries.remove(storageEntry)) { + if (mSelectedStorageEntry.equals(storageEntry)) { + mSelectedStorageEntry = + StorageEntry.getDefaultInternalStorageEntry(getContext()); + } + refreshUi(); + } + } + + @Override + public void onDiskScanned(DiskInfo disk, int volumeCount) { + if (!StorageUtils.isDiskUnsupported(disk)) { + return; + } + final StorageEntry storageEntry = new StorageEntry(disk); + if (!mStorageEntries.contains(storageEntry)) { + mStorageEntries.add(storageEntry); + refreshUi(); + } + } + + @Override + public void onDiskDestroyed(DiskInfo disk) { + final StorageEntry storageEntry = new StorageEntry(disk); + if (mStorageEntries.remove(storageEntry)) { + if (mSelectedStorageEntry.equals(storageEntry)) { + mSelectedStorageEntry = + StorageEntry.getDefaultInternalStorageEntry(getContext()); + } + refreshUi(); + } + } + }; + @Override public Fragment[] getFragments() { + if (mFragments != null) { + return mFragments; + } + final Bundle workBundle = new Bundle(); workBundle.putInt(EXTRA_PROFILE, ProfileType.WORK); - final Fragment workFragment = new StorageDashboardFragment(); + final Fragment workFragment = new StorageCategoryFragment(); workFragment.setArguments(workBundle); final Bundle personalBundle = new Bundle(); personalBundle.putInt(EXTRA_PROFILE, ProfileType.PERSONAL); - final Fragment personalFragment = new StorageDashboardFragment(); + final Fragment personalFragment = new StorageCategoryFragment(); personalFragment.setArguments(personalBundle); - return new Fragment[] { + mFragments = new Fragment[] { personalFragment, workFragment }; + return mFragments; + } + + @Override + protected int getPreferenceScreenResId() { + return R.xml.storage_dashboard_header_fragment; + } + + private void refreshUi() { + mStorageSelectionController.setStorageEntries(mStorageEntries); + mStorageSelectionController.setSelectedStorageEntry(mSelectedStorageEntry); + mStorageUsageProgressBarController.setSelectedStorageEntry(mSelectedStorageEntry); + + for (Fragment fragment : getFragments()) { + if (!(fragment instanceof StorageCategoryFragment)) { + throw new IllegalStateException("Wrong fragment type to refreshUi"); + } + ((StorageCategoryFragment) fragment).refreshUi(mSelectedStorageEntry); + } + + mOptionMenuController.setSelectedStorageEntry(mSelectedStorageEntry); + getActivity().invalidateOptionsMenu(); + } + + @Override + public void onCreate(Bundle icicle) { + super.onCreate(icicle); + + final Activity activity = getActivity(); + mStorageManager = activity.getSystemService(StorageManager.class); + + if (icicle == null) { + final VolumeInfo specifiedVolumeInfo = + Utils.maybeInitializeVolume(mStorageManager, getArguments()); + mSelectedStorageEntry = specifiedVolumeInfo == null + ? StorageEntry.getDefaultInternalStorageEntry(getContext()) + : new StorageEntry(getContext(), specifiedVolumeInfo); + } else { + mSelectedStorageEntry = icicle.getParcelable(SELECTED_STORAGE_ENTRY_KEY); + } + + initializeOptionsMenu(activity); + } + + @Override + public void onAttach(Context context) { + super.onAttach(context); + use(AutomaticStorageManagementSwitchPreferenceController.class).setFragmentManager( + getFragmentManager()); + mStorageSelectionController = use(StorageSelectionPreferenceController.class); + mStorageSelectionController.setOnItemSelectedListener(storageEntry -> { + mSelectedStorageEntry = storageEntry; + refreshUi(); + + if (storageEntry.isDiskInfoUnsupported() || storageEntry.isUnmountable()) { + DiskInitFragment.show(this, R.string.storage_dialog_unmountable, + storageEntry.getDiskId()); + } else if (storageEntry.isVolumeRecordMissed()) { + StorageUtils.launchForgetMissingVolumeRecordFragment(getContext(), storageEntry); + } + }); + mStorageUsageProgressBarController = use(StorageUsageProgressBarPreferenceController.class); + } + + @VisibleForTesting + void initializeOptionsMenu(Activity activity) { + mOptionMenuController = new VolumeOptionMenuController(activity, this, + mSelectedStorageEntry); + getSettingsLifecycle().addObserver(mOptionMenuController); + setHasOptionsMenu(true); + activity.invalidateOptionsMenu(); + } + + @Override + public void onResume() { + super.onResume(); + + mStorageEntries.clear(); + mStorageEntries.addAll(StorageUtils.getAllStorageEntries(getContext(), mStorageManager)); + refreshUi(); + mStorageManager.registerListener(mStorageEventListener); + } + + @Override + public void onPause() { + super.onPause(); + mStorageManager.unregisterListener(mStorageEventListener); + } + + @Override + public void onSaveInstanceState(Bundle outState) { + outState.putParcelable(SELECTED_STORAGE_ENTRY_KEY, mSelectedStorageEntry); + super.onSaveInstanceState(outState); + } + + @Override + public int getHelpResource() { + return R.string.help_url_storage_dashboard; + } + + @Override + public int getMetricsCategory() { + return SettingsEnums.SETTINGS_STORAGE_CATEGORY; + } + + @Override + protected String getLogTag() { + return TAG; } } diff --git a/src/com/android/settings/deviceinfo/StorageCategoryFragment.java b/src/com/android/settings/deviceinfo/StorageCategoryFragment.java new file mode 100644 index 00000000000..ba59498a795 --- /dev/null +++ b/src/com/android/settings/deviceinfo/StorageCategoryFragment.java @@ -0,0 +1,415 @@ +/* + * Copyright (C) 2021 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; + +import android.app.settings.SettingsEnums; +import android.app.usage.StorageStatsManager; +import android.content.Context; +import android.content.Intent; +import android.graphics.drawable.Drawable; +import android.os.Bundle; +import android.os.UserHandle; +import android.os.UserManager; +import android.os.storage.StorageManager; +import android.util.SparseArray; +import android.view.View; + +import androidx.annotation.VisibleForTesting; +import androidx.loader.app.LoaderManager; +import androidx.loader.content.Loader; +import androidx.preference.Preference; + +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; +import com.android.settings.deviceinfo.storage.StorageItemPreferenceController; +import com.android.settings.deviceinfo.storage.UserIconLoader; +import com.android.settings.deviceinfo.storage.VolumeSizesLoader; +import com.android.settings.overlay.FeatureFactory; +import com.android.settings.widget.EntityHeaderController; +import com.android.settingslib.applications.StorageStatsSource; +import com.android.settingslib.core.AbstractPreferenceController; +import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; +import com.android.settingslib.deviceinfo.PrivateStorageInfo; +import com.android.settingslib.deviceinfo.StorageManagerVolumeProvider; + +import java.util.ArrayList; +import java.util.List; + +/** + * Storage Settings main UI is composed by 3 fragments: + * + * StorageDashboardFragment only shows when there is only personal profile for current user. + * + * ProfileSelectStorageFragment (controls preferences above profile tab) and + * StorageCategoryFragment (controls preferences below profile tab) only show when current + * user has installed work profile. + * + * ProfileSelectStorageFragment and StorageCategoryFragment have many similar or the same + * code as StorageDashboardFragment. Remember to sync code between these fragments when you have to + * change Storage Settings. + */ +public class StorageCategoryFragment extends DashboardFragment + implements + LoaderManager.LoaderCallbacks>, + Preference.OnPreferenceClickListener { + private static final String TAG = "StorageCategoryFrag"; + private static final String SUMMARY_PREF_KEY = "storage_summary"; + private static final String FREE_UP_SPACE_PREF_KEY = "free_up_space"; + private static final int STORAGE_JOB_ID = 0; + private static final int ICON_JOB_ID = 1; + private static final int VOLUME_SIZE_JOB_ID = 2; + + private StorageManager mStorageManager; + private UserManager mUserManager; + private StorageEntry mSelectedStorageEntry; + private PrivateStorageInfo mStorageInfo; + private SparseArray mAppsResult; + private CachedStorageValuesHelper mCachedStorageValuesHelper; + + private StorageItemPreferenceController mPreferenceController; + private List mSecondaryUsers; + private boolean mIsWorkProfile; + private int mUserId; + private Preference mFreeUpSpacePreference; + + /** + * Refresh UI for specified storageEntry. + */ + public void refreshUi(StorageEntry storageEntry) { + mSelectedStorageEntry = storageEntry; + if (mPreferenceController == null) { + // Check null here because when onResume, StorageCategoryFragment may not + // onAttach to createPreferenceControllers and mPreferenceController will be null. + return; + } + + mPreferenceController.setVolume(mSelectedStorageEntry.getVolumeInfo()); + + if (!mSelectedStorageEntry.isMounted()) { + // Set null volume to hide category stats. + mPreferenceController.setVolume(null); + return; + } + if (mSelectedStorageEntry.isPrivate()) { + // Stats data is only available on private volumes. + getLoaderManager().restartLoader(STORAGE_JOB_ID, Bundle.EMPTY, this); + getLoaderManager() + .restartLoader(VOLUME_SIZE_JOB_ID, Bundle.EMPTY, new VolumeSizeCallbacks()); + getLoaderManager().restartLoader(ICON_JOB_ID, Bundle.EMPTY, new IconLoaderCallbacks()); + } else { + mPreferenceController.setVolume(mSelectedStorageEntry.getVolumeInfo()); + } + } + + @Override + public void onCreate(Bundle icicle) { + super.onCreate(icicle); + + mStorageManager = getActivity().getSystemService(StorageManager.class); + + initializePreference(); + } + + private void initializePreference() { + mFreeUpSpacePreference = getPreferenceScreen().findPreference(FREE_UP_SPACE_PREF_KEY); + mFreeUpSpacePreference.setOnPreferenceClickListener(this); + } + + @Override + public void onAttach(Context context) { + // These member variables are initialized befoer super.onAttach for + // createPreferenceControllers to work correctly. + mUserManager = context.getSystemService(UserManager.class); + mIsWorkProfile = getArguments().getInt(ProfileSelectFragment.EXTRA_PROFILE) + == ProfileSelectFragment.ProfileType.WORK; + mUserId = Utils.getCurrentUserId(mUserManager, mIsWorkProfile); + + super.onAttach(context); + } + + @Override + public void onViewCreated(View v, Bundle savedInstanceState) { + super.onViewCreated(v, savedInstanceState); + initializeCacheProvider(); + maybeSetLoading(isQuotaSupported()); + + EntityHeaderController.newInstance(getActivity(), this /*fragment*/, + null /* header view */) + .setRecyclerView(getListView(), getSettingsLifecycle()); + } + + @Override + public void onResume() { + super.onResume(); + + if (mSelectedStorageEntry != null) { + refreshUi(mSelectedStorageEntry); + } + } + + private void onReceivedSizes() { + boolean stopLoading = false; + if (mStorageInfo != null) { + final long privateUsedBytes = mStorageInfo.totalBytes - mStorageInfo.freeBytes; + mPreferenceController.setVolume(mSelectedStorageEntry.getVolumeInfo()); + mPreferenceController.setUsedSize(privateUsedBytes); + mPreferenceController.setTotalSize(mStorageInfo.totalBytes); + for (int i = 0, size = mSecondaryUsers.size(); i < size; i++) { + final AbstractPreferenceController controller = mSecondaryUsers.get(i); + if (controller instanceof SecondaryUserController) { + SecondaryUserController userController = (SecondaryUserController) controller; + userController.setTotalSize(mStorageInfo.totalBytes); + } + } + stopLoading = true; + } + + if (mAppsResult != null) { + mPreferenceController.onLoadFinished(mAppsResult, mUserId); + updateSecondaryUserControllers(mSecondaryUsers, mAppsResult); + stopLoading = true; + } + + // setLoading always causes a flicker, so let's avoid doing it. + if (stopLoading) { + if (getView().findViewById(R.id.loading_container).getVisibility() == View.VISIBLE) { + setLoading(false, true); + } + } + } + + @Override + public int getMetricsCategory() { + return SettingsEnums.SETTINGS_STORAGE_CATEGORY; + } + + @Override + protected String getLogTag() { + return TAG; + } + + @Override + protected int getPreferenceScreenResId() { + return R.xml.storage_category_fragment; + } + + @Override + protected List createPreferenceControllers(Context context) { + final List controllers = new ArrayList<>(); + final StorageManager sm = context.getSystemService(StorageManager.class); + mPreferenceController = new StorageItemPreferenceController(context, this, + null /* volume */, new StorageManagerVolumeProvider(sm), mIsWorkProfile); + controllers.add(mPreferenceController); + + mSecondaryUsers = SecondaryUserController.getSecondaryUserControllers(context, + mUserManager, mIsWorkProfile /* isWorkProfileOnly */); + controllers.addAll(mSecondaryUsers); + + return controllers; + } + + /** + * Updates the secondary user controller sizes. + */ + private void updateSecondaryUserControllers(List controllers, + SparseArray stats) { + for (int i = 0, size = controllers.size(); i < size; i++) { + final AbstractPreferenceController controller = controllers.get(i); + if (controller instanceof StorageAsyncLoader.ResultHandler) { + StorageAsyncLoader.ResultHandler userController = + (StorageAsyncLoader.ResultHandler) controller; + userController.handleResult(stats); + } + } + } + + @Override + public Loader> onCreateLoader(int id, + Bundle args) { + final Context context = getContext(); + return new StorageAsyncLoader(context, mUserManager, + mSelectedStorageEntry.getFsUuid(), + new StorageStatsSource(context), + context.getPackageManager()); + } + + @Override + public void onLoadFinished(Loader> loader, + SparseArray data) { + mAppsResult = data; + maybeCacheFreshValues(); + onReceivedSizes(); + } + + @Override + public void onLoaderReset(Loader> loader) { + } + + @Override + public boolean onPreferenceClick(Preference preference) { + if (preference == mFreeUpSpacePreference) { + final Context context = getContext(); + final MetricsFeatureProvider metricsFeatureProvider = + FeatureFactory.getFactory(context).getMetricsFeatureProvider(); + metricsFeatureProvider.logClickedPreference(preference, getMetricsCategory()); + metricsFeatureProvider.action(context, SettingsEnums.STORAGE_FREE_UP_SPACE_NOW); + final Intent intent = new Intent(StorageManager.ACTION_MANAGE_STORAGE); + context.startActivityAsUser(intent, new UserHandle(mUserId)); + return true; + } + return false; + } + + @VisibleForTesting + public void setCachedStorageValuesHelper(CachedStorageValuesHelper helper) { + mCachedStorageValuesHelper = helper; + } + + @VisibleForTesting + public PrivateStorageInfo getPrivateStorageInfo() { + return mStorageInfo; + } + + @VisibleForTesting + public void setPrivateStorageInfo(PrivateStorageInfo info) { + mStorageInfo = info; + } + + @VisibleForTesting + public SparseArray getAppsStorageResult() { + return mAppsResult; + } + + @VisibleForTesting + public void setAppsStorageResult(SparseArray info) { + mAppsResult = info; + } + + @VisibleForTesting + void initializeCachedValues() { + final PrivateStorageInfo info = mCachedStorageValuesHelper.getCachedPrivateStorageInfo(); + final SparseArray loaderResult = + mCachedStorageValuesHelper.getCachedAppsStorageResult(); + if (info == null || loaderResult == null) { + return; + } + + mStorageInfo = info; + mAppsResult = loaderResult; + } + + /** + * Activate loading UI and animation if it's necessary. + */ + @VisibleForTesting + public void maybeSetLoading(boolean isQuotaSupported) { + // If we have fast stats, we load until both have loaded. + // If we have slow stats, we load when we get the total volume sizes. + if ((isQuotaSupported && (mStorageInfo == null || mAppsResult == null)) + || (!isQuotaSupported && mStorageInfo == null)) { + setLoading(true /* loading */, false /* animate */); + } + } + + 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()); + } + + /** + * IconLoaderCallbacks exists because StorageCategoryFragment already implements + * LoaderCallbacks for a different type. + */ + public final class IconLoaderCallbacks + implements LoaderManager.LoaderCallbacks> { + @Override + public Loader> onCreateLoader(int id, Bundle args) { + return new UserIconLoader( + getContext(), + () -> UserIconLoader.loadUserIconsWithContext(getContext())); + } + + @Override + public void onLoadFinished( + Loader> loader, SparseArray data) { + mSecondaryUsers + .stream() + .filter(controller -> controller instanceof UserIconLoader.UserIconHandler) + .forEach( + controller -> + ((UserIconLoader.UserIconHandler) controller) + .handleUserIcons(data)); + } + + @Override + public void onLoaderReset(Loader> loader) { + } + } + + /** + * VolumeSizeCallbacks exists because StorageCategoryFragment already implements + * LoaderCallbacks for a different type. + */ + public final class VolumeSizeCallbacks + implements LoaderManager.LoaderCallbacks { + @Override + public Loader onCreateLoader(int id, Bundle args) { + final Context context = getContext(); + final StorageManagerVolumeProvider smvp = + new StorageManagerVolumeProvider(mStorageManager); + final StorageStatsManager stats = context.getSystemService(StorageStatsManager.class); + return new VolumeSizesLoader(context, smvp, stats, + mSelectedStorageEntry.getVolumeInfo()); + } + + @Override + public void onLoaderReset(Loader loader) { + } + + @Override + public void onLoadFinished( + Loader loader, PrivateStorageInfo privateStorageInfo) { + if (privateStorageInfo == null) { + getActivity().finish(); + return; + } + + mStorageInfo = privateStorageInfo; + maybeCacheFreshValues(); + onReceivedSizes(); + } + } +} diff --git a/src/com/android/settings/deviceinfo/StorageDashboardFragment.java b/src/com/android/settings/deviceinfo/StorageDashboardFragment.java index 6a3bb515e81..cc7eff6a27b 100644 --- a/src/com/android/settings/deviceinfo/StorageDashboardFragment.java +++ b/src/com/android/settings/deviceinfo/StorageDashboardFragment.java @@ -43,7 +43,6 @@ import androidx.preference.Preference; 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.AutomaticStorageManagementSwitchPreferenceController; import com.android.settings.deviceinfo.storage.CachedStorageValuesHelper; import com.android.settings.deviceinfo.storage.DiskInitFragment; @@ -69,8 +68,20 @@ import com.android.settingslib.search.SearchIndexable; import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import java.util.stream.Collectors; +/** + * Storage Settings main UI is composed by 3 fragments: + * + * StorageDashboardFragment only shows when there is only personal profile for current user. + * + * ProfileSelectStorageFragment (controls preferences above profile tab) and + * StorageCategoryFragment (controls preferences below profile tab) only show when current + * user has installed work profile. + * + * ProfileSelectStorageFragment and StorageCategoryFragment have many similar or the same + * code as StorageDashboardFragment. Remember to sync code between these fragments when you have to + * change Storage Settings. + */ @SearchIndexable public class StorageDashboardFragment extends DashboardFragment implements @@ -104,7 +115,7 @@ public class StorageDashboardFragment extends DashboardFragment private final StorageEventListener mStorageEventListener = new StorageEventListener() { @Override public void onVolumeStateChanged(VolumeInfo volumeInfo, int oldState, int newState) { - if (!isInteresting(volumeInfo)) { + if (!StorageUtils.isStorageSettingsInterestedVolume(volumeInfo)) { return; } @@ -146,7 +157,7 @@ public class StorageDashboardFragment extends DashboardFragment @Override public void onVolumeRecordChanged(VolumeRecord volumeRecord) { - if (isVolumeRecordMissed(volumeRecord)) { + if (StorageUtils.isVolumeRecordMissed(mStorageManager, volumeRecord)) { // VolumeRecord is a metadata of VolumeInfo, if a VolumeInfo is missing // (e.g., internal SD card is removed.) show the missing storage to users, // users can insert the SD card or manually forget the storage from the device. @@ -159,7 +170,7 @@ public class StorageDashboardFragment extends DashboardFragment // Find mapped VolumeInfo and replace with existing one for something changed. // (e.g., Renamed.) final VolumeInfo mappedVolumeInfo = - mStorageManager.findVolumeByUuid(volumeRecord.getFsUuid()); + mStorageManager.findVolumeByUuid(volumeRecord.getFsUuid()); if (mappedVolumeInfo == null) { return; } @@ -190,7 +201,7 @@ public class StorageDashboardFragment extends DashboardFragment @Override public void onDiskScanned(DiskInfo disk, int volumeCount) { - if (!isDiskUnsupported(disk)) { + if (!StorageUtils.isDiskUnsupported(disk)) { return; } final StorageEntry storageEntry = new StorageEntry(disk); @@ -213,33 +224,6 @@ public class StorageDashboardFragment extends DashboardFragment } }; - private static boolean isInteresting(VolumeInfo volumeInfo) { - switch (volumeInfo.getType()) { - case VolumeInfo.TYPE_PRIVATE: - case VolumeInfo.TYPE_PUBLIC: - case VolumeInfo.TYPE_STUB: - return true; - default: - return false; - } - } - - /** - * VolumeRecord is a metadata of VolumeInfo, this is the case where a VolumeInfo is missing. - * (e.g., internal SD card is removed.) - */ - private boolean isVolumeRecordMissed(VolumeRecord volumeRecord) { - return volumeRecord.getType() == VolumeInfo.TYPE_PRIVATE - && mStorageManager.findVolumeByUuid(volumeRecord.getFsUuid()) == null; - } - - /** - * A unsupported disk is the disk of problem format, android is not able to mount automatically. - */ - private static boolean isDiskUnsupported(DiskInfo disk) { - return disk.volumeCount == 0 && disk.size > 0; - } - private void refreshUi() { mStorageSelectionController.setStorageEntries(mStorageEntries); mStorageSelectionController.setSelectedStorageEntry(mSelectedStorageEntry); @@ -297,9 +281,8 @@ public class StorageDashboardFragment extends DashboardFragment // These member variables are initialized befoer super.onAttach for // createPreferenceControllers to work correctly. mUserManager = context.getSystemService(UserManager.class); - mIsWorkProfile = getArguments().getInt(ProfileSelectFragment.EXTRA_PROFILE) - == ProfileSelectFragment.ProfileType.WORK; - mUserId = Utils.getCurrentUserId(mUserManager, mIsWorkProfile); + mIsWorkProfile = false; + mUserId = UserHandle.myUserId(); super.onAttach(context); use(AutomaticStorageManagementSwitchPreferenceController.class).setFragmentManager( @@ -334,8 +317,7 @@ public class StorageDashboardFragment extends DashboardFragment initializeCacheProvider(); maybeSetLoading(isQuotaSupported()); - final Activity activity = getActivity(); - EntityHeaderController.newInstance(activity, this /*fragment*/, + EntityHeaderController.newInstance(getActivity(), this /*fragment*/, null /* header view */) .setRecyclerView(getListView(), getSettingsLifecycle()); } @@ -345,18 +327,7 @@ public class StorageDashboardFragment extends DashboardFragment super.onResume(); mStorageEntries.clear(); - mStorageEntries.addAll(mStorageManager.getVolumes().stream() - .filter(volumeInfo -> isInteresting(volumeInfo)) - .map(volumeInfo -> new StorageEntry(getContext(), volumeInfo)) - .collect(Collectors.toList())); - mStorageEntries.addAll(mStorageManager.getDisks().stream() - .filter(disk -> isDiskUnsupported(disk)) - .map(disk -> new StorageEntry(disk)) - .collect(Collectors.toList())); - mStorageEntries.addAll(mStorageManager.getVolumeRecords().stream() - .filter(volumeRecord -> isVolumeRecordMissed(volumeRecord)) - .map(volumeRecord -> new StorageEntry(volumeRecord)) - .collect(Collectors.toList())); + mStorageEntries.addAll(StorageUtils.getAllStorageEntries(getContext(), mStorageManager)); refreshUi(); mStorageManager.registerListener(mStorageEventListener); } @@ -381,19 +352,18 @@ public class StorageDashboardFragment extends DashboardFragment private void onReceivedSizes() { boolean stopLoading = false; if (mStorageInfo != null) { - long privateUsedBytes = mStorageInfo.totalBytes - mStorageInfo.freeBytes; + final long privateUsedBytes = mStorageInfo.totalBytes - mStorageInfo.freeBytes; mPreferenceController.setVolume(mSelectedStorageEntry.getVolumeInfo()); mPreferenceController.setUsedSize(privateUsedBytes); mPreferenceController.setTotalSize(mStorageInfo.totalBytes); for (int i = 0, size = mSecondaryUsers.size(); i < size; i++) { - AbstractPreferenceController controller = mSecondaryUsers.get(i); + final AbstractPreferenceController controller = mSecondaryUsers.get(i); if (controller instanceof SecondaryUserController) { SecondaryUserController userController = (SecondaryUserController) controller; userController.setTotalSize(mStorageInfo.totalBytes); } } stopLoading = true; - } if (mAppsResult != null) { @@ -428,7 +398,7 @@ public class StorageDashboardFragment extends DashboardFragment @Override protected List createPreferenceControllers(Context context) { final List controllers = new ArrayList<>(); - StorageManager sm = context.getSystemService(StorageManager.class); + final StorageManager sm = context.getSystemService(StorageManager.class); mPreferenceController = new StorageItemPreferenceController(context, this, null /* volume */, new StorageManagerVolumeProvider(sm), mIsWorkProfile); controllers.add(mPreferenceController); @@ -440,18 +410,13 @@ public class StorageDashboardFragment extends DashboardFragment return controllers; } - @VisibleForTesting - protected void setVolume(VolumeInfo info) { - mSelectedStorageEntry = new StorageEntry(getContext(), info); - } - /** * Updates the secondary user controller sizes. */ private void updateSecondaryUserControllers(List controllers, SparseArray stats) { for (int i = 0, size = controllers.size(); i < size; i++) { - AbstractPreferenceController controller = controllers.get(i); + final AbstractPreferenceController controller = controllers.get(i); if (controller instanceof StorageAsyncLoader.ResultHandler) { StorageAsyncLoader.ResultHandler userController = (StorageAsyncLoader.ResultHandler) controller; @@ -552,9 +517,9 @@ public class StorageDashboardFragment extends DashboardFragment } @VisibleForTesting - public void initializeCachedValues() { - PrivateStorageInfo info = mCachedStorageValuesHelper.getCachedPrivateStorageInfo(); - SparseArray loaderResult = + void initializeCachedValues() { + final PrivateStorageInfo info = mCachedStorageValuesHelper.getCachedPrivateStorageInfo(); + final SparseArray loaderResult = mCachedStorageValuesHelper.getCachedAppsStorageResult(); if (info == null || loaderResult == null) { return; @@ -564,12 +529,15 @@ public class StorageDashboardFragment extends DashboardFragment mAppsResult = loaderResult; } + /** + * Activate loading UI and animation if it's necessary. + */ @VisibleForTesting public void maybeSetLoading(boolean isQuotaSupported) { // If we have fast stats, we load until both have loaded. // If we have slow stats, we load when we get the total volume sizes. - if ((isQuotaSupported && (mStorageInfo == null || mAppsResult == null)) || - (!isQuotaSupported && mStorageInfo == null)) { + if ((isQuotaSupported && (mStorageInfo == null || mAppsResult == null)) + || (!isQuotaSupported && mStorageInfo == null)) { setLoading(true /* loading */, false /* animate */); } } @@ -622,6 +590,10 @@ public class StorageDashboardFragment extends DashboardFragment } } + /** + * VolumeSizeCallbacks exists because StorageCategoryFragment already implements + * LoaderCallbacks for a different type. + */ public final class VolumeSizeCallbacks implements LoaderManager.LoaderCallbacks { @Override diff --git a/src/com/android/settings/deviceinfo/storage/StorageUtils.java b/src/com/android/settings/deviceinfo/storage/StorageUtils.java index 919908dbda1..549eef61f7f 100644 --- a/src/com/android/settings/deviceinfo/storage/StorageUtils.java +++ b/src/com/android/settings/deviceinfo/storage/StorageUtils.java @@ -22,6 +22,7 @@ import android.content.Context; import android.os.AsyncTask; import android.os.Build; import android.os.Bundle; +import android.os.storage.DiskInfo; import android.os.storage.StorageManager; import android.os.storage.VolumeInfo; import android.os.storage.VolumeRecord; @@ -36,11 +37,67 @@ import com.android.settings.core.SubSettingLauncher; import com.android.settings.core.instrumentation.InstrumentedDialogFragment; import com.android.settings.deviceinfo.PrivateVolumeForget; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + /** Storage utilities */ public class StorageUtils { private static final String TAG = "StorageUtils"; + /** + * Collects and returns all kinds of StorageEntry which will show in Storage Settings. + */ + public static List getAllStorageEntries(Context context, + StorageManager storageManager) { + final List storageEntries = new ArrayList<>(); + storageEntries.addAll(storageManager.getVolumes().stream() + .filter(volumeInfo -> isStorageSettingsInterestedVolume(volumeInfo)) + .map(volumeInfo -> new StorageEntry(context, volumeInfo)) + .collect(Collectors.toList())); + storageEntries.addAll(storageManager.getDisks().stream() + .filter(disk -> isDiskUnsupported(disk)) + .map(disk -> new StorageEntry(disk)) + .collect(Collectors.toList())); + storageEntries.addAll(storageManager.getVolumeRecords().stream() + .filter(volumeRecord -> isVolumeRecordMissed(storageManager, volumeRecord)) + .map(volumeRecord -> new StorageEntry(volumeRecord)) + .collect(Collectors.toList())); + return storageEntries; + } + + /** + * Returns true if the volumeInfo may be displayed in Storage Settings. + */ + public static boolean isStorageSettingsInterestedVolume(VolumeInfo volumeInfo) { + switch (volumeInfo.getType()) { + case VolumeInfo.TYPE_PRIVATE: + case VolumeInfo.TYPE_PUBLIC: + case VolumeInfo.TYPE_STUB: + return true; + default: + return false; + } + } + + /** + * VolumeRecord is a metadata of VolumeInfo, this is the case where a VolumeInfo is missing. + * (e.g., internal SD card is removed.) + */ + public static boolean isVolumeRecordMissed(StorageManager storageManager, + VolumeRecord volumeRecord) { + return volumeRecord.getType() == VolumeInfo.TYPE_PRIVATE + && storageManager.findVolumeByUuid(volumeRecord.getFsUuid()) == null; + } + + /** + * A unsupported disk is the disk of problem format, android is not able to mount automatically. + */ + public static boolean isDiskUnsupported(DiskInfo disk) { + return disk.volumeCount == 0 && disk.size > 0; + } + /** Launches the fragment to forget a specified missing volume record. */ public static void launchForgetMissingVolumeRecordFragment(Context context, StorageEntry storageEntry) { diff --git a/tests/robotests/assets/exempt_not_implementing_index_provider b/tests/robotests/assets/exempt_not_implementing_index_provider index 7815a486dac..d4a1c2e268d 100644 --- a/tests/robotests/assets/exempt_not_implementing_index_provider +++ b/tests/robotests/assets/exempt_not_implementing_index_provider @@ -37,6 +37,7 @@ com.android.settings.datausage.DataUsageSummary com.android.settings.datetime.timezone.TimeZoneSettings com.android.settings.development.compat.PlatformCompatDashboard com.android.settings.deviceinfo.PublicVolumeSettings +com.android.settings.deviceinfo.StorageDashboardNoHeaderFragment com.android.settings.deviceinfo.legal.ModuleLicensesDashboard com.android.settings.enterprise.ApplicationListFragment$AdminGrantedPermissionCamera com.android.settings.enterprise.ApplicationListFragment$AdminGrantedPermissionLocation diff --git a/tests/unit/src/com/android/settings/dashboard/profileselector/ProfileSelectStorageFragmentTest.java b/tests/unit/src/com/android/settings/dashboard/profileselector/ProfileSelectStorageFragmentTest.java new file mode 100644 index 00000000000..6eb9aa526fd --- /dev/null +++ b/tests/unit/src/com/android/settings/dashboard/profileselector/ProfileSelectStorageFragmentTest.java @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2021 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.dashboard.profileselector; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +import android.app.Activity; +import android.os.Looper; + +import androidx.test.annotation.UiThreadTest; +import androidx.test.ext.junit.runners.AndroidJUnit4; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.MockitoAnnotations; + +@RunWith(AndroidJUnit4.class) +public class ProfileSelectStorageFragmentTest { + + private ProfileSelectStorageFragment mFragment; + + @Before + @UiThreadTest + public void setUp() { + MockitoAnnotations.initMocks(this); + + if (Looper.myLooper() == null) { + Looper.prepare(); + } + + mFragment = new ProfileSelectStorageFragment(); + } + + @Test + @UiThreadTest + public void test_initializeOptionsMenuInvalidatesExistingMenu() { + final Activity activity = mock(Activity.class); + + mFragment.initializeOptionsMenu(activity); + + verify(activity).invalidateOptionsMenu(); + } +} From 6062b6491d39a4fa297f524bd2616bd31c833d27 Mon Sep 17 00:00:00 2001 From: Arc Wang Date: Thu, 13 May 2021 10:51:28 +0800 Subject: [PATCH 5/6] Rename audios to audio Bug: 186635176 Test: build pass Change-Id: I0d909f639fe36edf2e5088c7ec219cceee4e963a --- res/values/config.xml | 4 +-- res/values/strings.xml | 4 +-- res/xml/storage_category_fragment.xml | 4 +-- res/xml/storage_dashboard_fragment.xml | 4 +-- .../StorageItemPreferenceController.java | 28 +++++++++---------- .../StorageItemPreferenceControllerTest.java | 22 +++++++-------- 6 files changed, 33 insertions(+), 33 deletions(-) diff --git a/res/values/config.xml b/res/values/config.xml index 21d9c7528d1..1e2855b459f 100755 --- a/res/values/config.xml +++ b/res/values/config.xml @@ -511,8 +511,8 @@ content://com.android.providers.media.documents/root/videos_root - - content://com.android.providers.media.documents/root/audio_root + + content://com.android.providers.media.documents/root/audio_root content://com.android.providers.media.documents/root/documents_root diff --git a/res/values/strings.xml b/res/values/strings.xml index a34f909260c..4f377eeaa3e 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -11883,8 +11883,8 @@ Videos - - Audios + + Audio Apps diff --git a/res/xml/storage_category_fragment.xml b/res/xml/storage_category_fragment.xml index 8ac9e940f86..72623d7b269 100644 --- a/res/xml/storage_category_fragment.xml +++ b/res/xml/storage_category_fragment.xml @@ -43,8 +43,8 @@ android:icon="@drawable/ic_local_movies" android:order="102"/> Date: Mon, 17 May 2021 14:11:09 +0800 Subject: [PATCH 6/6] Fix legacy failed unit test for BatteryInfoLoader fix the legacy failed test since the scale is different, setting the testing value in ms scale (getBatteryTimeRemainingMs()), but getting the data in us scale (info.remainingTimeUs) Bug: 188244142 Test: make SettingsRoboTests Change-Id: Ib389976985eb3741cc96e0ee4a3a000c7f690b37 --- src/com/android/settings/fuelgauge/BatteryDiffEntry.java | 5 +++++ src/com/android/settings/fuelgauge/ConvertUtils.java | 2 +- .../android/settings/fuelgauge/BatteryInfoLoaderTest.java | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/com/android/settings/fuelgauge/BatteryDiffEntry.java b/src/com/android/settings/fuelgauge/BatteryDiffEntry.java index 7b73638557e..81ad5bec87c 100644 --- a/src/com/android/settings/fuelgauge/BatteryDiffEntry.java +++ b/src/com/android/settings/fuelgauge/BatteryDiffEntry.java @@ -73,6 +73,11 @@ public class BatteryDiffEntry { mBackgroundUsageTimeInMs = backgroundUsageTimeInMs; mBatteryHistEntry = batteryHistEntry; mUserManager = context.getSystemService(UserManager.class); + if (foregroundUsageTimeInMs == 0 + && backgroundUsageTimeInMs == 0 + && consumePower != 0) { + Log.w(TAG, "abnornal BatteryDiffEntry:\n" + this); + } } /** Sets the total consumed power in a specific time slot. */ diff --git a/src/com/android/settings/fuelgauge/ConvertUtils.java b/src/com/android/settings/fuelgauge/ConvertUtils.java index 37f9e1212b4..e05247c3c40 100644 --- a/src/com/android/settings/fuelgauge/ConvertUtils.java +++ b/src/com/android/settings/fuelgauge/ConvertUtils.java @@ -230,7 +230,7 @@ public final class ConvertUtils { if (selectedBatteryEntry == null) { continue; } - // Force refine the cumulative value since it may introduce deviation + // Forces refine the cumulative value since it may introduce deviation // error since we will apply the interpolation arithmetic. final float totalUsageTimeInMs = foregroundUsageTimeInMs + backgroundUsageTimeInMs; diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryInfoLoaderTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryInfoLoaderTest.java index 5bcaf0a5cce..0dfabb99313 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryInfoLoaderTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryInfoLoaderTest.java @@ -78,6 +78,6 @@ public class BatteryInfoLoaderTest { BatteryInfo info = loader.loadInBackground(); assertThat(info.remainingLabel).isNotNull(); - assertThat(info.remainingTimeUs).isEqualTo(TEST_TIME_REMAINING); + assertThat(info.remainingTimeUs).isEqualTo(TEST_TIME_REMAINING * 1000); } }