From 5dff40c78f2bc99fb2cdac78e7fcca2d93ce39d2 Mon Sep 17 00:00:00 2001 From: Peter Wang Date: Mon, 10 May 2021 17:57:33 -0700 Subject: [PATCH 01/23] Change DSDS dialog confirm text from "Continue" to "Yes" [Part II] Bug: 131169645 Fix: 184769109 Test: Build Change-Id: Ifbde65db0abc43d739fdd67822c19c3063df0d32 --- .../network/telephony/ToggleSubscriptionDialogActivity.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/com/android/settings/network/telephony/ToggleSubscriptionDialogActivity.java b/src/com/android/settings/network/telephony/ToggleSubscriptionDialogActivity.java index d3b2af6ef88..0064e6ccfd2 100644 --- a/src/com/android/settings/network/telephony/ToggleSubscriptionDialogActivity.java +++ b/src/com/android/settings/network/telephony/ToggleSubscriptionDialogActivity.java @@ -326,7 +326,7 @@ public class ToggleSubscriptionDialogActivity extends SubscriptionActionDialogAc DIALOG_TAG_ENABLE_DSDS_CONFIRMATION, getString(R.string.sim_action_enable_dsds_title), getString(R.string.sim_action_enable_dsds_text), - getString(R.string.sim_action_continue), + getString(R.string.sim_action_yes), getString(R.string.sim_action_no_thanks)); } From 1b413601b9c026dc2584b04a0974873d1c730cdb Mon Sep 17 00:00:00 2001 From: Edgar Wang Date: Mon, 24 May 2021 17:25:45 +0800 Subject: [PATCH 02/23] Tweak right padding for multiple preferences - Moved two_target_min_width to SettingsLib - Set widget_frame minWidth to 72dp Bug: 185549116 Test: manual & robotest Change-Id: I613fe8e494443ef7cfc99088acfcd4894892d2e6 --- res/layout/accessibility_shortcut_secondary_action.xml | 5 +++-- res/layout/preference_single_target.xml | 2 +- res/layout/preference_two_target_radio.xml | 2 +- res/layout/preference_widget_gear.xml | 4 ++-- res/layout/preference_widget_primary_switch.xml | 2 -- res/layout/wifi_button_preference_widget.xml | 2 +- res/values/dimens.xml | 2 -- 7 files changed, 8 insertions(+), 11 deletions(-) diff --git a/res/layout/accessibility_shortcut_secondary_action.xml b/res/layout/accessibility_shortcut_secondary_action.xml index a114f0563e0..8d0ef3bdfe3 100644 --- a/res/layout/accessibility_shortcut_secondary_action.xml +++ b/res/layout/accessibility_shortcut_secondary_action.xml @@ -21,6 +21,8 @@ android:layout_height="wrap_content" android:minHeight="?android:attr/listPreferredItemHeightSmall" android:gravity="center_vertical" + android:paddingStart="?android:attr/listPreferredItemPaddingStart" + android:paddingEnd="?android:attr/listPreferredItemPaddingEnd" android:clipToPadding="false"> + > diff --git a/res/layout/preference_two_target_radio.xml b/res/layout/preference_two_target_radio.xml index c7d0f5e26cb..dc97f1d8785 100644 --- a/res/layout/preference_two_target_radio.xml +++ b/res/layout/preference_two_target_radio.xml @@ -85,7 +85,7 @@ android:layout_width="wrap_content" android:layout_height="match_parent" android:gravity="center" - android:minWidth="64dp" + android:minWidth="@dimen/two_target_min_width" android:orientation="vertical" /> diff --git a/res/layout/preference_widget_gear.xml b/res/layout/preference_widget_gear.xml index 11870acace9..c4fc27dbab6 100644 --- a/res/layout/preference_widget_gear.xml +++ b/res/layout/preference_widget_gear.xml @@ -21,8 +21,8 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:layout_gravity="center" - android:paddingStart="?android:attr/listPreferredItemPaddingEnd" - android:paddingEnd="?android:attr/listPreferredItemPaddingEnd" + android:paddingStart="24dp" + android:paddingEnd="24dp" android:background="?android:attr/selectableItemBackground" android:scaleType="center" android:src="@drawable/ic_settings_accent" diff --git a/res/layout/preference_widget_primary_switch.xml b/res/layout/preference_widget_primary_switch.xml index 26929ab468f..53c06b5ff7f 100644 --- a/res/layout/preference_widget_primary_switch.xml +++ b/res/layout/preference_widget_primary_switch.xml @@ -22,6 +22,4 @@ android:layout_height="match_parent" android:minWidth="@dimen/two_target_min_width" android:gravity="center_vertical" - android:paddingStart="?android:attr/listPreferredItemPaddingEnd" - android:paddingEnd="?android:attr/listPreferredItemPaddingEnd" android:clickable="false" /> diff --git a/res/layout/wifi_button_preference_widget.xml b/res/layout/wifi_button_preference_widget.xml index f4f161818ac..92e006b1ae3 100644 --- a/res/layout/wifi_button_preference_widget.xml +++ b/res/layout/wifi_button_preference_widget.xml @@ -19,7 +19,7 @@ android:id="@+id/button_icon" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:minWidth="64dp" + android:minWidth="@dimen/two_target_min_width" android:minHeight="@dimen/min_tap_target_size" android:layout_gravity="center" android:background="?android:attr/selectableItemBackground"/> diff --git a/res/values/dimens.xml b/res/values/dimens.xml index a9cda9e75ac..3deb6bc9a95 100755 --- a/res/values/dimens.xml +++ b/res/values/dimens.xml @@ -393,8 +393,6 @@ 4dp - 80dp - 1800dp From ba8e5802d45201bc1de191d3078a808e4f84b334 Mon Sep 17 00:00:00 2001 From: Yanting Yang Date: Tue, 25 May 2021 02:35:58 +0800 Subject: [PATCH 03/23] Remove silky flag from Apps for official release Remove the silky condition and clean up redundant files. Bug: 183670633 Test: robotests & visual with turning on/off silky home Change-Id: If6df8a4191d5750edca22dd94b99c43ccebf2e04 --- AndroidManifest.xml | 9 - res/xml/app_and_notification.xml | 114 ------------ .../AllAppsInfoPreferenceController.java | 73 -------- .../AppAndNotificationDashboardFragment.java | 151 --------------- .../applications/AppDashboardFragment.java | 20 -- .../RecentAppsPreferenceController.java | 176 ------------------ .../core/gateway/SettingsGateway.java | 2 - .../dashboard/DashboardFragmentRegistry.java | 4 +- .../AllAppsInfoPreferenceControllerTest.java | 89 --------- .../RecentAppsPreferenceControllerTest.java | 167 ----------------- 10 files changed, 2 insertions(+), 803 deletions(-) delete mode 100644 res/xml/app_and_notification.xml delete mode 100644 src/com/android/settings/applications/AllAppsInfoPreferenceController.java delete mode 100644 src/com/android/settings/applications/AppAndNotificationDashboardFragment.java delete mode 100644 src/com/android/settings/applications/RecentAppsPreferenceController.java delete mode 100644 tests/robotests/src/com/android/settings/applications/AllAppsInfoPreferenceControllerTest.java delete mode 100644 tests/robotests/src/com/android/settings/applications/RecentAppsPreferenceControllerTest.java diff --git a/AndroidManifest.xml b/AndroidManifest.xml index a21c4bb88ab..12900b8be2f 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -3317,15 +3317,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/com/android/settings/applications/AllAppsInfoPreferenceController.java b/src/com/android/settings/applications/AllAppsInfoPreferenceController.java deleted file mode 100644 index 325b25a3618..00000000000 --- a/src/com/android/settings/applications/AllAppsInfoPreferenceController.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (C) 2019 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.applications; - -import android.app.usage.UsageStats; -import android.content.Context; - -import androidx.annotation.NonNull; -import androidx.annotation.VisibleForTesting; -import androidx.preference.Preference; -import androidx.preference.PreferenceScreen; - -import com.android.settings.R; -import com.android.settings.core.BasePreferenceController; - -import java.util.List; - -public class AllAppsInfoPreferenceController extends BasePreferenceController - implements RecentAppStatsMixin.RecentAppStatsListener { - - @VisibleForTesting - Preference mPreference; - - public AllAppsInfoPreferenceController(Context context, String key) { - super(context, key); - } - - @Override - public int getAvailabilityStatus() { - return AVAILABLE; - } - - @Override - public void displayPreference(PreferenceScreen screen) { - super.displayPreference(screen); - mPreference = screen.findPreference(getPreferenceKey()); - // In most cases, device has recently opened apps. So, we hide it by default. - mPreference.setVisible(false); - } - - @Override - public void onReloadDataCompleted(@NonNull List recentApps) { - // If device has recently opened apps, we don't show all apps preference. - if (!recentApps.isEmpty()) { - mPreference.setVisible(false); - return; - } - - mPreference.setVisible(true); - // Show total number of installed apps as See all's summary. - new InstalledAppCounter(mContext, InstalledAppCounter.IGNORE_INSTALL_REASON, - mContext.getPackageManager()) { - @Override - protected void onCountComplete(int num) { - mPreference.setSummary(mContext.getString(R.string.apps_summary, num)); - } - }.execute(); - } -} diff --git a/src/com/android/settings/applications/AppAndNotificationDashboardFragment.java b/src/com/android/settings/applications/AppAndNotificationDashboardFragment.java deleted file mode 100644 index ddb39516598..00000000000 --- a/src/com/android/settings/applications/AppAndNotificationDashboardFragment.java +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright (C) 2016 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.applications; - -import android.app.settings.SettingsEnums; -import android.app.usage.UsageStats; -import android.content.Context; -import android.os.Bundle; -import android.provider.SearchIndexableResource; -import android.util.FeatureFlagUtils; -import android.view.View; - -import androidx.annotation.NonNull; - -import com.android.settings.R; -import com.android.settings.Utils; -import com.android.settings.core.FeatureFlags; -import com.android.settings.dashboard.DashboardFragment; -import com.android.settings.notification.EmergencyBroadcastPreferenceController; -import com.android.settings.search.BaseSearchIndexProvider; -import com.android.settingslib.core.AbstractPreferenceController; -import com.android.settingslib.search.SearchIndexable; -import com.android.settingslib.widget.AppEntitiesHeaderController; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -@SearchIndexable -public class AppAndNotificationDashboardFragment extends DashboardFragment - implements RecentAppStatsMixin.RecentAppStatsListener { - - private static final String TAG = "AppAndNotifDashboard"; - - private RecentAppStatsMixin mRecentAppStatsMixin; - private RecentAppsPreferenceController mRecentAppsPreferenceController; - private AllAppsInfoPreferenceController mAllAppsInfoPreferenceController; - - @Override - public int getMetricsCategory() { - return SettingsEnums.SETTINGS_APP_NOTIF_CATEGORY; - } - - @Override - protected String getLogTag() { - return TAG; - } - - @Override - public int getHelpResource() { - return R.string.help_url_apps_and_notifications; - } - - @Override - protected int getPreferenceScreenResId() { - return R.xml.app_and_notification; - } - - @Override - public void onAttach(Context context) { - super.onAttach(context); - - use(SpecialAppAccessPreferenceController.class).setSession(getSettingsLifecycle()); - - mRecentAppStatsMixin = new RecentAppStatsMixin(context, - AppEntitiesHeaderController.MAXIMUM_APPS); - getSettingsLifecycle().addObserver(mRecentAppStatsMixin); - mRecentAppStatsMixin.addListener(this); - - mRecentAppsPreferenceController = use(RecentAppsPreferenceController.class); - mRecentAppsPreferenceController.setFragment(this /* fragment */); - mRecentAppStatsMixin.addListener(mRecentAppsPreferenceController); - - mAllAppsInfoPreferenceController = use(AllAppsInfoPreferenceController.class); - mRecentAppStatsMixin.addListener(mAllAppsInfoPreferenceController); - } - - @Override - public void onViewCreated(View view, Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - setPinnedHeaderView(R.layout.progress_header); - showPinnedHeader(false); - } - - @Override - public void onStart() { - super.onStart(); - showPinnedHeader(true); - } - - @Override - public void onReloadDataCompleted(@NonNull List recentApps) { - showPinnedHeader(false); - if (!recentApps.isEmpty()) { - Utils.setActionBarShadowAnimation(getActivity(), getSettingsLifecycle(), - getListView()); - } - } - - @Override - protected List createPreferenceControllers(Context context) { - return buildPreferenceControllers(context); - } - - private static List buildPreferenceControllers(Context context) { - final List controllers = new ArrayList<>(); - controllers.add(new EmergencyBroadcastPreferenceController(context, - "app_and_notif_cell_broadcast_settings")); - return controllers; - } - - public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = - new BaseSearchIndexProvider() { - @Override - public List getXmlResourcesToIndex( - Context context, boolean enabled) { - final SearchIndexableResource sir = new SearchIndexableResource(context); - sir.xmlResId = R.xml.app_and_notification; - return Arrays.asList(sir); - } - - @Override - public List createPreferenceControllers( - Context context) { - return buildPreferenceControllers(context); - } - - @Override - protected boolean isPageSearchEnabled(Context context) { - // TODO(b/174964405): This method should be removed when silky home launched. - // This page is going to deprecate, we should make this page unsearchable - // when the silky home is enabled, otherwise search results will contain the - // old data and launch this page even if the silky home is enabled. - return !FeatureFlagUtils.isEnabled(context, FeatureFlags.SILKY_HOME); - } - }; -} diff --git a/src/com/android/settings/applications/AppDashboardFragment.java b/src/com/android/settings/applications/AppDashboardFragment.java index 3b1a9777d57..65f2b61cdd0 100644 --- a/src/com/android/settings/applications/AppDashboardFragment.java +++ b/src/com/android/settings/applications/AppDashboardFragment.java @@ -19,14 +19,11 @@ package com.android.settings.applications; import android.app.settings.SettingsEnums; import android.content.Context; import android.provider.SearchIndexableResource; -import android.util.FeatureFlagUtils; import com.android.settings.R; -import com.android.settings.core.FeatureFlags; import com.android.settings.dashboard.DashboardFragment; import com.android.settings.search.BaseSearchIndexProvider; import com.android.settingslib.core.AbstractPreferenceController; -import com.android.settingslib.drawer.CategoryKey; import com.android.settingslib.search.SearchIndexable; import java.util.ArrayList; @@ -79,16 +76,6 @@ public class AppDashboardFragment extends DashboardFragment { return buildPreferenceControllers(context); } - @Override - public String getCategoryKey() { - // TODO(b/174964405): Remove this function when the silky flag was deprecated. - // To include injection tiles, map this app fragment to the app category in the short term. - // When we deprecate the silky flag, we have to: - // 1. Remove this method. - // 2. Update the mapping in DashboardFragmentRegistry.PARENT_TO_CATEGORY_KEY_MAP. - return CategoryKey.CATEGORY_APPS; - } - public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = new BaseSearchIndexProvider() { @Override @@ -104,12 +91,5 @@ public class AppDashboardFragment extends DashboardFragment { Context context) { return buildPreferenceControllers(context); } - - @Override - protected boolean isPageSearchEnabled(Context context) { - // TODO(b/174964405): This method should be removed when silky home launched. - // Only allow this page can be searchable when silky home enabled. - return FeatureFlagUtils.isEnabled(context, FeatureFlags.SILKY_HOME); - } }; } diff --git a/src/com/android/settings/applications/RecentAppsPreferenceController.java b/src/com/android/settings/applications/RecentAppsPreferenceController.java deleted file mode 100644 index 20f9806d35f..00000000000 --- a/src/com/android/settings/applications/RecentAppsPreferenceController.java +++ /dev/null @@ -1,176 +0,0 @@ -/* - * 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.applications; - -import android.app.Application; -import android.app.usage.UsageStats; -import android.content.Context; -import android.icu.text.RelativeDateTimeFormatter; -import android.os.UserHandle; -import android.view.View; - -import androidx.annotation.NonNull; -import androidx.annotation.VisibleForTesting; -import androidx.fragment.app.Fragment; -import androidx.preference.Preference; -import androidx.preference.PreferenceScreen; - -import com.android.settings.R; -import com.android.settings.applications.appinfo.AppInfoDashboardFragment; -import com.android.settings.applications.manageapplications.ManageApplications; -import com.android.settings.core.BasePreferenceController; -import com.android.settings.core.SubSettingLauncher; -import com.android.settings.overlay.FeatureFactory; -import com.android.settingslib.Utils; -import com.android.settingslib.applications.ApplicationsState; -import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; -import com.android.settingslib.utils.StringUtil; -import com.android.settingslib.widget.AppEntitiesHeaderController; -import com.android.settingslib.widget.AppEntityInfo; -import com.android.settingslib.widget.LayoutPreference; - -import java.util.List; - -/** - * This controller displays up to three recently used apps. - * If there is no recently used app, we only show up an "App Info" preference. - */ -public class RecentAppsPreferenceController extends BasePreferenceController - implements RecentAppStatsMixin.RecentAppStatsListener { - - @VisibleForTesting - static final String KEY_DIVIDER = "recent_apps_divider"; - - @VisibleForTesting - AppEntitiesHeaderController mAppEntitiesController; - @VisibleForTesting - LayoutPreference mRecentAppsPreference; - @VisibleForTesting - Preference mDivider; - - private final ApplicationsState mApplicationsState; - private final int mUserId; - private final MetricsFeatureProvider mMetricsFeatureProvider; - - private Fragment mHost; - private List mRecentApps; - - public RecentAppsPreferenceController(Context context, String key) { - super(context, key); - mApplicationsState = ApplicationsState.getInstance( - (Application) mContext.getApplicationContext()); - mUserId = UserHandle.myUserId(); - mMetricsFeatureProvider = FeatureFactory.getFactory(mContext).getMetricsFeatureProvider(); - } - - public void setFragment(Fragment fragment) { - mHost = fragment; - } - - @Override - public int getAvailabilityStatus() { - return AVAILABLE_UNSEARCHABLE; - } - - @Override - public void displayPreference(PreferenceScreen screen) { - super.displayPreference(screen); - - mDivider = screen.findPreference(KEY_DIVIDER); - mRecentAppsPreference = screen.findPreference(getPreferenceKey()); - final View view = mRecentAppsPreference.findViewById(R.id.app_entities_header); - mAppEntitiesController = AppEntitiesHeaderController.newInstance(mContext, view) - .setHeaderTitleRes(R.string.recent_app_category_title) - .setHeaderDetailsClickListener((View v) -> { - mMetricsFeatureProvider.logClickedPreference(mRecentAppsPreference, - getMetricsCategory()); - new SubSettingLauncher(mContext) - .setDestination(ManageApplications.class.getName()) - .setArguments(null /* arguments */) - .setTitleRes(R.string.application_info_label) - .setSourceMetricsCategory(getMetricsCategory()) - .launch(); - }); - } - - @Override - public void onReloadDataCompleted(@NonNull List recentApps) { - mRecentApps = recentApps; - refreshUi(); - // Show total number of installed apps as See all's summary. - new InstalledAppCounter(mContext, InstalledAppCounter.IGNORE_INSTALL_REASON, - mContext.getPackageManager()) { - @Override - protected void onCountComplete(int num) { - mAppEntitiesController.setHeaderDetails( - mContext.getResources().getQuantityString(R.plurals.see_all_apps_title, - num, num)); - mAppEntitiesController.apply(); - } - }.execute(); - } - - private void refreshUi() { - if (!mRecentApps.isEmpty()) { - displayRecentApps(); - mRecentAppsPreference.setVisible(true); - mDivider.setVisible(true); - } else { - mDivider.setVisible(false); - mRecentAppsPreference.setVisible(false); - } - } - - private void displayRecentApps() { - int showAppsCount = 0; - - for (UsageStats stat : mRecentApps) { - final AppEntityInfo appEntityInfoInfo = createAppEntity(stat); - if (appEntityInfoInfo != null) { - mAppEntitiesController.setAppEntity(showAppsCount++, appEntityInfoInfo); - } - - if (showAppsCount == AppEntitiesHeaderController.MAXIMUM_APPS) { - break; - } - } - } - - private AppEntityInfo createAppEntity(UsageStats stat) { - final String pkgName = stat.getPackageName(); - final ApplicationsState.AppEntry appEntry = - mApplicationsState.getEntry(pkgName, mUserId); - if (appEntry == null) { - return null; - } - - return new AppEntityInfo.Builder() - .setIcon(Utils.getBadgedIcon(mContext, appEntry.info)) - .setTitle(appEntry.label) - .setSummary(StringUtil.formatRelativeTime(mContext, - System.currentTimeMillis() - stat.getLastTimeUsed(), false, - RelativeDateTimeFormatter.Style.SHORT)) - .setOnClickListener(v -> { - mMetricsFeatureProvider.logClickedPreference(mRecentAppsPreference, - getMetricsCategory()); - AppInfoBase.startAppInfoFragment(AppInfoDashboardFragment.class, - R.string.application_info_label, pkgName, appEntry.info.uid, - mHost, 1001 /*RequestCode*/, getMetricsCategory()); - }) - .build(); - } -} diff --git a/src/com/android/settings/core/gateway/SettingsGateway.java b/src/com/android/settings/core/gateway/SettingsGateway.java index faa320c3b5d..3719a5cfbbd 100644 --- a/src/com/android/settings/core/gateway/SettingsGateway.java +++ b/src/com/android/settings/core/gateway/SettingsGateway.java @@ -35,7 +35,6 @@ import com.android.settings.accounts.AccountDashboardFragment; import com.android.settings.accounts.AccountSyncSettings; import com.android.settings.accounts.ChooseAccountFragment; import com.android.settings.accounts.ManagedProfileSettings; -import com.android.settings.applications.AppAndNotificationDashboardFragment; import com.android.settings.applications.AppDashboardFragment; import com.android.settings.applications.ProcessStatsSummary; import com.android.settings.applications.ProcessStatsUi; @@ -293,7 +292,6 @@ public class SettingsGateway { NetworkDashboardFragment.class.getName(), ConnectedDeviceDashboardFragment.class.getName(), UsbDetailsFragment.class.getName(), - AppAndNotificationDashboardFragment.class.getName(), AppDashboardFragment.class.getName(), WifiCallingDisclaimerFragment.class.getName(), AccountDashboardFragment.class.getName(), diff --git a/src/com/android/settings/dashboard/DashboardFragmentRegistry.java b/src/com/android/settings/dashboard/DashboardFragmentRegistry.java index 2e326b03e1a..89b21c9ac8e 100644 --- a/src/com/android/settings/dashboard/DashboardFragmentRegistry.java +++ b/src/com/android/settings/dashboard/DashboardFragmentRegistry.java @@ -22,7 +22,7 @@ import com.android.settings.DisplaySettings; import com.android.settings.LegalSettings; import com.android.settings.accounts.AccountDashboardFragment; import com.android.settings.accounts.AccountDetailDashboardFragment; -import com.android.settings.applications.AppAndNotificationDashboardFragment; +import com.android.settings.applications.AppDashboardFragment; import com.android.settings.connecteddevice.AdvancedConnectedDeviceDashboardFragment; import com.android.settings.connecteddevice.ConnectedDeviceDashboardFragment; import com.android.settings.development.DevelopmentSettingsDashboardFragment; @@ -76,7 +76,7 @@ public class DashboardFragmentRegistry { CategoryKey.CATEGORY_CONNECT); PARENT_TO_CATEGORY_KEY_MAP.put(AdvancedConnectedDeviceDashboardFragment.class.getName(), CategoryKey.CATEGORY_DEVICE); - PARENT_TO_CATEGORY_KEY_MAP.put(AppAndNotificationDashboardFragment.class.getName(), + PARENT_TO_CATEGORY_KEY_MAP.put(AppDashboardFragment.class.getName(), CategoryKey.CATEGORY_APPS); PARENT_TO_CATEGORY_KEY_MAP.put(PowerUsageSummary.class.getName(), CategoryKey.CATEGORY_BATTERY); diff --git a/tests/robotests/src/com/android/settings/applications/AllAppsInfoPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/applications/AllAppsInfoPreferenceControllerTest.java deleted file mode 100644 index 2944db2dff9..00000000000 --- a/tests/robotests/src/com/android/settings/applications/AllAppsInfoPreferenceControllerTest.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (C) 2019 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.applications; - -import static com.android.settings.core.BasePreferenceController.AVAILABLE; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.when; - -import android.app.usage.UsageStats; -import android.content.Context; -import android.os.UserManager; - -import androidx.preference.Preference; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; - -import java.util.ArrayList; -import java.util.List; - -@RunWith(RobolectricTestRunner.class) -public class AllAppsInfoPreferenceControllerTest { - - @Mock - private UserManager mUserManager; - private AllAppsInfoPreferenceController mController; - - @Before - public void setUp() { - MockitoAnnotations.initMocks(this); - final Context context = spy(RuntimeEnvironment.application); - final Preference preference = new Preference(context); - doReturn(mUserManager).when(context).getSystemService(Context.USER_SERVICE); - when(mUserManager.getProfileIdsWithDisabled(anyInt())).thenReturn(new int[]{}); - mController = new AllAppsInfoPreferenceController(context, "test_key"); - mController.mPreference = preference; - } - - @Test - public void getAvailabilityStatus_shouldReturnAVAILABLE() { - assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE); - } - - @Test - public void onReloadDataCompleted_recentAppsSet_hidePreference() { - final List stats = new ArrayList<>(); - final UsageStats stat1 = new UsageStats(); - stat1.mLastTimeUsed = System.currentTimeMillis(); - stat1.mPackageName = "pkg.class"; - stats.add(stat1); - - mController.onReloadDataCompleted(stats); - - assertThat(mController.mPreference.isVisible()).isFalse(); - } - - @Test - public void onReloadDataCompleted_noRecentAppSet_showPreference() { - final List stats = new ArrayList<>(); - - mController.onReloadDataCompleted(stats); - - assertThat(mController.mPreference.isVisible()).isTrue(); - } -} diff --git a/tests/robotests/src/com/android/settings/applications/RecentAppsPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/applications/RecentAppsPreferenceControllerTest.java deleted file mode 100644 index 2928d6f4398..00000000000 --- a/tests/robotests/src/com/android/settings/applications/RecentAppsPreferenceControllerTest.java +++ /dev/null @@ -1,167 +0,0 @@ -/* - * 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.applications; - -import static com.android.settings.core.BasePreferenceController.AVAILABLE_UNSEARCHABLE; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import android.app.usage.UsageStats; -import android.content.Context; -import android.content.pm.ApplicationInfo; -import android.content.pm.PackageManager; -import android.os.UserHandle; -import android.os.UserManager; -import android.view.LayoutInflater; -import android.view.View; - -import androidx.fragment.app.Fragment; -import androidx.preference.Preference; -import androidx.preference.PreferenceScreen; - -import com.android.settings.R; -import com.android.settingslib.applications.ApplicationsState; -import com.android.settingslib.widget.AppEntitiesHeaderController; -import com.android.settingslib.widget.AppEntityInfo; -import com.android.settingslib.widget.LayoutPreference; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -import org.robolectric.util.ReflectionHelpers; - -import java.util.ArrayList; -import java.util.List; - -@RunWith(RobolectricTestRunner.class) -public class RecentAppsPreferenceControllerTest { - - @Mock - private PreferenceScreen mScreen; - @Mock - private UserManager mUserManager; - @Mock - private ApplicationsState mAppState; - @Mock - private PackageManager mPackageManager; - @Mock - private ApplicationsState.AppEntry mAppEntry; - @Mock - private ApplicationInfo mApplicationInfo; - @Mock - private Fragment mFragment; - - private RecentAppsPreferenceController mController; - - @Before - public void setUp() { - MockitoAnnotations.initMocks(this); - final Context context = spy(RuntimeEnvironment.application); - when(context.getApplicationContext()).thenReturn(context); - ReflectionHelpers.setStaticField(ApplicationsState.class, "sInstance", mAppState); - doReturn(mUserManager).when(context).getSystemService(Context.USER_SERVICE); - doReturn(mPackageManager).when(context).getPackageManager(); - when(mUserManager.getProfileIdsWithDisabled(anyInt())).thenReturn(new int[]{}); - - final View appEntitiesHeaderView = LayoutInflater.from(context).inflate( - R.layout.app_entities_header, null /* root */); - final Preference dividerPreference = new Preference(context); - final LayoutPreference recentAppsPreference = - spy(new LayoutPreference(context, appEntitiesHeaderView)); - - mController = spy(new RecentAppsPreferenceController(context, "test_key")); - mController.setFragment(mFragment); - - mController.mAppEntitiesController = mock(AppEntitiesHeaderController.class); - mController.mRecentAppsPreference = recentAppsPreference; - mController.mDivider = dividerPreference; - - when(mScreen.findPreference(RecentAppsPreferenceController.KEY_DIVIDER)) - .thenReturn(dividerPreference); - when(mScreen.findPreference("test_key")).thenReturn(recentAppsPreference); - when(recentAppsPreference.findViewById(R.id.app_entities_header)).thenReturn( - appEntitiesHeaderView); - } - - @Test - public void getAvailabilityStatus_shouldReturnAVAILABLE_UNSEARCHABLE() { - assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE_UNSEARCHABLE); - } - - @Test - public void displayPreference_shouldSetupAppEntitiesHeaderController() { - mController.displayPreference(mScreen); - - assertThat(mController.mAppEntitiesController).isNotNull(); - } - - @Test - public void onReloadDataCompleted_threeValidRecentOpenAppsSet_setAppEntityThreeTime() { - final List stats = new ArrayList<>(); - final UsageStats stat1 = new UsageStats(); - final UsageStats stat2 = new UsageStats(); - final UsageStats stat3 = new UsageStats(); - stat1.mLastTimeUsed = System.currentTimeMillis(); - stat1.mPackageName = "pkg.class"; - stats.add(stat1); - - stat2.mLastTimeUsed = System.currentTimeMillis(); - stat2.mPackageName = "pkg.class2"; - stats.add(stat2); - - stat3.mLastTimeUsed = System.currentTimeMillis(); - stat3.mPackageName = "pkg.class3"; - stats.add(stat3); - when(mAppState.getEntry(stat1.mPackageName, UserHandle.myUserId())) - .thenReturn(mAppEntry); - when(mAppState.getEntry(stat2.mPackageName, UserHandle.myUserId())) - .thenReturn(mAppEntry); - when(mAppState.getEntry(stat3.mPackageName, UserHandle.myUserId())) - .thenReturn(mAppEntry); - mAppEntry.info = mApplicationInfo; - - mController.onReloadDataCompleted(stats); - - verify(mController.mAppEntitiesController, times(3)) - .setAppEntity(anyInt(), any(AppEntityInfo.class)); - assertThat(mController.mRecentAppsPreference.isVisible()).isTrue(); - assertThat(mController.mDivider.isVisible()).isTrue(); - } - - @Test - public void onReloadDataCompleted_noRecentOpenAppsSet_shouldHideRecentAppPreference() { - final List stats = new ArrayList<>(); - - mController.onReloadDataCompleted(stats); - - assertThat(mController.mRecentAppsPreference.isVisible()).isFalse(); - assertThat(mController.mDivider.isVisible()).isFalse(); - } -} From 4c29aad5f1815eb0427dec71f242a85be41f16a7 Mon Sep 17 00:00:00 2001 From: ykhung Date: Tue, 25 May 2021 12:01:06 +0800 Subject: [PATCH 04/23] Refine consumed battery value formula for power component for power component, the battery UI is designed to show system relative component without considering the attributed apps, update the current formula to use `devicePowerMah` value data only Bug: 188663505 Test: make SettingsgRoboTests Change-Id: Ibeeb360915303faed2f79c4621f17d6ba0dd725f --- src/com/android/settings/fuelgauge/BatteryEntry.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/com/android/settings/fuelgauge/BatteryEntry.java b/src/com/android/settings/fuelgauge/BatteryEntry.java index 25a66b6c34d..636d2651a8d 100644 --- a/src/com/android/settings/fuelgauge/BatteryEntry.java +++ b/src/com/android/settings/fuelgauge/BatteryEntry.java @@ -241,7 +241,7 @@ public class BatteryEntry { mBatteryConsumer = null; mIsHidden = false; mPowerComponentId = powerComponentId; - mConsumedPower = devicePowerMah - appsPowerMah; + mConsumedPower = devicePowerMah; mUsageDurationMs = usageDurationMs; mConsumerType = ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY; @@ -265,11 +265,10 @@ public class BatteryEntry { icon = context.getDrawable(iconId); name = powerComponentName; - mConsumedPower = devicePowerMah - appsPowerMah; + mConsumedPower = devicePowerMah; mConsumerType = ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY; } - public Drawable getIcon() { return icon; } From 250858e4beccf9e4a664809de1b303ae86a219b8 Mon Sep 17 00:00:00 2001 From: Yi-Ling Chuang Date: Mon, 24 May 2021 17:01:00 +0800 Subject: [PATCH 05/23] Apply setup wizard's transition on a11y pages - Start a11y activities with transition type. - Only play fade out transition on these activities with transition type. Fixes: 174540259 Test: rebuild and launch pages from Vision Settings Change-Id: I7e8e0ee8cdb7a3f99cfc9a6e2d1623e2970511b7 --- .../AccessibilitySettingsForSetupWizardActivity.java | 5 ++++- src/com/android/settings/core/SettingsBaseActivity.java | 8 ++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/com/android/settings/accessibility/AccessibilitySettingsForSetupWizardActivity.java b/src/com/android/settings/accessibility/AccessibilitySettingsForSetupWizardActivity.java index 2d58bedf2e8..48b3992b685 100644 --- a/src/com/android/settings/accessibility/AccessibilitySettingsForSetupWizardActivity.java +++ b/src/com/android/settings/accessibility/AccessibilitySettingsForSetupWizardActivity.java @@ -34,6 +34,7 @@ import com.android.settings.display.FontSizePreferenceFragmentForSetupWizard; import com.android.settings.search.actionbar.SearchMenuController; import com.android.settings.support.actionbar.HelpResourceProvider; import com.android.settingslib.core.instrumentation.Instrumentable; +import com.android.settingslib.transition.SettingsTransitionHelper; import com.google.android.setupcompat.util.WizardManagerHelper; import com.google.android.setupdesign.util.ThemeHelper; @@ -92,6 +93,7 @@ public class AccessibilitySettingsForSetupWizardActivity extends SettingsActivit : Instrumentable.METRICS_CATEGORY_UNKNOWN) .setExtras(SetupWizardUtils.copyLifecycleExtra(getIntent().getExtras(), new Bundle())) + .setTransitionType(SettingsTransitionHelper.TransitionType.TRANSITION_FADE) .launch(); return true; } @@ -119,7 +121,8 @@ public class AccessibilitySettingsForSetupWizardActivity extends SettingsActivit .setArguments(args) .setSourceMetricsCategory(Instrumentable.METRICS_CATEGORY_UNKNOWN) .setExtras(SetupWizardUtils.copyLifecycleExtra(getIntent().getExtras(), - new Bundle())); + new Bundle())) + .setTransitionType(SettingsTransitionHelper.TransitionType.TRANSITION_FADE); Log.d(LOG_TAG, "Launch font size settings"); subSettingLauncher.launch(); diff --git a/src/com/android/settings/core/SettingsBaseActivity.java b/src/com/android/settings/core/SettingsBaseActivity.java index 81e4412485d..3a8c837d3fc 100644 --- a/src/com/android/settings/core/SettingsBaseActivity.java +++ b/src/com/android/settings/core/SettingsBaseActivity.java @@ -177,6 +177,10 @@ public class SettingsBaseActivity extends FragmentActivity { } else if (transitionType == TransitionType.TRANSITION_NONE) { super.startActivity(intent, null); return; + } else if (transitionType == TransitionType.TRANSITION_FADE) { + super.startActivity(intent, null); + overridePendingTransition(android.R.anim.fade_in, R.anim.sud_stay); + return; } super.startActivity(intent, createActivityOptionsBundleForTransition(null)); } @@ -266,6 +270,10 @@ public class SettingsBaseActivity extends FragmentActivity { @Override protected void onPause() { + // For accessibility activities launched from setup wizard. + if (getTransitionType(getIntent()) == TransitionType.TRANSITION_FADE) { + overridePendingTransition(R.anim.sud_stay, android.R.anim.fade_out); + } unregisterReceiver(mPackageReceiver); super.onPause(); } From 5f0fc1ff9178652f0c73ad91d6912965b5bcc7c2 Mon Sep 17 00:00:00 2001 From: Jason Chiu Date: Mon, 24 May 2021 18:27:42 +0800 Subject: [PATCH 06/23] Add icon declaration in metadata for injected activities Settings injection no longer supports auto-load the component icon when metadata doesn't contain icon and icon_uri. Copy the icon resource from the activity to metadata. Bug: 186801104 Test: visual Change-Id: I3a90bbb5e27eb0f4491d57b1412b14a326fca0a7 --- AndroidManifest.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/AndroidManifest.xml b/AndroidManifest.xml index a21c4bb88ab..9ca7abbaa65 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -2115,6 +2115,8 @@ android:value="com.android.settings.category.ia.system" /> + + + From 5c60d3905e471a56c02f9669f3416a246d4db813 Mon Sep 17 00:00:00 2001 From: Yanting Yang Date: Tue, 25 May 2021 20:53:06 +0800 Subject: [PATCH 07/23] Remove silky flag from App info for official release Remove the silky condition and clean up redundant files. Bug: 183670633 Test: robotests & visual with turning on/off silky home Change-Id: I6b159c348dd3266a8515d58b3c5f508375ac4301 --- res/xml/app_info_settings.xml | 30 +-- res/xml/app_info_settings_v2.xml | 201 ------------------ .../appinfo/AppInfoDashboardFragment.java | 9 +- 3 files changed, 16 insertions(+), 224 deletions(-) delete mode 100644 res/xml/app_info_settings_v2.xml diff --git a/res/xml/app_info_settings.xml b/res/xml/app_info_settings.xml index f5d927ef26e..fef52432d24 100644 --- a/res/xml/app_info_settings.xml +++ b/res/xml/app_info_settings.xml @@ -18,33 +18,33 @@ + android:key="installed_app_detail_settings_screen"> + android:order="-10000" /> + android:order="-9999" /> + + + settings:controller="com.android.settings.applications.appinfo.AppNotificationPreferenceController" /> + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java b/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java index 6a5c5df30f6..a6ed4b82f8a 100755 --- a/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java +++ b/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java @@ -35,7 +35,6 @@ import android.os.Bundle; import android.os.UserHandle; import android.os.UserManager; import android.text.TextUtils; -import android.util.FeatureFlagUtils; import android.util.Log; import android.view.Menu; import android.view.MenuInflater; @@ -49,7 +48,6 @@ import com.android.settings.SettingsPreferenceFragment; import com.android.settings.applications.manageapplications.ManageApplications; import com.android.settings.applications.specialaccess.interactacrossprofiles.InteractAcrossProfilesDetailsPreferenceController; import com.android.settings.applications.specialaccess.pictureinpicture.PictureInPictureDetailPreferenceController; -import com.android.settings.core.FeatureFlags; import com.android.settings.core.SubSettingLauncher; import com.android.settings.dashboard.DashboardFragment; import com.android.settingslib.RestrictedLockUtilsInternal; @@ -166,9 +164,7 @@ public class AppInfoDashboardFragment extends DashboardFragment use(AppStoragePreferenceController.class).setParentFragment(this); use(AppVersionPreferenceController.class).setParentFragment(this); use(InstantAppDomainsPreferenceController.class).setParentFragment(this); - if (FeatureFlagUtils.isEnabled(context, FeatureFlags.SILKY_HOME)) { - use(ExtraAppInfoPreferenceController.class).setPackageName(packageName); - } + use(ExtraAppInfoPreferenceController.class).setPackageName(packageName); final HibernationSwitchPreferenceController appHibernationSettings = use(HibernationSwitchPreferenceController.class); @@ -258,9 +254,6 @@ public class AppInfoDashboardFragment extends DashboardFragment @Override protected int getPreferenceScreenResId() { - if (FeatureFlagUtils.isEnabled(getContext(), FeatureFlags.SILKY_HOME)) { - return R.xml.app_info_settings_v2; - } return R.xml.app_info_settings; } From 92feb9e8fcbac32240a80290c0a34fa43bb2e212 Mon Sep 17 00:00:00 2001 From: "Wesley.CW Wang" Date: Thu, 20 May 2021 00:01:49 +0800 Subject: [PATCH 08/23] Add new battery entry into AppInfo page launch variable - Insert uid as launch variable - Add new launch type into AppInfo page Bug: 178197718 Test: make RunSettingsRoboTests Change-Id: I8c68bebd02491dbbc1516bbebc14254ed06940f6 --- .../AppBatteryPreferenceController.java | 50 ++++++++++++++++++- .../appinfo/AppInfoDashboardFragment.java | 22 +++++++- .../BatteryChartPreferenceController.java | 4 +- .../AppBatteryPreferenceControllerTest.java | 6 ++- 4 files changed, 75 insertions(+), 7 deletions(-) diff --git a/src/com/android/settings/applications/appinfo/AppBatteryPreferenceController.java b/src/com/android/settings/applications/appinfo/AppBatteryPreferenceController.java index 6d515a31363..79cae92cf72 100644 --- a/src/com/android/settings/applications/appinfo/AppBatteryPreferenceController.java +++ b/src/com/android/settings/applications/appinfo/AppBatteryPreferenceController.java @@ -18,6 +18,7 @@ package com.android.settings.applications.appinfo; import android.content.Context; import android.content.pm.PackageInfo; +import android.os.AsyncTask; import android.os.BatteryUsageStats; import android.os.Bundle; import android.os.UidBatteryConsumer; @@ -34,6 +35,8 @@ import com.android.settings.R; import com.android.settings.Utils; import com.android.settings.core.BasePreferenceController; import com.android.settings.fuelgauge.AdvancedPowerUsageDetail; +import com.android.settings.fuelgauge.BatteryChartPreferenceController; +import com.android.settings.fuelgauge.BatteryDiffEntry; import com.android.settings.fuelgauge.BatteryEntry; import com.android.settings.fuelgauge.BatteryUsageStatsLoader; import com.android.settings.fuelgauge.BatteryUtils; @@ -63,13 +66,18 @@ public class AppBatteryPreferenceController extends BasePreferenceController private final AppInfoDashboardFragment mParent; private String mBatteryPercent; private final String mPackageName; + private final int mUid; + private BatteryDiffEntry mBatteryDiffEntry; + private boolean mBatteryUsageStatsLoaded = false; + private boolean mBatteryDiffEntriesLoaded = false; public AppBatteryPreferenceController(Context context, AppInfoDashboardFragment parent, - String packageName, Lifecycle lifecycle) { + String packageName, int uid, Lifecycle lifecycle) { super(context, KEY_BATTERY); mParent = parent; mBatteryUtils = BatteryUtils.getInstance(mContext); mPackageName = packageName; + mUid = uid; if (lifecycle != null) { lifecycle.addObserver(this); } @@ -87,6 +95,7 @@ public class AppBatteryPreferenceController extends BasePreferenceController super.displayPreference(screen); mPreference = screen.findPreference(getPreferenceKey()); mPreference.setEnabled(false); + loadBatteryDiffEntries(); } @Override @@ -94,6 +103,17 @@ public class AppBatteryPreferenceController extends BasePreferenceController if (!KEY_BATTERY.equals(preference.getKey())) { return false; } + if (mBatteryDiffEntry != null) { + AdvancedPowerUsageDetail.startBatteryDetailPage( + mParent.getActivity(), + mParent, + mBatteryDiffEntry, + mBatteryPercent, + /*isValidToShowSummary=*/ true, + /*slotInformation=*/ null); + return true; + } + if (isBatteryStatsAvailable()) { final UserManager userManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE); @@ -121,6 +141,31 @@ public class AppBatteryPreferenceController extends BasePreferenceController AppInfoDashboardFragment.LOADER_BATTERY_USAGE_STATS); } + private void loadBatteryDiffEntries() { + new AsyncTask() { + @Override + protected BatteryDiffEntry doInBackground(Void... unused) { + final List batteryDiffEntries = + BatteryChartPreferenceController.getBatteryLast24HrUsageData(mContext); + if (batteryDiffEntries != null) { + for (BatteryDiffEntry batteryDiffEntry : batteryDiffEntries) { + if (batteryDiffEntry.mBatteryHistEntry.mUid == mUid) { + return batteryDiffEntry; + } + } + } + return null; + } + + @Override + protected void onPostExecute(BatteryDiffEntry batteryDiffEntry) { + mBatteryDiffEntry = batteryDiffEntry; + mBatteryDiffEntriesLoaded = true; + mPreference.setEnabled(mBatteryUsageStatsLoaded); + } + }.execute(); + } + private void onLoadFinished() { if (mBatteryUsageStats == null) { return; @@ -138,7 +183,8 @@ public class AppBatteryPreferenceController extends BasePreferenceController @VisibleForTesting void updateBattery() { - mPreference.setEnabled(true); + mBatteryUsageStatsLoaded = true; + mPreference.setEnabled(mBatteryDiffEntriesLoaded); if (isBatteryStatsAvailable()) { final int percentOfMax = (int) mBatteryUtils.calculateBatteryPercent( mUidBatteryConsumer.getConsumedPower(), mBatteryUsageStats.getConsumedPower(), diff --git a/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java b/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java index 6a5c5df30f6..2f9ead74209 100755 --- a/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java +++ b/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java @@ -111,6 +111,7 @@ public class AppInfoDashboardFragment extends DashboardFragment private PackageInfo mPackageInfo; private int mUserId; private String mPackageName; + private int mUid; private DevicePolicyManager mDpm; private UserManager mUserManager; @@ -297,7 +298,8 @@ public class AppInfoDashboardFragment extends DashboardFragment (SettingsActivity) getActivity(), this, lifecycle, packageName, mState, REQUEST_UNINSTALL, REQUEST_REMOVE_DEVICE_ADMIN); controllers.add(mAppButtonsPreferenceController); - controllers.add(new AppBatteryPreferenceController(context, this, packageName, lifecycle)); + controllers.add(new AppBatteryPreferenceController( + context, this, packageName, getUid(), lifecycle)); controllers.add(new AppMemoryPreferenceController(context, this, lifecycle)); controllers.add(new DefaultHomeShortcutPreferenceController(context, packageName)); controllers.add(new DefaultBrowserShortcutPreferenceController(context, packageName)); @@ -568,7 +570,7 @@ public class AppInfoDashboardFragment extends DashboardFragment final Bundle args = getArguments(); mPackageName = (args != null) ? args.getString(ARG_PACKAGE_NAME) : null; if (mPackageName == null) { - final Intent intent = (args == null) ? + final Intent intent = args == null ? getActivity().getIntent() : (Intent) args.getParcelable("intent"); if (intent != null) { mPackageName = intent.getData().getSchemeSpecificPart(); @@ -577,6 +579,22 @@ public class AppInfoDashboardFragment extends DashboardFragment return mPackageName; } + private int getUid() { + if (mUid > 0) { + return mUid; + } + final Bundle args = getArguments(); + mUid = (args != null) ? args.getInt(ARG_PACKAGE_UID) : -1; + if (mUid <= 0) { + final Intent intent = args == null + ? getActivity().getIntent() : (Intent) args.getParcelable("intent"); + if (intent != null && intent.getExtras() != null) { + mUid = intent.getIntExtra("uId", -1); + } + } + return mUid; + } + @VisibleForTesting void retrieveAppEntry() { final Activity activity = getActivity(); diff --git a/src/com/android/settings/fuelgauge/BatteryChartPreferenceController.java b/src/com/android/settings/fuelgauge/BatteryChartPreferenceController.java index a36c2ef964a..b2b6856ebfc 100644 --- a/src/com/android/settings/fuelgauge/BatteryChartPreferenceController.java +++ b/src/com/android/settings/fuelgauge/BatteryChartPreferenceController.java @@ -50,8 +50,8 @@ import com.android.settingslib.core.lifecycle.events.OnSaveInstanceState; import com.android.settingslib.utils.StringUtil; import com.android.settingslib.widget.FooterPreference; -import java.util.Arrays; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; @@ -638,7 +638,7 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll return true; } - static List getBatteryLast24HrUsageData(Context context) { + public static List getBatteryLast24HrUsageData(Context context) { final long start = System.currentTimeMillis(); final Map> batteryHistoryMap = FeatureFactory.getFactory(context) diff --git a/tests/robotests/src/com/android/settings/applications/appinfo/AppBatteryPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/applications/appinfo/AppBatteryPreferenceControllerTest.java index 71ab3344b29..73e9bed3a61 100644 --- a/tests/robotests/src/com/android/settings/applications/appinfo/AppBatteryPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/applications/appinfo/AppBatteryPreferenceControllerTest.java @@ -96,7 +96,11 @@ public class AppBatteryPreferenceControllerTest { when(mOtherUidBatteryConsumer.getUid()).thenReturn(OTHER_UID); mController = spy(new AppBatteryPreferenceController( - RuntimeEnvironment.application, mFragment, "package1", null /* lifecycle */)); + RuntimeEnvironment.application, + mFragment, + "package1" /* packageName */, + 0 /* uId */, + null /* lifecycle */)); mController.mBatteryUtils = mBatteryUtils; when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mBatteryPreference); } From 044c91cc70ab40a4e32e27914eba56454a5fa40e Mon Sep 17 00:00:00 2001 From: Arc Wang Date: Mon, 17 May 2021 15:52:51 +0800 Subject: [PATCH 09/23] Query storage size instead of calculate size of installed APP From android S, Storage Settings show files of images/videos/audios category instead of installed APP of each category. So it's necessary to change the way to calculate size information. This change also - StorageItemPreference shows changing storage size units instead of fixed GB. It helps UX for categories of only small size files. - Query media provider for size of Documents and others. - Query media provider for size of Trash. Bug: 170918505 Bug: 177892478 Bug: 179871408 Bug: 184379946 Bug: 186077224 Bug: 187128447 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 manual visual Click each file category to count files size is the same as displayed in Storage Settings. Change-Id: I37c7b3a4b5860323cb55581b23a90f583f4af216 --- .../deviceinfo/StorageCategoryFragment.java | 22 +-- .../deviceinfo/StorageDashboardFragment.java | 22 +-- .../deviceinfo/StorageItemPreference.java | 19 ++- .../storage/CachedStorageValuesHelper.java | 59 +++++--- .../storage/SecondaryUserController.java | 6 +- .../storage/StorageAsyncLoader.java | 142 +++++++++++------- .../StorageItemPreferenceController.java | 65 +++----- .../StorageDashboardFragmentTest.java | 20 +-- .../deviceinfo/StorageItemPreferenceTest.java | 2 +- .../CachedStorageValuesHelperTest.java | 100 ++++++------ .../storage/SecondaryUserControllerTest.java | 10 +- .../StorageItemPreferenceControllerTest.java | 29 ++-- .../storage/StorageAsyncLoaderTest.java | 69 +++------ 13 files changed, 279 insertions(+), 286 deletions(-) diff --git a/src/com/android/settings/deviceinfo/StorageCategoryFragment.java b/src/com/android/settings/deviceinfo/StorageCategoryFragment.java index ba59498a795..ce8f2199187 100644 --- a/src/com/android/settings/deviceinfo/StorageCategoryFragment.java +++ b/src/com/android/settings/deviceinfo/StorageCategoryFragment.java @@ -70,7 +70,7 @@ import java.util.List; */ public class StorageCategoryFragment extends DashboardFragment implements - LoaderManager.LoaderCallbacks>, + LoaderManager.LoaderCallbacks>, Preference.OnPreferenceClickListener { private static final String TAG = "StorageCategoryFrag"; private static final String SUMMARY_PREF_KEY = "storage_summary"; @@ -83,7 +83,7 @@ public class StorageCategoryFragment extends DashboardFragment private UserManager mUserManager; private StorageEntry mSelectedStorageEntry; private PrivateStorageInfo mStorageInfo; - private SparseArray mAppsResult; + private SparseArray mAppsResult; private CachedStorageValuesHelper mCachedStorageValuesHelper; private StorageItemPreferenceController mPreferenceController; @@ -232,7 +232,7 @@ public class StorageCategoryFragment extends DashboardFragment * Updates the secondary user controller sizes. */ private void updateSecondaryUserControllers(List controllers, - SparseArray stats) { + SparseArray stats) { for (int i = 0, size = controllers.size(); i < size; i++) { final AbstractPreferenceController controller = controllers.get(i); if (controller instanceof StorageAsyncLoader.ResultHandler) { @@ -244,7 +244,7 @@ public class StorageCategoryFragment extends DashboardFragment } @Override - public Loader> onCreateLoader(int id, + public Loader> onCreateLoader(int id, Bundle args) { final Context context = getContext(); return new StorageAsyncLoader(context, mUserManager, @@ -254,15 +254,15 @@ public class StorageCategoryFragment extends DashboardFragment } @Override - public void onLoadFinished(Loader> loader, - SparseArray data) { + public void onLoadFinished(Loader> loader, + SparseArray data) { mAppsResult = data; maybeCacheFreshValues(); onReceivedSizes(); } @Override - public void onLoaderReset(Loader> loader) { + public void onLoaderReset(Loader> loader) { } @Override @@ -296,20 +296,20 @@ public class StorageCategoryFragment extends DashboardFragment } @VisibleForTesting - public SparseArray getAppsStorageResult() { + public SparseArray getStorageResult() { return mAppsResult; } @VisibleForTesting - public void setAppsStorageResult(SparseArray info) { + public void setStorageResult(SparseArray info) { mAppsResult = info; } @VisibleForTesting void initializeCachedValues() { final PrivateStorageInfo info = mCachedStorageValuesHelper.getCachedPrivateStorageInfo(); - final SparseArray loaderResult = - mCachedStorageValuesHelper.getCachedAppsStorageResult(); + final SparseArray loaderResult = + mCachedStorageValuesHelper.getCachedStorageResult(); if (info == null || loaderResult == null) { return; } diff --git a/src/com/android/settings/deviceinfo/StorageDashboardFragment.java b/src/com/android/settings/deviceinfo/StorageDashboardFragment.java index cc7eff6a27b..1145d7fa47c 100644 --- a/src/com/android/settings/deviceinfo/StorageDashboardFragment.java +++ b/src/com/android/settings/deviceinfo/StorageDashboardFragment.java @@ -85,7 +85,7 @@ import java.util.List; @SearchIndexable public class StorageDashboardFragment extends DashboardFragment implements - LoaderManager.LoaderCallbacks>, + LoaderManager.LoaderCallbacks>, Preference.OnPreferenceClickListener { private static final String TAG = "StorageDashboardFrag"; private static final String SUMMARY_PREF_KEY = "storage_summary"; @@ -100,7 +100,7 @@ public class StorageDashboardFragment extends DashboardFragment private final List mStorageEntries = new ArrayList<>(); private StorageEntry mSelectedStorageEntry; private PrivateStorageInfo mStorageInfo; - private SparseArray mAppsResult; + private SparseArray mAppsResult; private CachedStorageValuesHelper mCachedStorageValuesHelper; private StorageItemPreferenceController mPreferenceController; @@ -414,7 +414,7 @@ public class StorageDashboardFragment extends DashboardFragment * Updates the secondary user controller sizes. */ private void updateSecondaryUserControllers(List controllers, - SparseArray stats) { + SparseArray stats) { for (int i = 0, size = controllers.size(); i < size; i++) { final AbstractPreferenceController controller = controllers.get(i); if (controller instanceof StorageAsyncLoader.ResultHandler) { @@ -455,7 +455,7 @@ public class StorageDashboardFragment extends DashboardFragment }; @Override - public Loader> onCreateLoader(int id, + public Loader> onCreateLoader(int id, Bundle args) { final Context context = getContext(); return new StorageAsyncLoader(context, mUserManager, @@ -465,15 +465,15 @@ public class StorageDashboardFragment extends DashboardFragment } @Override - public void onLoadFinished(Loader> loader, - SparseArray data) { + public void onLoadFinished(Loader> loader, + SparseArray data) { mAppsResult = data; maybeCacheFreshValues(); onReceivedSizes(); } @Override - public void onLoaderReset(Loader> loader) { + public void onLoaderReset(Loader> loader) { } @Override @@ -507,20 +507,20 @@ public class StorageDashboardFragment extends DashboardFragment } @VisibleForTesting - public SparseArray getAppsStorageResult() { + public SparseArray getStorageResult() { return mAppsResult; } @VisibleForTesting - public void setAppsStorageResult(SparseArray info) { + public void setStorageResult(SparseArray info) { mAppsResult = info; } @VisibleForTesting void initializeCachedValues() { final PrivateStorageInfo info = mCachedStorageValuesHelper.getCachedPrivateStorageInfo(); - final SparseArray loaderResult = - mCachedStorageValuesHelper.getCachedAppsStorageResult(); + final SparseArray loaderResult = + mCachedStorageValuesHelper.getCachedStorageResult(); if (info == null || loaderResult == null) { return; } diff --git a/src/com/android/settings/deviceinfo/StorageItemPreference.java b/src/com/android/settings/deviceinfo/StorageItemPreference.java index 65ef6f4849e..8410e42c889 100644 --- a/src/com/android/settings/deviceinfo/StorageItemPreference.java +++ b/src/com/android/settings/deviceinfo/StorageItemPreference.java @@ -17,7 +17,8 @@ package com.android.settings.deviceinfo; import android.content.Context; -import android.content.res.Resources; +import android.text.TextUtils; +import android.text.format.Formatter; import android.util.AttributeSet; import android.widget.ProgressBar; @@ -25,7 +26,6 @@ import androidx.preference.Preference; import androidx.preference.PreferenceViewHolder; import com.android.settings.R; -import com.android.settings.utils.FileSizeFormatter; public class StorageItemPreference extends Preference { public int userHandle; @@ -49,12 +49,8 @@ public class StorageItemPreference extends Preference { public void setStorageSize(long size, long total) { mStorageSize = size; - setSummary( - FileSizeFormatter.formatFileSize( - getContext(), - size, - getGigabyteSuffix(getContext().getResources()), - FileSizeFormatter.GIGABYTE_IN_BYTES)); + setSummary(getStorageSummary(size)); + if (total == 0) { mProgressPercent = 0; } else { @@ -82,7 +78,10 @@ public class StorageItemPreference extends Preference { super.onBindViewHolder(view); } - private static int getGigabyteSuffix(Resources res) { - return res.getIdentifier("gigabyteShort", "string", "android"); + private String getStorageSummary(long bytes) { + final Formatter.BytesResult result = Formatter.formatBytes(getContext().getResources(), + bytes, Formatter.FLAG_SHORTER); + return TextUtils.expandTemplate(getContext().getText(R.string.storage_size_large), + result.value, result.units).toString(); } } diff --git a/src/com/android/settings/deviceinfo/storage/CachedStorageValuesHelper.java b/src/com/android/settings/deviceinfo/storage/CachedStorageValuesHelper.java index e6d9a724d94..4ca623dc53d 100644 --- a/src/com/android/settings/deviceinfo/storage/CachedStorageValuesHelper.java +++ b/src/com/android/settings/deviceinfo/storage/CachedStorageValuesHelper.java @@ -35,9 +35,11 @@ public class CachedStorageValuesHelper { public static final String FREE_BYTES_KEY = "free_bytes"; public static final String TOTAL_BYTES_KEY = "total_bytes"; public static final String GAME_APPS_SIZE_KEY = "game_apps_size"; - public static final String MUSIC_APPS_SIZE_KEY = "music_apps_size"; - public static final String VIDEO_APPS_SIZE_KEY = "video_apps_size"; - public static final String PHOTO_APPS_SIZE_KEY = "photo_apps_size"; + public static final String 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"; @@ -78,21 +80,27 @@ public class CachedStorageValuesHelper { return new PrivateStorageInfo(freeBytes, totalBytes); } - public SparseArray getCachedAppsStorageResult() { + /** Returns cached storage result or null if it's not available. */ + public SparseArray getCachedStorageResult() { if (!isDataValid()) { return null; } final long gamesSize = mSharedPreferences.getLong(GAME_APPS_SIZE_KEY, -1); - final long musicAppsSize = mSharedPreferences.getLong(MUSIC_APPS_SIZE_KEY, -1); - final long videoAppsSize = mSharedPreferences.getLong(VIDEO_APPS_SIZE_KEY, -1); - final long photoAppSize = mSharedPreferences.getLong(PHOTO_APPS_SIZE_KEY, -1); - final long otherAppsSize = mSharedPreferences.getLong(OTHER_APPS_SIZE_KEY, -1); + final long 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 - || musicAppsSize < 0 - || videoAppsSize < 0 - || photoAppSize < 0 - || otherAppsSize < 0 + || audioSize < 0 + || videosSize < 0 + || imagesSize < 0 + || documentsAndOtherSize < 0 + || trashSize < 0 + || allAppsExceptGamesSize < 0 || cacheSize < 0) { return null; } @@ -117,31 +125,34 @@ public class CachedStorageValuesHelper { externalVideoBytes, externalImageBytes, externalAppBytes); - final StorageAsyncLoader.AppsStorageResult result = - new StorageAsyncLoader.AppsStorageResult(); + final StorageAsyncLoader.StorageResult result = new StorageAsyncLoader.StorageResult(); result.gamesSize = gamesSize; - result.musicAppsSize = musicAppsSize; - result.videoAppsSize = videoAppsSize; - result.photosAppsSize = photoAppSize; - result.otherAppsSize = otherAppsSize; + 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 resultArray = new SparseArray<>(); + final SparseArray resultArray = new SparseArray<>(); resultArray.append(mUserId, result); return resultArray; } public void cacheResult( - PrivateStorageInfo storageInfo, StorageAsyncLoader.AppsStorageResult result) { + 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(MUSIC_APPS_SIZE_KEY, result.musicAppsSize) - .putLong(VIDEO_APPS_SIZE_KEY, result.videoAppsSize) - .putLong(PHOTO_APPS_SIZE_KEY, result.photosAppsSize) - .putLong(OTHER_APPS_SIZE_KEY, result.otherAppsSize) + .putLong(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) diff --git a/src/com/android/settings/deviceinfo/storage/SecondaryUserController.java b/src/com/android/settings/deviceinfo/storage/SecondaryUserController.java index 99b67526730..6475029f21b 100644 --- a/src/com/android/settings/deviceinfo/storage/SecondaryUserController.java +++ b/src/com/android/settings/deviceinfo/storage/SecondaryUserController.java @@ -168,9 +168,9 @@ public class SecondaryUserController extends AbstractPreferenceController implem mTotalSizeBytes = totalSizeBytes; } - public void handleResult(SparseArray stats) { - int userId = getUser().id; - StorageAsyncLoader.AppsStorageResult result = stats.get(userId); + @Override + public void handleResult(SparseArray stats) { + final StorageAsyncLoader.StorageResult result = stats.get(getUser().id); if (result != null) { setSize(result.externalStats.totalBytes); } diff --git a/src/com/android/settings/deviceinfo/storage/StorageAsyncLoader.java b/src/com/android/settings/deviceinfo/storage/StorageAsyncLoader.java index 3d8a822f3cb..0a67ef29a27 100644 --- a/src/com/android/settings/deviceinfo/storage/StorageAsyncLoader.java +++ b/src/com/android/settings/deviceinfo/storage/StorageAsyncLoader.java @@ -21,13 +21,20 @@ import static android.content.pm.ApplicationInfo.CATEGORY_GAME; import static android.content.pm.ApplicationInfo.CATEGORY_IMAGE; import static android.content.pm.ApplicationInfo.CATEGORY_VIDEO; +import android.content.ContentResolver; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.UserInfo; +import android.database.Cursor; +import android.net.Uri; +import android.os.Bundle; import android.os.UserHandle; import android.os.UserManager; +import android.provider.MediaStore; +import android.provider.MediaStore.Files.FileColumns; +import android.provider.MediaStore.MediaColumns; import android.util.ArraySet; import android.util.Log; import android.util.SparseArray; @@ -37,7 +44,6 @@ import com.android.settingslib.utils.AsyncLoaderCompat; import java.io.IOException; import java.util.Collections; -import java.util.Comparator; import java.util.List; /** @@ -45,7 +51,7 @@ import java.util.List; * users */ public class StorageAsyncLoader - extends AsyncLoaderCompat> { + extends AsyncLoaderCompat> { private UserManager mUserManager; private static final String TAG = "StorageAsyncLoader"; @@ -64,38 +70,81 @@ public class StorageAsyncLoader } @Override - public SparseArray loadInBackground() { - return loadApps(); + public SparseArray loadInBackground() { + return getStorageResultsForUsers(); } - private SparseArray loadApps() { + private SparseArray getStorageResultsForUsers() { mSeenPackages = new ArraySet<>(); - SparseArray result = new SparseArray<>(); - List infos = mUserManager.getUsers(); + final SparseArray results = new SparseArray<>(); + final List infos = mUserManager.getUsers(); + // Sort the users by user id ascending. - Collections.sort( - infos, - new Comparator() { - @Override - public int compare(UserInfo userInfo, UserInfo otherUser) { - return Integer.compare(userInfo.id, otherUser.id); - } - }); - for (int i = 0, userCount = infos.size(); i < userCount; i++) { - final UserInfo info = infos.get(i); - result.put(info.id, getStorageResultForUser(info.id)); + Collections.sort(infos, + (userInfo, otherUser) -> Integer.compare(userInfo.id, otherUser.id)); + + for (UserInfo info : infos) { + final StorageResult result = getAppsAndGamesSize(info.id); + + result.imagesSize = getFilesSize(info.id, MediaStore.Images.Media.EXTERNAL_CONTENT_URI, + null /* queryArgs */); + result.videosSize = getFilesSize(info.id, MediaStore.Video.Media.EXTERNAL_CONTENT_URI, + null /* queryArgs */); + result.audioSize = getFilesSize(info.id, MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, + null /* queryArgs */); + + final Bundle documentsAndOtherQueryArgs = new Bundle(); + documentsAndOtherQueryArgs.putString(ContentResolver.QUERY_ARG_SQL_SELECTION, + FileColumns.MEDIA_TYPE + "!=" + FileColumns.MEDIA_TYPE_IMAGE + + " AND " + FileColumns.MEDIA_TYPE + "!=" + FileColumns.MEDIA_TYPE_VIDEO + + " AND " + FileColumns.MEDIA_TYPE + "!=" + FileColumns.MEDIA_TYPE_AUDIO + + " AND " + FileColumns.MIME_TYPE + " IS NOT NULL"); + result.documentsAndOtherSize = getFilesSize(info.id, + MediaStore.Files.getContentUri(MediaStore.VOLUME_EXTERNAL), + documentsAndOtherQueryArgs); + + final Bundle trashQueryArgs = new Bundle(); + trashQueryArgs.putInt(MediaStore.QUERY_ARG_MATCH_TRASHED, MediaStore.MATCH_ONLY); + result.trashSize = getFilesSize(info.id, + MediaStore.Files.getContentUri(MediaStore.VOLUME_EXTERNAL), trashQueryArgs); + + results.put(info.id, result); } - return result; + return results; } - private AppsStorageResult getStorageResultForUser(int userId) { + private long getFilesSize(int userId, Uri uri, Bundle queryArgs) { + final Context perUserContext; + try { + perUserContext = getContext().createPackageContextAsUser( + getContext().getApplicationContext().getPackageName(), + 0 /* flags= */, + UserHandle.of(userId)); + } catch (NameNotFoundException e) { + Log.e(TAG, "Not able to get Context for user ID " + userId); + return 0; + } + + try (Cursor cursor = perUserContext.getContentResolver().query( + uri, + new String[] {"sum(" + MediaColumns.SIZE + ")"}, + queryArgs, + null /* cancellationSignal */)) { + if (cursor == null) { + return 0; + } + return cursor.moveToFirst() ? cursor.getInt(0) : 0; + } + } + + private StorageResult getAppsAndGamesSize(int userId) { Log.d(TAG, "Loading apps"); - List applicationInfos = + final List applicationInfos = mPackageManager.getInstalledApplicationsAsUser(0, userId); - AppsStorageResult result = new AppsStorageResult(); - UserHandle myUser = UserHandle.of(userId); + final StorageResult result = new StorageResult(); + final UserHandle myUser = UserHandle.of(userId); for (int i = 0, size = applicationInfos.size(); i < size; i++) { - ApplicationInfo app = applicationInfos.get(i); + final ApplicationInfo app = applicationInfos.get(i); StorageStatsSource.AppStorageStats stats; try { @@ -131,28 +180,9 @@ public class StorageAsyncLoader result.gamesSize += blamedSize; break; case CATEGORY_AUDIO: - // TODO(b/170918505): Should revamp audio size calculation with the data - // from media provider. - result.musicAppsSize += blamedSize; - result.musicAppsSize -= stats.getCodeBytes(); - - result.otherAppsSize += blamedSize; - break; case CATEGORY_VIDEO: - // TODO(b/170918505): Should revamp video size calculation with the data - // from media provider. - result.videoAppsSize += blamedSize; - result.videoAppsSize -= stats.getCodeBytes(); - - result.otherAppsSize += blamedSize; - break; case CATEGORY_IMAGE: - // TODO(b/170918505): Should revamp image size calculation with the data - // from media provider. - result.photosAppsSize += blamedSize; - result.photosAppsSize -= stats.getCodeBytes(); - - result.otherAppsSize += blamedSize; + result.allAppsExceptGamesSize += blamedSize; break; default: // The deprecated game flag does not set the category. @@ -160,7 +190,7 @@ public class StorageAsyncLoader result.gamesSize += blamedSize; break; } - result.otherAppsSize += blamedSize; + result.allAppsExceptGamesSize += blamedSize; break; } } @@ -177,15 +207,22 @@ public class StorageAsyncLoader } @Override - protected void onDiscardResult(SparseArray result) { + protected void onDiscardResult(SparseArray result) { } - public static class AppsStorageResult { + /** Storage result for displaying file categories size in Storage Settings. */ + public static class StorageResult { + // APP based sizes. public long gamesSize; - public long musicAppsSize; - public long photosAppsSize; - public long videoAppsSize; - public long otherAppsSize; + public long allAppsExceptGamesSize; + + // File based sizes. + public long audioSize; + public long imagesSize; + public long videosSize; + public long documentsAndOtherSize; + public long trashSize; + public long cacheSize; public long duplicateCodeSize; public StorageStatsSource.ExternalStorageStats externalStats; @@ -196,6 +233,7 @@ public class StorageAsyncLoader * {@link StorageAsyncLoader}. */ public interface ResultHandler { - void handleResult(SparseArray result); + /** Overrides this method to get storage result once it's available. */ + void handleResult(SparseArray result); } } diff --git a/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceController.java b/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceController.java index 241c852911c..67a5bb7f49d 100644 --- a/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceController.java +++ b/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceController.java @@ -357,18 +357,18 @@ public class StorageItemPreferenceController extends AbstractPreferenceControlle updatePrivateStorageCategoryPreferencesOrder(); } - public void onLoadFinished(SparseArray result, + /** Fragments use it to set storage result and update UI of this controller. */ + public void onLoadFinished(SparseArray result, int userId) { - final StorageAsyncLoader.AppsStorageResult data = result.get(userId); + final StorageAsyncLoader.StorageResult data = result.get(userId); - mImagesPreference.setStorageSize(getImagesSize(data), mTotalSize); - mVideosPreference.setStorageSize(getVideosSize(data), mTotalSize); - mAudioPreference.setStorageSize(getAudioSize(data), mTotalSize); - mAppsPreference.setStorageSize(getAppsSize(data), mTotalSize); - mGamesPreference.setStorageSize(getGamesSize(data), mTotalSize); - mDocumentsAndOtherPreference.setStorageSize(getDocumentsAndOtherSize(data), - mTotalSize); - mTrashPreference.setStorageSize(getTrashSize(data), mTotalSize); + 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); if (mSystemPreference != null) { // Everything else that hasn't already been attributed is tracked as @@ -377,13 +377,15 @@ public class StorageItemPreferenceController extends AbstractPreferenceControlle // from media provider. long attributedSize = 0; for (int i = 0; i < result.size(); i++) { - final StorageAsyncLoader.AppsStorageResult otherData = result.valueAt(i); + final StorageAsyncLoader.StorageResult otherData = result.valueAt(i); attributedSize += otherData.gamesSize - + otherData.musicAppsSize - + otherData.videoAppsSize - + otherData.photosAppsSize - + otherData.otherAppsSize; + + otherData.audioSize + + otherData.videosSize + + otherData.imagesSize + + otherData.documentsAndOtherSize + + otherData.trashSize + + otherData.allAppsExceptGamesSize; attributedSize += otherData.externalStats.totalBytes - otherData.externalStats.appBytes; attributedSize -= otherData.duplicateCodeSize; @@ -418,18 +420,6 @@ public class StorageItemPreferenceController extends AbstractPreferenceControlle mContext.startActivityAsUser(intent, new UserHandle(mUserId)); } - private long getImagesSize(StorageAsyncLoader.AppsStorageResult data) { - return data.photosAppsSize + data.externalStats.imageBytes + data.externalStats.videoBytes; - } - - private long getVideosSize(StorageAsyncLoader.AppsStorageResult data) { - return data.videoAppsSize; - } - - private long getAudioSize(StorageAsyncLoader.AppsStorageResult data) { - return data.musicAppsSize + data.externalStats.audioBytes; - } - private void launchAppsIntent() { final Bundle args = getWorkAnnotatedBundle(3); args.putString(ManageApplications.EXTRA_CLASSNAME, @@ -446,10 +436,6 @@ public class StorageItemPreferenceController extends AbstractPreferenceControlle Utils.launchIntent(mFragment, intent); } - private long getAppsSize(StorageAsyncLoader.AppsStorageResult data) { - return data.otherAppsSize; - } - private void launchGamesIntent() { final Bundle args = getWorkAnnotatedBundle(1); args.putString(ManageApplications.EXTRA_CLASSNAME, @@ -464,10 +450,6 @@ public class StorageItemPreferenceController extends AbstractPreferenceControlle Utils.launchIntent(mFragment, intent); } - private long getGamesSize(StorageAsyncLoader.AppsStorageResult data) { - return data.gamesSize; - } - private Bundle getWorkAnnotatedBundle(int additionalCapacity) { final Bundle args = new Bundle(1 + additionalCapacity); args.putInt(SettingsActivity.EXTRA_SHOW_FRAGMENT_TAB, @@ -475,14 +457,6 @@ public class StorageItemPreferenceController extends AbstractPreferenceControlle return args; } - private long getDocumentsAndOtherSize(StorageAsyncLoader.AppsStorageResult data) { - return data.externalStats.totalBytes - - data.externalStats.audioBytes - - data.externalStats.videoBytes - - data.externalStats.imageBytes - - data.externalStats.appBytes; - } - private void launchTrashIntent() { final Intent intent = new Intent("android.settings.VIEW_TRASH"); @@ -493,11 +467,6 @@ public class StorageItemPreferenceController extends AbstractPreferenceControlle } } - private long getTrashSize(StorageAsyncLoader.AppsStorageResult data) { - // TODO(170918505): Implement it. - return 0L; - } - private static long totalValues(StorageMeasurement.MeasurementDetails details, int userId, String... keys) { long total = 0; diff --git a/tests/robotests/src/com/android/settings/deviceinfo/StorageDashboardFragmentTest.java b/tests/robotests/src/com/android/settings/deviceinfo/StorageDashboardFragmentTest.java index 4e4375dc72e..af1900ac83a 100644 --- a/tests/robotests/src/com/android/settings/deviceinfo/StorageDashboardFragmentTest.java +++ b/tests/robotests/src/com/android/settings/deviceinfo/StorageDashboardFragmentTest.java @@ -77,14 +77,14 @@ public class StorageDashboardFragmentTest { CachedStorageValuesHelper helper = mock(CachedStorageValuesHelper.class); PrivateStorageInfo info = new PrivateStorageInfo(0, 0); when(helper.getCachedPrivateStorageInfo()).thenReturn(info); - SparseArray result = new SparseArray<>(); - when(helper.getCachedAppsStorageResult()).thenReturn(result); + SparseArray result = new SparseArray<>(); + when(helper.getCachedStorageResult()).thenReturn(result); mFragment.setCachedStorageValuesHelper(helper); mFragment.initializeCachedValues(); assertThat(mFragment.getPrivateStorageInfo()).isEqualTo(info); - assertThat(mFragment.getAppsStorageResult()).isEqualTo(result); + assertThat(mFragment.getStorageResult()).isEqualTo(result); } @Test @@ -97,20 +97,20 @@ public class StorageDashboardFragmentTest { mFragment.initializeCachedValues(); assertThat(mFragment.getPrivateStorageInfo()).isNull(); - assertThat(mFragment.getAppsStorageResult()).isNull(); + assertThat(mFragment.getStorageResult()).isNull(); } @Test public void test_cacheProviderDoesntProvideValuesIfVolumeInfoMissing() { CachedStorageValuesHelper helper = mock(CachedStorageValuesHelper.class); - SparseArray result = new SparseArray<>(); - when(helper.getCachedAppsStorageResult()).thenReturn(result); + SparseArray result = new SparseArray<>(); + when(helper.getCachedStorageResult()).thenReturn(result); mFragment.setCachedStorageValuesHelper(helper); mFragment.initializeCachedValues(); assertThat(mFragment.getPrivateStorageInfo()).isNull(); - assertThat(mFragment.getAppsStorageResult()).isNull(); + assertThat(mFragment.getStorageResult()).isNull(); } @Test @@ -169,7 +169,7 @@ public class StorageDashboardFragmentTest { mFragment = spy(mFragment); when(mFragment.getView()).thenReturn(fakeView); when(mFragment.getListView()).thenReturn(fakeRecyclerView); - mFragment.setAppsStorageResult(new SparseArray<>()); + mFragment.setStorageResult(new SparseArray<>()); mFragment.maybeSetLoading(true); @@ -185,7 +185,7 @@ public class StorageDashboardFragmentTest { when(mFragment.getView()).thenReturn(fakeView); when(mFragment.getListView()).thenReturn(fakeRecyclerView); - mFragment.setAppsStorageResult(new SparseArray<>()); + mFragment.setStorageResult(new SparseArray<>()); PrivateStorageInfo storageInfo = new PrivateStorageInfo(0, 0); mFragment.setPrivateStorageInfo(storageInfo); @@ -203,4 +203,4 @@ public class StorageDashboardFragmentTest { assertThat(indexRes).isNotNull(); assertThat(indexRes.get(0).xmlResId).isEqualTo(mFragment.getPreferenceScreenResId()); } -} \ No newline at end of file +} diff --git a/tests/robotests/src/com/android/settings/deviceinfo/StorageItemPreferenceTest.java b/tests/robotests/src/com/android/settings/deviceinfo/StorageItemPreferenceTest.java index 5795157e684..24543801ef7 100644 --- a/tests/robotests/src/com/android/settings/deviceinfo/StorageItemPreferenceTest.java +++ b/tests/robotests/src/com/android/settings/deviceinfo/StorageItemPreferenceTest.java @@ -54,7 +54,7 @@ public class StorageItemPreferenceTest { @Test public void testAfterLoad() { mPreference.setStorageSize(MEGABYTE_IN_BYTES * 10, MEGABYTE_IN_BYTES * 100); - assertThat(mPreference.getSummary()).isEqualTo("0.01 GB"); + assertThat(mPreference.getSummary()).isEqualTo("10 MB"); } @Test diff --git a/tests/robotests/src/com/android/settings/deviceinfo/storage/CachedStorageValuesHelperTest.java b/tests/robotests/src/com/android/settings/deviceinfo/storage/CachedStorageValuesHelperTest.java index d4048acea90..ccc9152a014 100644 --- a/tests/robotests/src/com/android/settings/deviceinfo/storage/CachedStorageValuesHelperTest.java +++ b/tests/robotests/src/com/android/settings/deviceinfo/storage/CachedStorageValuesHelperTest.java @@ -16,7 +16,9 @@ package com.android.settings.deviceinfo.storage; +import static com.android.settings.deviceinfo.storage.CachedStorageValuesHelper.AUDIO_SIZE_KEY; import static com.android.settings.deviceinfo.storage.CachedStorageValuesHelper.CACHE_APPS_SIZE_KEY; +import static com.android.settings.deviceinfo.storage.CachedStorageValuesHelper.DOCUMENTS_AND_OTHER_SIZE_KEY; import static com.android.settings.deviceinfo.storage.CachedStorageValuesHelper.EXTERNAL_APP_BYTES; import static com.android.settings.deviceinfo.storage.CachedStorageValuesHelper .EXTERNAL_AUDIO_BYTES; @@ -28,15 +30,15 @@ import static com.android.settings.deviceinfo.storage.CachedStorageValuesHelper .EXTERNAL_VIDEO_BYTES; import static com.android.settings.deviceinfo.storage.CachedStorageValuesHelper.FREE_BYTES_KEY; import static com.android.settings.deviceinfo.storage.CachedStorageValuesHelper.GAME_APPS_SIZE_KEY; -import static com.android.settings.deviceinfo.storage.CachedStorageValuesHelper.MUSIC_APPS_SIZE_KEY; +import static com.android.settings.deviceinfo.storage.CachedStorageValuesHelper.IMAGES_SIZE_KEY; import static com.android.settings.deviceinfo.storage.CachedStorageValuesHelper.OTHER_APPS_SIZE_KEY; -import static com.android.settings.deviceinfo.storage.CachedStorageValuesHelper.PHOTO_APPS_SIZE_KEY; import static com.android.settings.deviceinfo.storage.CachedStorageValuesHelper .SHARED_PREFERENCES_NAME; import static com.android.settings.deviceinfo.storage.CachedStorageValuesHelper.TIMESTAMP_KEY; import static com.android.settings.deviceinfo.storage.CachedStorageValuesHelper.TOTAL_BYTES_KEY; +import static com.android.settings.deviceinfo.storage.CachedStorageValuesHelper.TRASH_SIZE_KEY; import static com.android.settings.deviceinfo.storage.CachedStorageValuesHelper.USER_ID_KEY; -import static com.android.settings.deviceinfo.storage.CachedStorageValuesHelper.VIDEO_APPS_SIZE_KEY; +import static com.android.settings.deviceinfo.storage.CachedStorageValuesHelper.VIDEOS_SIZE_KEY; import static com.google.common.truth.Truth.assertThat; @@ -81,9 +83,9 @@ public class CachedStorageValuesHelperTest { mSharedPreferences .edit() .putLong(GAME_APPS_SIZE_KEY, 0) - .putLong(MUSIC_APPS_SIZE_KEY, 10) - .putLong(VIDEO_APPS_SIZE_KEY, 100) - .putLong(PHOTO_APPS_SIZE_KEY, 1000) + .putLong(AUDIO_SIZE_KEY, 10) + .putLong(VIDEOS_SIZE_KEY, 100) + .putLong(IMAGES_SIZE_KEY, 1000) .putLong(OTHER_APPS_SIZE_KEY, 10000) .putLong(CACHE_APPS_SIZE_KEY, 100000) .putLong(EXTERNAL_TOTAL_BYTES, 2) @@ -104,14 +106,16 @@ public class CachedStorageValuesHelperTest { } @Test - public void getCachedAppsStorageResult_cachedValuesAreLoaded() { + public void getCachedStorageResult_cachedValuesAreLoaded() { when(mMockClock.getCurrentTime()).thenReturn(10001L); mSharedPreferences .edit() .putLong(GAME_APPS_SIZE_KEY, 1) - .putLong(MUSIC_APPS_SIZE_KEY, 10) - .putLong(VIDEO_APPS_SIZE_KEY, 100) - .putLong(PHOTO_APPS_SIZE_KEY, 1000) + .putLong(AUDIO_SIZE_KEY, 10) + .putLong(VIDEOS_SIZE_KEY, 100) + .putLong(IMAGES_SIZE_KEY, 1000) + .putLong(DOCUMENTS_AND_OTHER_SIZE_KEY, 1001) + .putLong(TRASH_SIZE_KEY, 1002) .putLong(OTHER_APPS_SIZE_KEY, 10000) .putLong(CACHE_APPS_SIZE_KEY, 100000) .putLong(EXTERNAL_TOTAL_BYTES, 222222) @@ -125,15 +129,17 @@ public class CachedStorageValuesHelperTest { .putLong(TIMESTAMP_KEY, 10000L) .apply(); - final SparseArray result = - mCachedValuesHelper.getCachedAppsStorageResult(); + final SparseArray result = + mCachedValuesHelper.getCachedStorageResult(); - StorageAsyncLoader.AppsStorageResult primaryResult = result.get(0); + StorageAsyncLoader.StorageResult primaryResult = result.get(0); assertThat(primaryResult.gamesSize).isEqualTo(1L); - assertThat(primaryResult.musicAppsSize).isEqualTo(10L); - assertThat(primaryResult.videoAppsSize).isEqualTo(100L); - assertThat(primaryResult.photosAppsSize).isEqualTo(1000L); - assertThat(primaryResult.otherAppsSize).isEqualTo(10000L); + assertThat(primaryResult.audioSize).isEqualTo(10L); + assertThat(primaryResult.videosSize).isEqualTo(100L); + assertThat(primaryResult.imagesSize).isEqualTo(1000L); + assertThat(primaryResult.documentsAndOtherSize).isEqualTo(1001L); + assertThat(primaryResult.trashSize).isEqualTo(1002L); + assertThat(primaryResult.allAppsExceptGamesSize).isEqualTo(10000L); assertThat(primaryResult.cacheSize).isEqualTo(100000L); assertThat(primaryResult.externalStats.totalBytes).isEqualTo(222222L); assertThat(primaryResult.externalStats.audioBytes).isEqualTo(22L); @@ -148,9 +154,9 @@ public class CachedStorageValuesHelperTest { mSharedPreferences .edit() .putLong(GAME_APPS_SIZE_KEY, 0) - .putLong(MUSIC_APPS_SIZE_KEY, 10) - .putLong(VIDEO_APPS_SIZE_KEY, 100) - .putLong(PHOTO_APPS_SIZE_KEY, 1000) + .putLong(AUDIO_SIZE_KEY, 10) + .putLong(VIDEOS_SIZE_KEY, 100) + .putLong(IMAGES_SIZE_KEY, 1000) .putLong(OTHER_APPS_SIZE_KEY, 10000) .putLong(CACHE_APPS_SIZE_KEY, 100000) .putLong(EXTERNAL_TOTAL_BYTES, 2) @@ -169,14 +175,14 @@ public class CachedStorageValuesHelperTest { } @Test - public void getCachedAppsStorageResult_nullIfDataIsStale() { + public void getCachedStorageResult_nullIfDataIsStale() { when(mMockClock.getCurrentTime()).thenReturn(10000000L); mSharedPreferences .edit() .putLong(GAME_APPS_SIZE_KEY, 0) - .putLong(MUSIC_APPS_SIZE_KEY, 10) - .putLong(VIDEO_APPS_SIZE_KEY, 100) - .putLong(PHOTO_APPS_SIZE_KEY, 1000) + .putLong(AUDIO_SIZE_KEY, 10) + .putLong(VIDEOS_SIZE_KEY, 100) + .putLong(IMAGES_SIZE_KEY, 1000) .putLong(OTHER_APPS_SIZE_KEY, 10000) .putLong(CACHE_APPS_SIZE_KEY, 100000) .putLong(EXTERNAL_TOTAL_BYTES, 2) @@ -190,8 +196,8 @@ public class CachedStorageValuesHelperTest { .putLong(TIMESTAMP_KEY, 10000L) .apply(); - final SparseArray result = - mCachedValuesHelper.getCachedAppsStorageResult(); + final SparseArray result = + mCachedValuesHelper.getCachedStorageResult(); assertThat(result).isNull(); } @@ -201,9 +207,9 @@ public class CachedStorageValuesHelperTest { mSharedPreferences .edit() .putLong(GAME_APPS_SIZE_KEY, 0) - .putLong(MUSIC_APPS_SIZE_KEY, 10) - .putLong(VIDEO_APPS_SIZE_KEY, 100) - .putLong(PHOTO_APPS_SIZE_KEY, 1000) + .putLong(AUDIO_SIZE_KEY, 10) + .putLong(VIDEOS_SIZE_KEY, 100) + .putLong(IMAGES_SIZE_KEY, 1000) .putLong(OTHER_APPS_SIZE_KEY, 10000) .putLong(CACHE_APPS_SIZE_KEY, 100000) .putLong(EXTERNAL_TOTAL_BYTES, 2) @@ -222,14 +228,14 @@ public class CachedStorageValuesHelperTest { } @Test - public void getCachedAppsStorageResult_nullIfWrongUser() { + public void getCachedStorageResult_nullIfWrongUser() { when(mMockClock.getCurrentTime()).thenReturn(10001L); mSharedPreferences .edit() .putLong(GAME_APPS_SIZE_KEY, 0) - .putLong(MUSIC_APPS_SIZE_KEY, 10) - .putLong(VIDEO_APPS_SIZE_KEY, 100) - .putLong(PHOTO_APPS_SIZE_KEY, 1000) + .putLong(AUDIO_SIZE_KEY, 10) + .putLong(VIDEOS_SIZE_KEY, 100) + .putLong(IMAGES_SIZE_KEY, 1000) .putLong(OTHER_APPS_SIZE_KEY, 10000) .putLong(CACHE_APPS_SIZE_KEY, 100000) .putLong(EXTERNAL_TOTAL_BYTES, 2) @@ -243,8 +249,8 @@ public class CachedStorageValuesHelperTest { .putLong(TIMESTAMP_KEY, 10000L) .apply(); - final SparseArray result = - mCachedValuesHelper.getCachedAppsStorageResult(); + final SparseArray result = + mCachedValuesHelper.getCachedStorageResult(); assertThat(result).isNull(); } @@ -255,9 +261,9 @@ public class CachedStorageValuesHelperTest { } @Test - public void getCachedAppsStorageResult_nullIfEmpty() { - final SparseArray result = - mCachedValuesHelper.getCachedAppsStorageResult(); + public void getCachedStorageResult_nullIfEmpty() { + final SparseArray result = + mCachedValuesHelper.getCachedStorageResult(); assertThat(result).isNull(); } @@ -266,13 +272,13 @@ public class CachedStorageValuesHelperTest { when(mMockClock.getCurrentTime()).thenReturn(10000L); final StorageStatsSource.ExternalStorageStats externalStats = new StorageStatsSource.ExternalStorageStats(22222L, 2L, 20L, 200L, 2000L); - final StorageAsyncLoader.AppsStorageResult result = - new StorageAsyncLoader.AppsStorageResult(); + final StorageAsyncLoader.StorageResult result = + new StorageAsyncLoader.StorageResult(); result.gamesSize = 1L; - result.musicAppsSize = 10L; - result.videoAppsSize = 100L; - result.photosAppsSize = 1000L; - result.otherAppsSize = 10000L; + result.audioSize = 10L; + result.videosSize = 100L; + result.imagesSize = 1000L; + result.allAppsExceptGamesSize = 10000L; result.cacheSize = 100000L; result.externalStats = externalStats; final PrivateStorageInfo info = new PrivateStorageInfo(1000L, 6000L); @@ -280,9 +286,9 @@ public class CachedStorageValuesHelperTest { mCachedValuesHelper.cacheResult(info, result); assertThat(mSharedPreferences.getLong(GAME_APPS_SIZE_KEY, -1)).isEqualTo(1L); - assertThat(mSharedPreferences.getLong(MUSIC_APPS_SIZE_KEY, -1)).isEqualTo(10L); - assertThat(mSharedPreferences.getLong(VIDEO_APPS_SIZE_KEY, -1)).isEqualTo(100L); - assertThat(mSharedPreferences.getLong(PHOTO_APPS_SIZE_KEY, -1)).isEqualTo(1000L); + assertThat(mSharedPreferences.getLong(AUDIO_SIZE_KEY, -1)).isEqualTo(10L); + assertThat(mSharedPreferences.getLong(VIDEOS_SIZE_KEY, -1)).isEqualTo(100L); + assertThat(mSharedPreferences.getLong(IMAGES_SIZE_KEY, -1)).isEqualTo(1000L); assertThat(mSharedPreferences.getLong(OTHER_APPS_SIZE_KEY, -1)).isEqualTo(10000L); assertThat(mSharedPreferences.getLong(CACHE_APPS_SIZE_KEY, -1)).isEqualTo(100000L); assertThat(mSharedPreferences.getLong(EXTERNAL_TOTAL_BYTES, -1)).isEqualTo(22222L); diff --git a/tests/robotests/src/com/android/settings/deviceinfo/storage/SecondaryUserControllerTest.java b/tests/robotests/src/com/android/settings/deviceinfo/storage/SecondaryUserControllerTest.java index ec0f4d06b82..ad811dcceac 100644 --- a/tests/robotests/src/com/android/settings/deviceinfo/storage/SecondaryUserControllerTest.java +++ b/tests/robotests/src/com/android/settings/deviceinfo/storage/SecondaryUserControllerTest.java @@ -103,7 +103,7 @@ public class SecondaryUserControllerTest { verify(mGroup).addPreference(argumentCaptor.capture()); final Preference preference = argumentCaptor.getValue(); - assertThat(preference.getSummary()).isEqualTo("0.01 GB"); + assertThat(preference.getSummary()).isEqualTo("10 MB"); } @Test @@ -201,9 +201,9 @@ public class SecondaryUserControllerTest { mPrimaryUser.name = TEST_NAME; mPrimaryUser.id = 10; mController.displayPreference(mScreen); - final StorageAsyncLoader.AppsStorageResult userResult = - new StorageAsyncLoader.AppsStorageResult(); - final SparseArray result = new SparseArray<>(); + final StorageAsyncLoader.StorageResult userResult = + new StorageAsyncLoader.StorageResult(); + final SparseArray result = new SparseArray<>(); userResult.externalStats = new StorageStatsSource.ExternalStorageStats( MEGABYTE_IN_BYTES * 30, @@ -217,7 +217,7 @@ public class SecondaryUserControllerTest { verify(mGroup).addPreference(argumentCaptor.capture()); final Preference preference = argumentCaptor.getValue(); - assertThat(preference.getSummary()).isEqualTo("0.03 GB"); + assertThat(preference.getSummary()).isEqualTo("30 MB"); } @Test diff --git a/tests/robotests/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceControllerTest.java index 0a87d08f53f..d55975a3a84 100644 --- a/tests/robotests/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceControllerTest.java @@ -16,6 +16,8 @@ package com.android.settings.deviceinfo.storage; import static com.android.settings.applications.manageapplications.ManageApplications.EXTRA_WORK_ID; +import static com.android.settings.utils.FileSizeFormatter.GIGABYTE_IN_BYTES; +import static com.android.settings.utils.FileSizeFormatter.KILOBYTE_IN_BYTES; import static com.android.settings.utils.FileSizeFormatter.MEGABYTE_IN_BYTES; import static com.google.common.truth.Truth.assertThat; @@ -336,12 +338,14 @@ public class StorageItemPreferenceControllerTest { mController.displayPreference(mPreferenceScreen); mController.setUsedSize(MEGABYTE_IN_BYTES * 970); // There should 870MB attributed. - final StorageAsyncLoader.AppsStorageResult result = - new StorageAsyncLoader.AppsStorageResult(); + final StorageAsyncLoader.StorageResult result = new StorageAsyncLoader.StorageResult(); result.gamesSize = MEGABYTE_IN_BYTES * 80; - result.videoAppsSize = MEGABYTE_IN_BYTES * 160; - result.musicAppsSize = MEGABYTE_IN_BYTES * 40; - result.otherAppsSize = MEGABYTE_IN_BYTES * 90; + result.imagesSize = MEGABYTE_IN_BYTES * 350; + result.videosSize = GIGABYTE_IN_BYTES * 30; + result.audioSize = MEGABYTE_IN_BYTES * 40; + result.documentsAndOtherSize = MEGABYTE_IN_BYTES * 50; + result.trashSize = KILOBYTE_IN_BYTES * 100; + result.allAppsExceptGamesSize = MEGABYTE_IN_BYTES * 90; result.externalStats = new StorageStatsSource.ExternalStorageStats( MEGABYTE_IN_BYTES * 500, // total @@ -349,17 +353,18 @@ public class StorageItemPreferenceControllerTest { MEGABYTE_IN_BYTES * 150, // video MEGABYTE_IN_BYTES * 200, 0); // image - final SparseArray results = new SparseArray<>(); + final SparseArray results = new SparseArray<>(); results.put(0, result); mController.onLoadFinished(results, 0); - assertThat(mController.mImagesPreference.getSummary().toString()).isEqualTo("0.35 GB"); - assertThat(mController.mVideosPreference.getSummary().toString()).isEqualTo("0.16 GB"); - assertThat(mController.mAudioPreference.getSummary().toString()).isEqualTo("0.14 GB"); - assertThat(mController.mAppsPreference.getSummary().toString()).isEqualTo("0.09 GB"); - assertThat(mController.mGamesPreference.getSummary().toString()).isEqualTo("0.08 GB"); + assertThat(mController.mImagesPreference.getSummary().toString()).isEqualTo("350 MB"); + assertThat(mController.mVideosPreference.getSummary().toString()).isEqualTo("30 GB"); + assertThat(mController.mAudioPreference.getSummary().toString()).isEqualTo("40 MB"); + assertThat(mController.mAppsPreference.getSummary().toString()).isEqualTo("90 MB"); + assertThat(mController.mGamesPreference.getSummary().toString()).isEqualTo("80 MB"); assertThat(mController.mDocumentsAndOtherPreference.getSummary().toString()) - .isEqualTo("0.05 GB"); + .isEqualTo("50 MB"); + assertThat(mController.mTrashPreference.getSummary().toString()).isEqualTo("100 kB"); } @Test diff --git a/tests/unit/src/com/android/settings/deviceinfo/storage/StorageAsyncLoaderTest.java b/tests/unit/src/com/android/settings/deviceinfo/storage/StorageAsyncLoaderTest.java index a271e9b9e99..671da95aa17 100644 --- a/tests/unit/src/com/android/settings/deviceinfo/storage/StorageAsyncLoaderTest.java +++ b/tests/unit/src/com/android/settings/deviceinfo/storage/StorageAsyncLoaderTest.java @@ -101,22 +101,22 @@ public class StorageAsyncLoaderTest { addPackage(PACKAGE_NAME_1, 0, 1, 10, ApplicationInfo.CATEGORY_UNDEFINED); addPackage(PACKAGE_NAME_2, 0, 100, 1000, ApplicationInfo.CATEGORY_UNDEFINED); - SparseArray result = mLoader.loadInBackground(); + SparseArray result = mLoader.loadInBackground(); assertThat(result.size()).isEqualTo(1); assertThat(result.get(PRIMARY_USER_ID).gamesSize).isEqualTo(0L); - assertThat(result.get(PRIMARY_USER_ID).otherAppsSize).isEqualTo(1111L); + assertThat(result.get(PRIMARY_USER_ID).allAppsExceptGamesSize).isEqualTo(1111L); } @Test public void testGamesAreFiltered() throws Exception { addPackage(PACKAGE_NAME_1, 0, 1, 10, ApplicationInfo.CATEGORY_GAME); - SparseArray result = mLoader.loadInBackground(); + SparseArray result = mLoader.loadInBackground(); assertThat(result.size()).isEqualTo(1); assertThat(result.get(PRIMARY_USER_ID).gamesSize).isEqualTo(11L); - assertThat(result.get(PRIMARY_USER_ID).otherAppsSize).isEqualTo(0); + assertThat(result.get(PRIMARY_USER_ID).allAppsExceptGamesSize).isEqualTo(0); } @Test @@ -125,21 +125,21 @@ public class StorageAsyncLoaderTest { addPackage(PACKAGE_NAME_1, 0, 1, 10, ApplicationInfo.CATEGORY_UNDEFINED); info.flags = ApplicationInfo.FLAG_IS_GAME; - SparseArray result = mLoader.loadInBackground(); + SparseArray result = mLoader.loadInBackground(); assertThat(result.size()).isEqualTo(1); assertThat(result.get(PRIMARY_USER_ID).gamesSize).isEqualTo(11L); - assertThat(result.get(PRIMARY_USER_ID).otherAppsSize).isEqualTo(0); + assertThat(result.get(PRIMARY_USER_ID).allAppsExceptGamesSize).isEqualTo(0); } @Test public void testCacheIsNotIgnored() throws Exception { addPackage(PACKAGE_NAME_1, 100, 1, 10, ApplicationInfo.CATEGORY_UNDEFINED); - SparseArray result = mLoader.loadInBackground(); + SparseArray result = mLoader.loadInBackground(); assertThat(result.size()).isEqualTo(1); - assertThat(result.get(PRIMARY_USER_ID).otherAppsSize).isEqualTo(111L); + assertThat(result.get(PRIMARY_USER_ID).allAppsExceptGamesSize).isEqualTo(111L); } @Test @@ -152,7 +152,7 @@ public class StorageAsyncLoaderTest { when(mSource.getExternalStorageStats(anyString(), eq(new UserHandle(SECONDARY_USER_ID)))) .thenReturn(new StorageStatsSource.ExternalStorageStats(10, 3, 3, 4, 0)); - SparseArray result = mLoader.loadInBackground(); + SparseArray result = mLoader.loadInBackground(); assertThat(result.size()).isEqualTo(2); assertThat(result.get(PRIMARY_USER_ID).externalStats.totalBytes).isEqualTo(9L); @@ -165,21 +165,10 @@ public class StorageAsyncLoaderTest { addPackage(PACKAGE_NAME_1, 100, 1, 10, ApplicationInfo.CATEGORY_UNDEFINED); systemApp.flags = ApplicationInfo.FLAG_SYSTEM & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP; - SparseArray result = mLoader.loadInBackground(); + SparseArray result = mLoader.loadInBackground(); assertThat(result.size()).isEqualTo(1); - assertThat(result.get(PRIMARY_USER_ID).otherAppsSize).isEqualTo(111L); - } - - @Test - public void testVideoAppsAreFiltered() throws Exception { - addPackage(PACKAGE_NAME_1, 0, 1, 10, ApplicationInfo.CATEGORY_VIDEO); - - SparseArray result = mLoader.loadInBackground(); - - assertThat(result.size()).isEqualTo(1); - // Code size is not included for file based video category. - assertThat(result.get(PRIMARY_USER_ID).videoAppsSize).isEqualTo(10L); + assertThat(result.get(PRIMARY_USER_ID).allAppsExceptGamesSize).isEqualTo(111L); } @Test @@ -191,44 +180,20 @@ public class StorageAsyncLoaderTest { when(mSource.getStatsForPackage(anyString(), anyString(), any(UserHandle.class))) .thenThrow(new NameNotFoundException()); - SparseArray result = mLoader.loadInBackground(); + SparseArray result = mLoader.loadInBackground(); // Should not crash. } - @Test - public void testPackageIsNotDoubleCounted() throws Exception { - UserInfo info = new UserInfo(); - info.id = SECONDARY_USER_ID; - mUsers.add(info); - when(mSource.getExternalStorageStats(anyString(), eq(UserHandle.SYSTEM))) - .thenReturn(new StorageStatsSource.ExternalStorageStats(9, 2, 3, 4, 0)); - when(mSource.getExternalStorageStats(anyString(), eq(new UserHandle(SECONDARY_USER_ID)))) - .thenReturn(new StorageStatsSource.ExternalStorageStats(10, 3, 3, 4, 0)); - addPackage(PACKAGE_NAME_1, 0, 1, 10, ApplicationInfo.CATEGORY_VIDEO); - ArrayList secondaryUserApps = new ArrayList<>(); - ApplicationInfo appInfo = new ApplicationInfo(); - appInfo.packageName = PACKAGE_NAME_1; - appInfo.category = ApplicationInfo.CATEGORY_VIDEO; - secondaryUserApps.add(appInfo); - - SparseArray result = mLoader.loadInBackground(); - - assertThat(result.size()).isEqualTo(2); - // Code size is not included for file based video category. - assertThat(result.get(PRIMARY_USER_ID).videoAppsSize).isEqualTo(10L); - // No code size for the second user. - assertThat(result.get(SECONDARY_USER_ID).videoAppsSize).isEqualTo(10L); - } - @Test public void testCacheOveragesAreCountedAsFree() throws Exception { addPackage(PACKAGE_NAME_1, DEFAULT_QUOTA + 100, 1, 10, ApplicationInfo.CATEGORY_UNDEFINED); - SparseArray result = mLoader.loadInBackground(); + SparseArray result = mLoader.loadInBackground(); assertThat(result.size()).isEqualTo(1); - assertThat(result.get(PRIMARY_USER_ID).otherAppsSize).isEqualTo(DEFAULT_QUOTA + 11); + assertThat(result.get(PRIMARY_USER_ID).allAppsExceptGamesSize) + .isEqualTo(DEFAULT_QUOTA + 11); } @Test @@ -237,10 +202,10 @@ public class StorageAsyncLoaderTest { addPackage(PACKAGE_NAME_2, 0, 1, 10, ApplicationInfo.CATEGORY_VIDEO); addPackage(PACKAGE_NAME_3, 0, 1, 10, ApplicationInfo.CATEGORY_AUDIO); - SparseArray result = mLoader.loadInBackground(); + SparseArray result = mLoader.loadInBackground(); assertThat(result.size()).isEqualTo(1); - assertThat(result.get(PRIMARY_USER_ID).otherAppsSize).isEqualTo(33L); + assertThat(result.get(PRIMARY_USER_ID).allAppsExceptGamesSize).isEqualTo(33L); } private ApplicationInfo addPackage(String packageName, long cacheSize, long codeSize, From e81b8275a8ec480740b446264b6529eca84a3f18 Mon Sep 17 00:00:00 2001 From: Julia Reynolds Date: Tue, 25 May 2021 11:50:21 -0400 Subject: [PATCH 10/23] Consolidate app notification setting prefs Test: manual Fixes: 189201867 Change-Id: If5cc03e0bd2d4273cd842e097b99b15d1178f3dc --- res/values/strings.xml | 6 + res/xml/configure_notification_settings.xml | 83 ++-- .../ConfigureNotificationSettings.java | 4 - ...centNotifyingAppsPreferenceController.java | 301 -------------- ...NotifyingAppsPreferenceControllerTest.java | 389 ------------------ 5 files changed, 39 insertions(+), 744 deletions(-) delete mode 100644 src/com/android/settings/notification/RecentNotifyingAppsPreferenceController.java delete mode 100644 tests/robotests/src/com/android/settings/notification/RecentNotifyingAppsPreferenceControllerTest.java diff --git a/res/values/strings.xml b/res/values/strings.xml index 4dc306093ce..424f7a20a9c 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -8747,6 +8747,12 @@ See all from last 7 days + + General + + + App settings + General diff --git a/res/xml/configure_notification_settings.xml b/res/xml/configure_notification_settings.xml index ab22f73dd8f..dad5e0e5453 100644 --- a/res/xml/configure_notification_settings.xml +++ b/res/xml/configure_notification_settings.xml @@ -18,6 +18,39 @@ xmlns:settings="http://schemas.android.com/apk/res-auto" android:title="@string/configure_notification_settings"> + + + + + + + + + + + @@ -39,59 +72,9 @@ /> - - - - - - - - - - - - - - - - buildPreferenceControllers(Context context, Application app, Fragment host) { final List controllers = new ArrayList<>(); - controllers.add(new RecentNotifyingAppsPreferenceController( - context, new NotificationBackend(), IUsageStatsManager.Stub.asInterface( - ServiceManager.getService(Context.USAGE_STATS_SERVICE)), - context.getSystemService(UserManager.class), app, host)); controllers.add(new ShowOnLockScreenNotificationPreferenceController( context, KEY_LOCKSCREEN)); controllers.add(new NotificationRingtonePreferenceController(context) { diff --git a/src/com/android/settings/notification/RecentNotifyingAppsPreferenceController.java b/src/com/android/settings/notification/RecentNotifyingAppsPreferenceController.java deleted file mode 100644 index 8e0807db89e..00000000000 --- a/src/com/android/settings/notification/RecentNotifyingAppsPreferenceController.java +++ /dev/null @@ -1,301 +0,0 @@ -/* - * Copyright (C) 2018 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.notification; - -import android.app.Application; -import android.app.settings.SettingsEnums; -import android.app.usage.IUsageStatsManager; -import android.app.usage.UsageEvents; -import android.content.Context; -import android.content.pm.PackageManager; -import android.os.Bundle; -import android.os.RemoteException; -import android.os.UserHandle; -import android.os.UserManager; -import android.service.notification.NotifyingApp; -import android.text.TextUtils; -import android.util.ArrayMap; -import android.util.IconDrawableFactory; -import android.util.Slog; - -import androidx.annotation.VisibleForTesting; -import androidx.fragment.app.Fragment; -import androidx.preference.Preference; -import androidx.preference.PreferenceCategory; -import androidx.preference.PreferenceScreen; - -import com.android.settings.R; -import com.android.settings.Utils; -import com.android.settings.applications.AppInfoBase; -import com.android.settings.core.PreferenceControllerMixin; -import com.android.settings.core.SubSettingLauncher; -import com.android.settings.notification.app.AppNotificationSettings; -import com.android.settings.widget.PrimarySwitchPreference; -import com.android.settingslib.applications.ApplicationsState; -import com.android.settingslib.core.AbstractPreferenceController; -import com.android.settingslib.utils.StringUtil; -import com.android.settingslib.utils.ThreadUtils; -import com.android.settingslib.widget.TwoTargetPreference; - -import java.util.ArrayList; -import java.util.Calendar; -import java.util.Collections; -import java.util.List; - -/** - * This controller displays a list of recently used apps and a "See all" button. If there is - * no recently used app, "See all" will be displayed as "Notifications". - */ -public class RecentNotifyingAppsPreferenceController extends AbstractPreferenceController - implements PreferenceControllerMixin { - - private static final String TAG = "RecentNotisCtrl"; - private static final String KEY_PREF_CATEGORY = "recent_notifications_category"; - - @VisibleForTesting - static final String KEY_SEE_ALL = "all_notifications"; - static final String KEY_PLACEHOLDER = "app"; - private static final int SHOW_RECENT_APP_COUNT = 3; - private static final int DAYS = 3; - - private final Fragment mHost; - private final PackageManager mPm; - private final NotificationBackend mNotificationBackend; - private IUsageStatsManager mUsageStatsManager; - private final IconDrawableFactory mIconDrawableFactory; - - private Calendar mCal; - List mApps; - private final ApplicationsState mApplicationsState; - - private PreferenceCategory mCategory; - private Preference mSeeAllPref; - protected List mUserIds; - - public RecentNotifyingAppsPreferenceController(Context context, NotificationBackend backend, - IUsageStatsManager usageStatsManager, UserManager userManager, - Application app, Fragment host) { - this(context, backend, usageStatsManager, userManager, - app == null ? null : ApplicationsState.getInstance(app), host); - } - - @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE) - RecentNotifyingAppsPreferenceController(Context context, NotificationBackend backend, - IUsageStatsManager usageStatsManager, UserManager userManager, - ApplicationsState appState, Fragment host) { - super(context); - mIconDrawableFactory = IconDrawableFactory.newInstance(context); - mPm = context.getPackageManager(); - mHost = host; - mApplicationsState = appState; - mNotificationBackend = backend; - mUsageStatsManager = usageStatsManager; - mUserIds = new ArrayList<>(); - mUserIds.add(mContext.getUserId()); - int workUserId = Utils.getManagedProfileId(userManager, mContext.getUserId()); - if (workUserId != UserHandle.USER_NULL) { - mUserIds.add(workUserId); - } - } - - @Override - public boolean isAvailable() { - return mApplicationsState != null; - } - - @Override - public String getPreferenceKey() { - return KEY_PREF_CATEGORY; - } - - @Override - public void updateNonIndexableKeys(List keys) { - PreferenceControllerMixin.super.updateNonIndexableKeys(keys); - // Don't index category name into search. It's not actionable. - keys.add(KEY_PREF_CATEGORY); - } - - @Override - public void displayPreference(PreferenceScreen screen) { - mCategory = screen.findPreference(getPreferenceKey()); - mSeeAllPref = screen.findPreference(KEY_SEE_ALL); - super.displayPreference(screen); - refreshUi(mCategory.getContext()); - } - - @Override - public void updateState(Preference preference) { - super.updateState(preference); - refreshUi(mCategory.getContext()); - mSeeAllPref.setTitle(mContext.getString(R.string.recent_notifications_see_all_title)); - } - - @VisibleForTesting - void refreshUi(Context prefContext) { - for (int i = 1; i <= SHOW_RECENT_APP_COUNT; i++) { - PrimarySwitchPreference app = mCategory.findPreference(KEY_PLACEHOLDER + i); - if (app != null) { - app.setChecked(true); - } - } - ThreadUtils.postOnBackgroundThread(() -> { - reloadData(); - final List recentApps = getDisplayableRecentAppList(); - ThreadUtils.postOnMainThread(() -> { - if (recentApps != null && !recentApps.isEmpty()) { - displayRecentApps(prefContext, recentApps); - } else { - displayOnlyAllAppsLink(); - } - }); - }); - } - - @VisibleForTesting - void reloadData() { - mApps = new ArrayList<>(); - mCal = Calendar.getInstance(); - mCal.add(Calendar.DAY_OF_YEAR, -DAYS); - for (int userId : mUserIds) { - UsageEvents events = null; - try { - events = mUsageStatsManager.queryEventsForUser(mCal.getTimeInMillis(), - System.currentTimeMillis(), userId, mContext.getPackageName()); - } catch (RemoteException e) { - e.printStackTrace(); - } - if (events != null) { - ArrayMap aggregatedStats = new ArrayMap<>(); - - UsageEvents.Event event = new UsageEvents.Event(); - while (events.hasNextEvent()) { - events.getNextEvent(event); - - if (event.getEventType() == UsageEvents.Event.NOTIFICATION_INTERRUPTION) { - NotifyingApp app = - aggregatedStats.get(getKey(userId, event.getPackageName())); - if (app == null) { - app = new NotifyingApp(); - aggregatedStats.put(getKey(userId, event.getPackageName()), app); - app.setPackage(event.getPackageName()); - app.setUserId(userId); - } - if (event.getTimeStamp() > app.getLastNotified()) { - app.setLastNotified(event.getTimeStamp()); - } - } - - } - - mApps.addAll(aggregatedStats.values()); - } - } - } - - private static String getKey(int userId, String pkg) { - return userId + "|" + pkg; - } - - private void displayOnlyAllAppsLink() { - mCategory.setTitle(null); - mSeeAllPref.setTitle(R.string.notifications_title); - mSeeAllPref.setIcon(null); - int prefCount = mCategory.getPreferenceCount(); - for (int i = prefCount - 1; i >= 0; i--) { - final Preference pref = mCategory.getPreference(i); - if (!TextUtils.equals(pref.getKey(), KEY_SEE_ALL)) { - mCategory.removePreference(pref); - } - } - } - - private void displayRecentApps(Context prefContext, List recentApps) { - mCategory.setTitle(R.string.recent_notifications); - mSeeAllPref.setSummary(null); - mSeeAllPref.setIcon(R.drawable.ic_chevron_right_24dp); - - int keyIndex = 1; - final int recentAppsCount = recentApps.size(); - for (int i = 0; i < recentAppsCount; i++, keyIndex++) { - final NotifyingApp app = recentApps.get(i); - // Bind recent apps to existing prefs if possible, or create a new pref. - final String pkgName = app.getPackage(); - final ApplicationsState.AppEntry appEntry = - mApplicationsState.getEntry(app.getPackage(), app.getUserId()); - if (appEntry == null || appEntry.label == null) { - continue; - } - - PrimarySwitchPreference pref = mCategory.findPreference(KEY_PLACEHOLDER + keyIndex); - pref.setTitle(appEntry.label); - pref.setIcon(mIconDrawableFactory.getBadgedIcon(appEntry.info)); - pref.setIconSize(TwoTargetPreference.ICON_SIZE_SMALL); - pref.setSummary(StringUtil.formatRelativeTime(mContext, - System.currentTimeMillis() - app.getLastNotified(), true)); - Bundle args = new Bundle(); - args.putString(AppInfoBase.ARG_PACKAGE_NAME, pkgName); - args.putInt(AppInfoBase.ARG_PACKAGE_UID, appEntry.info.uid); - pref.setOnPreferenceClickListener(preference -> { - new SubSettingLauncher(mHost.getActivity()) - .setDestination(AppNotificationSettings.class.getName()) - .setTitleRes(R.string.notifications_title) - .setArguments(args) - .setUserHandle(new UserHandle(UserHandle.getUserId(appEntry.info.uid))) - .setSourceMetricsCategory( - SettingsEnums.MANAGE_APPLICATIONS_NOTIFICATIONS) - .launch(); - return true; - }); - pref.setSwitchEnabled(mNotificationBackend.isBlockable(mContext, appEntry.info)); - pref.setOnPreferenceChangeListener((preference, newValue) -> { - mNotificationBackend.setNotificationsEnabledForPackage( - pkgName, appEntry.info.uid, (Boolean) newValue); - return true; - }); - pref.setChecked( - !mNotificationBackend.getNotificationsBanned(pkgName, appEntry.info.uid)); - - } - // If there are less than SHOW_RECENT_APP_COUNT recent apps, remove placeholders - for (int i = keyIndex; i <= SHOW_RECENT_APP_COUNT; i++) { - mCategory.removePreferenceRecursively(KEY_PLACEHOLDER + i); - } - } - - private List getDisplayableRecentAppList() { - Collections.sort(mApps); - List displayableApps = new ArrayList<>(SHOW_RECENT_APP_COUNT); - int count = 0; - for (NotifyingApp app : mApps) { - try { - final ApplicationsState.AppEntry appEntry = mApplicationsState.getEntry( - app.getPackage(), app.getUserId()); - if (appEntry == null) { - continue; - } - displayableApps.add(app); - count++; - if (count >= SHOW_RECENT_APP_COUNT) { - break; - } - } catch (Exception e) { - Slog.e(TAG, "Failed to find app " + app.getPackage() + "/" + app.getUserId(), e); - } - } - return displayableApps; - } -} diff --git a/tests/robotests/src/com/android/settings/notification/RecentNotifyingAppsPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/RecentNotifyingAppsPreferenceControllerTest.java deleted file mode 100644 index f6eb93b7f29..00000000000 --- a/tests/robotests/src/com/android/settings/notification/RecentNotifyingAppsPreferenceControllerTest.java +++ /dev/null @@ -1,389 +0,0 @@ -/* - * Copyright (C) 2018 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.notification; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.argThat; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.doNothing; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import android.app.usage.IUsageStatsManager; -import android.app.usage.UsageEvents; -import android.app.usage.UsageEvents.Event; -import android.content.Context; -import android.content.Intent; -import android.content.pm.ApplicationInfo; -import android.content.pm.PackageManager; -import android.content.pm.ResolveInfo; -import android.os.Parcel; -import android.os.UserHandle; -import android.os.UserManager; -import android.service.notification.NotifyingApp; -import android.text.TextUtils; - -import com.android.settings.R; -import com.android.settings.widget.PrimarySwitchPreference; -import com.android.settingslib.applications.AppUtils; -import com.android.settingslib.applications.ApplicationsState; -import com.android.settingslib.applications.instantapps.InstantAppDataProvider; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; -import org.mockito.ArgumentMatcher; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -import org.robolectric.annotation.Config; -import org.robolectric.util.ReflectionHelpers; - -import java.util.ArrayList; -import java.util.List; - -import androidx.fragment.app.Fragment; -import androidx.fragment.app.FragmentActivity; -import androidx.preference.Preference; -import androidx.preference.PreferenceCategory; -import androidx.preference.PreferenceScreen; - -@RunWith(RobolectricTestRunner.class) -public class RecentNotifyingAppsPreferenceControllerTest { - - @Mock - private PreferenceScreen mScreen; - @Mock - private PreferenceCategory mCategory; - private PrimarySwitchPreference mApp1; - private PrimarySwitchPreference mApp2; - private PrimarySwitchPreference mApp3; - @Mock - private Preference mSeeAllPref; - @Mock - private UserManager mUserManager; - @Mock - private ApplicationsState mAppState; - @Mock - private PackageManager mPackageManager; - @Mock - private ApplicationsState.AppEntry mAppEntry; - @Mock - private ApplicationInfo mApplicationInfo; - @Mock - private NotificationBackend mBackend; - @Mock - private Fragment mHost; - @Mock - private FragmentActivity mActivity; - @Mock - private IUsageStatsManager mIUsageStatsManager; - - private Context mContext; - private RecentNotifyingAppsPreferenceController mController; - - @Before - public void setUp() { - MockitoAnnotations.initMocks(this); - mContext = spy(RuntimeEnvironment.application); - doReturn(mUserManager).when(mContext).getSystemService(Context.USER_SERVICE); - doReturn(mPackageManager).when(mContext).getPackageManager(); - when(mUserManager.getProfileIdsWithDisabled(0)).thenReturn(new int[] {0}); - - mController = new RecentNotifyingAppsPreferenceController( - mContext, mBackend, mIUsageStatsManager, mUserManager, mAppState, mHost); - when(mScreen.findPreference(anyString())).thenReturn(mCategory); - mApp1 = new PrimarySwitchPreference(mContext); - mApp1.setKey("app1"); - mApp2 = new PrimarySwitchPreference(mContext); - mApp2.setKey("app2"); - mApp3 = new PrimarySwitchPreference(mContext); - mApp3.setKey("app3"); - when(mCategory.findPreference("app1")).thenReturn(mApp1); - when(mCategory.findPreference("app2")).thenReturn(mApp2); - when(mCategory.findPreference("app3")).thenReturn(mApp3); - - when(mScreen.findPreference(RecentNotifyingAppsPreferenceController.KEY_SEE_ALL)) - .thenReturn(mSeeAllPref); - when(mCategory.getContext()).thenReturn(mContext); - when(mHost.getActivity()).thenReturn(mActivity); - } - - @Test - public void isAlwaysAvailable() { - assertThat(mController.isAvailable()).isTrue(); - } - - @Test - public void onDisplayAndUpdateState_shouldRefreshUi() { - mController = spy(new RecentNotifyingAppsPreferenceController( - mContext, null, mIUsageStatsManager, mUserManager, (ApplicationsState) null, null)); - - doNothing().when(mController).refreshUi(mContext); - - mController.displayPreference(mScreen); - mController.updateState(mCategory); - - verify(mController, times(2)).refreshUi(mContext); - } - - @Test - @Config(qualifiers = "mcc999") - public void display_shouldNotShowRecents_showAppInfoPreference() { - mController.displayPreference(mScreen); - - verify(mCategory, never()).addPreference(any(Preference.class)); - verify(mCategory).setTitle(null); - verify(mSeeAllPref).setTitle(R.string.notifications_title); - verify(mSeeAllPref).setIcon(null); - } - - @Test - public void display_showRecents() throws Exception { - List events = new ArrayList<>(); - Event app = new Event(); - app.mEventType = Event.NOTIFICATION_INTERRUPTION; - app.mPackage = "a"; - app.mTimeStamp = System.currentTimeMillis(); - events.add(app); - Event app1 = new Event(); - app1.mEventType = Event.NOTIFICATION_INTERRUPTION; - app1.mPackage = "com.android.settings"; - app1.mTimeStamp = System.currentTimeMillis(); - events.add(app1); - Event app2 = new Event(); - app2.mEventType = Event.NOTIFICATION_INTERRUPTION; - app2.mPackage = "pkg.class2"; - app2.mTimeStamp = System.currentTimeMillis() - 1000; - events.add(app2); - ApplicationsState.AppEntry app1Entry = mock(ApplicationsState.AppEntry.class); - ApplicationsState.AppEntry app2Entry = mock(ApplicationsState.AppEntry.class); - app1Entry.info = mApplicationInfo; - app1Entry.label = "app 1"; - app2Entry.info = mApplicationInfo; - app2Entry.label = "app 2"; - - // app1, app2 are valid apps. app3 is invalid. - when(mAppState.getEntry(app.getPackageName(), UserHandle.myUserId())) - .thenReturn(app1Entry); - when(mAppState.getEntry(app1.getPackageName(), UserHandle.myUserId())) - .thenReturn(app2Entry); - when(mAppState.getEntry(app2.getPackageName(), UserHandle.myUserId())) - .thenReturn(null); - when(mPackageManager.resolveActivity(any(Intent.class), anyInt())).thenReturn( - new ResolveInfo()); - - UsageEvents usageEvents = getUsageEvents( - new String[] {app.getPackageName(), app1.getPackageName(), app2.getPackageName()}, - events); - when(mIUsageStatsManager.queryEventsForUser(anyLong(), anyLong(), anyInt(), anyString())) - .thenReturn(usageEvents); - - mAppEntry.info = mApplicationInfo; - - mController.displayPreference(mScreen); - - verify(mCategory).setTitle(R.string.recent_notifications); - // Only add app1 & app2. app3 skipped because it's invalid app. - assertThat(mApp1.getTitle()).isEqualTo(app1Entry.label); - assertThat(mApp2.getTitle()).isEqualTo(app2Entry.label); - - verify(mCategory).removePreferenceRecursively(mApp3.getKey()); - - verify(mSeeAllPref).setSummary(null); - verify(mSeeAllPref).setIcon(R.drawable.ic_chevron_right_24dp); - } - - @Test - public void display_noCrashIfLessThan3() throws Exception { - List events = new ArrayList<>(); - Event app = new Event(); - app.mEventType = Event.NOTIFICATION_INTERRUPTION; - app.mPackage = "a"; - app.mTimeStamp = System.currentTimeMillis(); - events.add(app); - ApplicationsState.AppEntry app1Entry = mock(ApplicationsState.AppEntry.class); - app1Entry.info = mApplicationInfo; - app1Entry.label = "app 1"; - - when(mAppState.getEntry(app.getPackageName(), UserHandle.myUserId())) - .thenReturn(app1Entry); - when(mPackageManager.resolveActivity(any(Intent.class), anyInt())).thenReturn( - new ResolveInfo()); - - UsageEvents usageEvents = getUsageEvents( - new String[] {app.getPackageName()}, - events); - when(mIUsageStatsManager.queryEventsForUser(anyLong(), anyLong(), anyInt(), anyString())) - .thenReturn(usageEvents); - - mAppEntry.info = mApplicationInfo; - - mController.displayPreference(mScreen); - - verify(mCategory).setTitle(R.string.recent_notifications); - // Only add app1 & app2. app3 skipped because it's invalid app. - assertThat(mApp1.getTitle()).isEqualTo(app1Entry.label); - - verify(mCategory).removePreferenceRecursively("app2"); - - mController.refreshUi(mContext); - } - - @Test - public void display_showRecentsWithInstantApp() throws Exception { - List events = new ArrayList<>(); - Event app = new Event(); - app.mEventType = Event.NOTIFICATION_INTERRUPTION; - app.mPackage = "com.foo.bar"; - app.mTimeStamp = System.currentTimeMillis(); - events.add(app); - Event app1 = new Event(); - app1.mEventType = Event.NOTIFICATION_INTERRUPTION; - app1.mPackage = "com.foo.barinstant"; - app1.mTimeStamp = System.currentTimeMillis() - 200; - events.add(app1); - UsageEvents usageEvents = getUsageEvents( - new String[] {"com.foo.bar", "com.foo.barinstant"}, events); - when(mIUsageStatsManager.queryEventsForUser(anyLong(), anyLong(), anyInt(), anyString())) - .thenReturn(usageEvents); - - ApplicationsState.AppEntry appEntry = mock(ApplicationsState.AppEntry.class); - ApplicationsState.AppEntry app1Entry = mock(ApplicationsState.AppEntry.class); - appEntry.info = mApplicationInfo; - appEntry.label = "app 1"; - app1Entry.info = mApplicationInfo; - app1Entry.label = "app 2"; - - when(mAppState.getEntry( - app.getPackageName(), UserHandle.myUserId())).thenReturn(appEntry); - when(mAppState.getEntry( - app1.getPackageName(), UserHandle.myUserId())).thenReturn(app1Entry); - - // Only the regular app app1 should have its intent resolve. - when(mPackageManager.resolveActivity(argThat(intentMatcher(app.getPackageName())), - anyInt())).thenReturn(new ResolveInfo()); - - // Make sure app2 is considered an instant app. - ReflectionHelpers.setStaticField(AppUtils.class, "sInstantAppDataProvider", - (InstantAppDataProvider) (ApplicationInfo info) -> { - if (info == app1Entry.info) { - return true; - } else { - return false; - } - }); - - mController.displayPreference(mScreen); - - assertThat(mApp1.getTitle()).isEqualTo(appEntry.label); - assertThat(mApp1.getSummary()).isEqualTo("Just now"); - assertThat(mApp2.getTitle()).isEqualTo(app1Entry.label); - - verify(mCategory).removePreferenceRecursively(mApp3.getKey()); - } - - @Test - public void reloadData() throws Exception { - when(mUserManager.getProfileIdsWithDisabled(0)).thenReturn(new int[] {0, 10}); - - mController = new RecentNotifyingAppsPreferenceController( - mContext, mBackend, mIUsageStatsManager, mUserManager, mAppState, mHost); - - List events = new ArrayList<>(); - Event app = new Event(); - app.mEventType = Event.NOTIFICATION_INTERRUPTION; - app.mPackage = "b"; - app.mTimeStamp = 1; - events.add(app); - Event app1 = new Event(); - app1.mEventType = Event.MAX_EVENT_TYPE; - app1.mPackage = "com.foo.bar"; - app1.mTimeStamp = 10; - events.add(app1); - UsageEvents usageEvents = getUsageEvents( - new String[] {"b", "com.foo.bar"}, events); - when(mIUsageStatsManager.queryEventsForUser(anyLong(), anyLong(), eq(0), anyString())) - .thenReturn(usageEvents); - - List events10 = new ArrayList<>(); - Event app10 = new Event(); - app10.mEventType = Event.NOTIFICATION_INTERRUPTION; - app10.mPackage = "a"; - app10.mTimeStamp = 2; - events10.add(app10); - Event app10a = new Event(); - app10a.mEventType = Event.NOTIFICATION_INTERRUPTION; - app10a.mPackage = "a"; - app10a.mTimeStamp = 20; - events10.add(app10a); - UsageEvents usageEvents10 = getUsageEvents( - new String[] {"a"}, events10); - when(mIUsageStatsManager.queryEventsForUser(anyLong(), anyLong(), eq(10), anyString())) - .thenReturn(usageEvents10); - - mController.reloadData(); - - assertThat(mController.mApps.size()).isEqualTo(2); - boolean foundPkg0 = false; - boolean foundPkg10 = false; - for (NotifyingApp notifyingApp : mController.mApps) { - if (notifyingApp.getLastNotified() == 20 - && notifyingApp.getPackage().equals("a") - && notifyingApp.getUserId() == 10) { - foundPkg10 = true; - } - if (notifyingApp.getLastNotified() == 1 - && notifyingApp.getPackage().equals("b") - && notifyingApp.getUserId() == 0) { - foundPkg0 = true; - } - } - assertThat(foundPkg0).isTrue(); - assertThat(foundPkg10).isTrue(); - } - - private static ArgumentMatcher summaryMatches(String expected) { - return preference -> TextUtils.equals(expected, preference.getSummary()); - } - - // Used for matching an intent with a specific package name. - private static ArgumentMatcher intentMatcher(String packageName) { - return intent -> packageName.equals(intent.getPackage()); - } - - private UsageEvents getUsageEvents(String[] pkgs, List events) { - UsageEvents usageEvents = new UsageEvents(events, pkgs); - Parcel parcel = Parcel.obtain(); - parcel.setDataPosition(0); - usageEvents.writeToParcel(parcel, 0); - parcel.setDataPosition(0); - return UsageEvents.CREATOR.createFromParcel(parcel); - } -} From 0465239d4aa91359b0ae988ae936e39860fd5af8 Mon Sep 17 00:00:00 2001 From: Abel Tesfaye Date: Fri, 21 May 2021 22:39:51 +0000 Subject: [PATCH 11/23] Update battery saver string and make r lowercase in Auto rotate Bug: 188843414 Test: none Change-Id: I449fbe3d67eafb9ccdcef7719abdeb31eeb69b3f --- res/values/strings.xml | 7 +++++-- .../display/SmartAutoRotateBatterySaverController.java | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/res/values/strings.xml b/res/values/strings.xml index 8141192b34e..cedbd74d0e9 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -98,11 +98,11 @@ Make larger - Use Auto-Rotate + Use Auto-rotate - Face Detection uses the front-facing camera to improve Auto-Rotate accuracy. Images are never stored or sent to Google.<br><br> + Face Detection uses the front-facing camera to improve Auto-rotate accuracy. Images are never stored or sent to Google.<br><br> <a href="http://support.google.com/mobile?p=telephony_rtt">Learn more</a> Sample text @@ -11393,6 +11393,9 @@ Temporarily disabled due to Battery Saver + + Turn off battery saver + Temporarily turned on due to Battery Saver diff --git a/src/com/android/settings/display/SmartAutoRotateBatterySaverController.java b/src/com/android/settings/display/SmartAutoRotateBatterySaverController.java index 9bb2196acbd..d135d4b06a4 100644 --- a/src/com/android/settings/display/SmartAutoRotateBatterySaverController.java +++ b/src/com/android/settings/display/SmartAutoRotateBatterySaverController.java @@ -70,7 +70,7 @@ public class SmartAutoRotateBatterySaverController extends BasePreferenceControl super.displayPreference(screen); mPreference = screen.findPreference(getPreferenceKey()); ((BannerMessagePreference) mPreference) - .setPositiveButtonText(R.string.disable_text) + .setPositiveButtonText(R.string.ambient_camera_battery_saver_off) .setPositiveButtonOnClickListener(v -> { mPowerManager.setPowerSaveModeEnabled(false); }); From 6bf1c3675dfe436bff1a41e68b2e2edd206e373e Mon Sep 17 00:00:00 2001 From: Yanting Yang Date: Wed, 26 May 2021 05:38:22 +0800 Subject: [PATCH 12/23] Correct breadcrumbs of Wallpaper & style Remove the sitemap connection between Display and Wallpaper & style, since we already moved the Wallpaper & style to the homepage. Bug: 182708819 Test: robotests & visual Change-Id: Ia069be91177d8fef56248b5343c41a13ef8267a2 --- .../android/settings/search/CustomSiteMapRegistry.java | 4 ---- .../settings/search/CustomSiteMapRegistryTest.java | 9 --------- 2 files changed, 13 deletions(-) diff --git a/src/com/android/settings/search/CustomSiteMapRegistry.java b/src/com/android/settings/search/CustomSiteMapRegistry.java index 84488469807..ab33fa256d1 100644 --- a/src/com/android/settings/search/CustomSiteMapRegistry.java +++ b/src/com/android/settings/search/CustomSiteMapRegistry.java @@ -18,7 +18,6 @@ package com.android.settings.search; import android.util.ArrayMap; -import com.android.settings.DisplaySettings; import com.android.settings.backup.UserBackupSettingsActivity; import com.android.settings.connecteddevice.ConnectedDeviceDashboardFragment; import com.android.settings.connecteddevice.usb.UsbDetailsFragment; @@ -34,7 +33,6 @@ import com.android.settings.notification.zen.ZenModeRestrictNotificationsSetting import com.android.settings.security.SecuritySettings; import com.android.settings.security.screenlock.ScreenLockSettings; import com.android.settings.system.SystemDashboardFragment; -import com.android.settings.wallpaper.WallpaperSuggestionActivity; import com.android.settings.wifi.WifiSettings; import java.util.Map; @@ -52,8 +50,6 @@ public class CustomSiteMapRegistry { static { CUSTOM_SITE_MAP = new ArrayMap<>(); CUSTOM_SITE_MAP.put(ScreenLockSettings.class.getName(), SecuritySettings.class.getName()); - CUSTOM_SITE_MAP.put( - WallpaperSuggestionActivity.class.getName(), DisplaySettings.class.getName()); CUSTOM_SITE_MAP.put( WifiSettings.class.getName(), NetworkDashboardFragment.class.getName()); CUSTOM_SITE_MAP.put(PowerUsageAdvanced.class.getName(), PowerUsageSummary.class.getName()); diff --git a/tests/unit/src/com/android/settings/search/CustomSiteMapRegistryTest.java b/tests/unit/src/com/android/settings/search/CustomSiteMapRegistryTest.java index b8c3d57f445..3848fe446b0 100644 --- a/tests/unit/src/com/android/settings/search/CustomSiteMapRegistryTest.java +++ b/tests/unit/src/com/android/settings/search/CustomSiteMapRegistryTest.java @@ -20,7 +20,6 @@ import static com.google.common.truth.Truth.assertThat; import androidx.test.ext.junit.runners.AndroidJUnit4; -import com.android.settings.DisplaySettings; import com.android.settings.backup.UserBackupSettingsActivity; import com.android.settings.connecteddevice.ConnectedDeviceDashboardFragment; import com.android.settings.connecteddevice.usb.UsbDetailsFragment; @@ -36,7 +35,6 @@ import com.android.settings.notification.zen.ZenModeRestrictNotificationsSetting import com.android.settings.security.SecuritySettings; import com.android.settings.security.screenlock.ScreenLockSettings; import com.android.settings.system.SystemDashboardFragment; -import com.android.settings.wallpaper.WallpaperSuggestionActivity; import com.android.settings.wifi.WifiSettings; import org.junit.Test; @@ -51,13 +49,6 @@ public class CustomSiteMapRegistryTest { .isEqualTo(SecuritySettings.class.getName()); } - @Test - public void shouldContainWallpaperSuggestionActivityPairs() { - assertThat(CustomSiteMapRegistry.CUSTOM_SITE_MAP.get( - WallpaperSuggestionActivity.class.getName())) - .isEqualTo(DisplaySettings.class.getName()); - } - @Test public void shouldContainWifiSettingsPairs() { assertThat(CustomSiteMapRegistry.CUSTOM_SITE_MAP.get(WifiSettings.class.getName())) From 4b34271f7daff252880b4f3a74cff1d9b0a70de9 Mon Sep 17 00:00:00 2001 From: Kevin Han Date: Tue, 25 May 2021 17:45:23 -0700 Subject: [PATCH 13/23] Ensure hibernation exemption toggle uses pre-S flag For dogfood, we want hibernation to target apps that target pre-S. This was done on the PermissionController side but the toggle in Settings did not visually reflect this policy, confusing dogfood/teamfood participants. This updates the default toggle position to consider whether the pre-S flag is on and then default to the "on" position for apps targeting pre-S if the flag was on for the device. Bug: 189260947 Test: atest HibernationSwitchPreferenceControllerTest Test: manual Change-Id: I9cd16e82e1eee4589cb17a356b6bf2e3297a8dd2 --- src/com/android/settings/Utils.java | 4 ++++ .../HibernationSwitchPreferenceController.java | 13 +++++++++++-- ...HibernationSwitchPreferenceControllerTest.java | 15 +++++++++++++++ 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/src/com/android/settings/Utils.java b/src/com/android/settings/Utils.java index 7614070981f..6e926404674 100644 --- a/src/com/android/settings/Utils.java +++ b/src/com/android/settings/Utils.java @@ -161,6 +161,10 @@ public final class Utils extends com.android.settingslib.Utils { /** Whether or not app hibernation is enabled on the device **/ public static final String PROPERTY_APP_HIBERNATION_ENABLED = "app_hibernation_enabled"; + /** Whether or not app hibernation targets apps that target a pre-S SDK **/ + public static final String PROPERTY_HIBERNATION_TARGETS_PRE_S_APPS = + "app_hibernation_targets_pre_s_apps"; + /** Whether or not Settings Shared Axis transition is enabled */ public static final String SETTINGS_SHARED_AXIS_ENABLED = "settings_shared_axis_enabled"; diff --git a/src/com/android/settings/applications/appinfo/HibernationSwitchPreferenceController.java b/src/com/android/settings/applications/appinfo/HibernationSwitchPreferenceController.java index 40be629d724..42f862dac17 100644 --- a/src/com/android/settings/applications/appinfo/HibernationSwitchPreferenceController.java +++ b/src/com/android/settings/applications/appinfo/HibernationSwitchPreferenceController.java @@ -23,6 +23,7 @@ import static android.app.AppOpsManager.OPSTR_AUTO_REVOKE_PERMISSIONS_IF_UNUSED; import static android.provider.DeviceConfig.NAMESPACE_APP_HIBERNATION; import static com.android.settings.Utils.PROPERTY_APP_HIBERNATION_ENABLED; +import static com.android.settings.Utils.PROPERTY_HIBERNATION_TARGETS_PRE_S_APPS; import android.app.AppOpsManager; import android.content.Context; @@ -95,8 +96,11 @@ public final class HibernationSwitchPreferenceController extends AppInfoPreferen : android.os.Build.VERSION_CODES.Q; try { mPackageUid = packageManager.getPackageUid(packageName, /* flags */ 0); - mIsPackageExemptByDefault = packageManager.getTargetSdkVersion(packageName) - <= maxTargetSdkVersionForExemptApps; + mIsPackageExemptByDefault = + hibernationTargetsPreSApps() + ? false + : packageManager.getTargetSdkVersion(packageName) + <= maxTargetSdkVersionForExemptApps; mIsPackageSet = true; } catch (PackageManager.NameNotFoundException e) { Slog.w(TAG, "Package [" + mPackageName + "] is not found!"); @@ -142,4 +146,9 @@ public final class HibernationSwitchPreferenceController extends AppInfoPreferen return DeviceConfig.getBoolean( NAMESPACE_APP_HIBERNATION, PROPERTY_APP_HIBERNATION_ENABLED, false); } + + private static boolean hibernationTargetsPreSApps() { + return DeviceConfig.getBoolean( + NAMESPACE_APP_HIBERNATION, PROPERTY_HIBERNATION_TARGETS_PRE_S_APPS, false); + } } diff --git a/tests/unit/src/com/android/settings/applications/appinfo/HibernationSwitchPreferenceControllerTest.java b/tests/unit/src/com/android/settings/applications/appinfo/HibernationSwitchPreferenceControllerTest.java index 65ffe4b7657..1e1799a282b 100644 --- a/tests/unit/src/com/android/settings/applications/appinfo/HibernationSwitchPreferenceControllerTest.java +++ b/tests/unit/src/com/android/settings/applications/appinfo/HibernationSwitchPreferenceControllerTest.java @@ -22,6 +22,7 @@ import static android.app.AppOpsManager.OPSTR_AUTO_REVOKE_PERMISSIONS_IF_UNUSED; import static android.provider.DeviceConfig.NAMESPACE_APP_HIBERNATION; import static com.android.settings.Utils.PROPERTY_APP_HIBERNATION_ENABLED; +import static com.android.settings.Utils.PROPERTY_HIBERNATION_TARGETS_PRE_S_APPS; import static com.android.settings.core.BasePreferenceController.AVAILABLE; import static com.google.common.truth.Truth.assertThat; @@ -143,4 +144,18 @@ public class HibernationSwitchPreferenceControllerTest { verify(mPreference).setChecked(false); } + + @Test + public void updateState_exemptedByDefaultPackageOverriddenByPreSFlag_shouldCheck() { + DeviceConfig.setProperty(NAMESPACE_APP_HIBERNATION, PROPERTY_HIBERNATION_TARGETS_PRE_S_APPS, + "true", true /* makeDefault */); + when(mAppOpsManager.unsafeCheckOpNoThrow( + eq(OPSTR_AUTO_REVOKE_PERMISSIONS_IF_UNUSED), anyInt(), eq(EXEMPTED_PACKAGE_NAME))) + .thenReturn(MODE_DEFAULT); + mController.setPackage(EXEMPTED_PACKAGE_NAME); + + mController.updateState(mPreference); + + verify(mPreference).setChecked(true); + } } From 3f6bccc87c93384d95b690426dad4ecd438038d3 Mon Sep 17 00:00:00 2001 From: changbetty Date: Wed, 26 May 2021 11:19:03 +0800 Subject: [PATCH 14/23] Remove all the dividers in Wifi Settings Bug: 189049289 Test: manual test Change-Id: Ib2b884e36837bf9cc30c6af554c774bda8e7322b --- res/xml/network_provider_settings.xml | 8 ++------ res/xml/wifi_network_details_fragment2.xml | 21 +++++++-------------- 2 files changed, 9 insertions(+), 20 deletions(-) diff --git a/res/xml/network_provider_settings.xml b/res/xml/network_provider_settings.xml index b29755bab82..3d4ce800dc0 100644 --- a/res/xml/network_provider_settings.xml +++ b/res/xml/network_provider_settings.xml @@ -25,16 +25,14 @@ android:key="resetting_your_internet" android:title="@string/resetting_internet_text" android:selectable="false" - android:layout="@layout/resetting_internet" - settings:allowDividerBelow="true"/> + android:layout="@layout/resetting_internet"/> + android:layout="@layout/airplane_mode_message_preference"/> + android:order="-10000"/> + android:selectable="false"/> + android:selectable="false"/> + android:selectable="false"/> + android:summary="@string/wifi_subscription_summary"/> + android:summary="@string/wifi_auto_connect_summary"/> + android:summary="@string/wifi_dpp_connect_network_using_qr_code"/> Date: Tue, 25 May 2021 22:18:23 +0800 Subject: [PATCH 15/23] Remove silky flag from Display for official release Remove the silky condition and clean up redundant files. Bug: 183670633 Test: robotests & visual with turning on/off silky home Change-Id: I139f1dbc1ca030ccb0b778c479e0b23289c1c282 --- res/xml/display_settings.xml | 224 +++++++++--------- res/xml/display_settings_v2.xml | 159 ------------- src/com/android/settings/DisplaySettings.java | 18 +- 3 files changed, 116 insertions(+), 285 deletions(-) delete mode 100644 res/xml/display_settings_v2.xml diff --git a/res/xml/display_settings.xml b/res/xml/display_settings.xml index ab8b3859def..c48dcbcaef3 100644 --- a/res/xml/display_settings.xml +++ b/res/xml/display_settings.xml @@ -19,134 +19,140 @@ xmlns:settings="http://schemas.android.com/apk/res-auto" android:key="display_settings_screen" android:title="@string/display_settings" - settings:keywords="@string/keywords_display" - settings:initialExpandedChildrenCount="6"> + settings:keywords="@string/keywords_display"> - - - + - + - + + - + - - + - - + + - + - + - + - + + - + - + - + + - + - + - + - + - + - + - + + + + + + + + + diff --git a/res/xml/display_settings_v2.xml b/res/xml/display_settings_v2.xml deleted file mode 100644 index 2d6e3db5f25..00000000000 --- a/res/xml/display_settings_v2.xml +++ /dev/null @@ -1,159 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/com/android/settings/DisplaySettings.java b/src/com/android/settings/DisplaySettings.java index 1cb9aded0c5..9a62412704b 100644 --- a/src/com/android/settings/DisplaySettings.java +++ b/src/com/android/settings/DisplaySettings.java @@ -19,10 +19,7 @@ package com.android.settings; import android.app.settings.SettingsEnums; import android.content.Context; import android.os.Bundle; -import android.provider.SearchIndexableResource; -import android.util.FeatureFlagUtils; -import com.android.settings.core.FeatureFlags; import com.android.settings.dashboard.DashboardFragment; import com.android.settings.display.BrightnessLevelPreferenceController; import com.android.settings.display.CameraGesturePreferenceController; @@ -38,7 +35,6 @@ import com.android.settingslib.core.lifecycle.Lifecycle; import com.android.settingslib.search.SearchIndexable; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; @SearchIndexable(forTarget = SearchIndexable.ALL & ~SearchIndexable.ARC) @@ -57,9 +53,6 @@ public class DisplaySettings extends DashboardFragment { @Override protected int getPreferenceScreenResId() { - if (FeatureFlagUtils.isEnabled(getContext(), FeatureFlags.SILKY_HOME)) { - return R.xml.display_settings_v2; - } return R.xml.display_settings; } @@ -93,16 +86,7 @@ public class DisplaySettings extends DashboardFragment { } public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = - new BaseSearchIndexProvider() { - - @Override - public List getXmlResourcesToIndex( - Context context, boolean enabled) { - final SearchIndexableResource sir = new SearchIndexableResource(context); - sir.xmlResId = FeatureFlagUtils.isEnabled(context, FeatureFlags.SILKY_HOME) - ? R.xml.display_settings_v2 : R.xml.display_settings; - return Arrays.asList(sir); - } + new BaseSearchIndexProvider(R.xml.display_settings) { @Override public List createPreferenceControllers( From e0c921a8fafe23e485089f4aa63527dd5fdc0f4d Mon Sep 17 00:00:00 2001 From: Sunny Shao Date: Tue, 25 May 2021 10:51:21 +0800 Subject: [PATCH 16/23] Fix the extra speaking in Allow supervision dialog - Extra speaking the "double tap to activate" when focus "Family Link manage ...". - Root cause: this Textview set the setMovementMethod method. - Solution: Remove this setMovementMethod because it is usless in here. Bug: 187968203 Test: manual test Change-Id: Ia3f277f6814cb009f0e07f56381e3e46fbacc7a8 --- .../applications/specialaccess/deviceadmin/DeviceAdminAdd.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminAdd.java b/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminAdd.java index 3ebbc06dc88..7b2f4ba15af 100644 --- a/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminAdd.java +++ b/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminAdd.java @@ -49,7 +49,6 @@ import android.os.UserHandle; import android.os.UserManager; import android.text.TextUtils; import android.text.TextUtils.TruncateAt; -import android.text.method.ScrollingMovementMethod; import android.util.EventLog; import android.util.Log; import android.view.Display; @@ -338,7 +337,6 @@ public class DeviceAdminAdd extends CollapsingToolbarBaseActivity { mActionButton = ((AlertDialog) dialog).getButton(DialogInterface.BUTTON_POSITIVE); mActionButton.setFilterTouchesWhenObscured(true); mAddMsg = dialog.findViewById(R.id.add_msg_simplified); - mAddMsg.setMovementMethod(new ScrollingMovementMethod()); mAddMsg.setText(mAddMsgText); mAdminWarning = dialog.findViewById(R.id.admin_warning_simplified); mAdminWarning.setText(getString(R.string.device_admin_warning_simplified, From 46bcdda9b976d4e22d4d58efb40288e6c22d6f61 Mon Sep 17 00:00:00 2001 From: ykhung Date: Tue, 25 May 2021 14:34:50 +0800 Subject: [PATCH 17/23] Disable app usage item if this item is not clickable some items are not clickable to launch the restriction page in the battery usage list, we will apply the disabled visual in the preferrence item to improve the UX (avoid users click the item without any action) Bug: 188751551 Bug: 188663505 Test: make SettingsgRoboTests Change-Id: Ib8925b8e191117543bb1c74d6d01191e3043fc73 --- .../BatteryChartPreferenceController.java | 23 ++--- .../settings/fuelgauge/BatteryDiffEntry.java | 85 ++++++++++++++++-- .../settings/fuelgauge/BatteryEntry.java | 11 ++- .../BatteryChartPreferenceControllerTest.java | 10 +-- .../fuelgauge/BatteryDiffEntryTest.java | 90 +++++++++++++++++-- 5 files changed, 178 insertions(+), 41 deletions(-) diff --git a/src/com/android/settings/fuelgauge/BatteryChartPreferenceController.java b/src/com/android/settings/fuelgauge/BatteryChartPreferenceController.java index dbbafe6bdf6..ffbd2d90e4e 100644 --- a/src/com/android/settings/fuelgauge/BatteryChartPreferenceController.java +++ b/src/com/android/settings/fuelgauge/BatteryChartPreferenceController.java @@ -189,6 +189,8 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll mPrefContext = screen.getContext(); mAppListPrefGroup = screen.findPreference(mPreferenceKey); mAppListPrefGroup.setOrderingAsAdded(false); + mAppListPrefGroup.setTitle( + mPrefContext.getString(R.string.battery_app_usage_for_past_24)); mFooterPreference = screen.findPreference(KEY_FOOTER_PREF); // Removes footer first until usage data is loaded to avoid flashing. if (mFooterPreference != null) { @@ -216,15 +218,6 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll final BatteryHistEntry histEntry = diffEntry.mBatteryHistEntry; final String packageName = histEntry.mPackageName; final boolean isAppEntry = histEntry.isAppEntry(); - // Checks whether the package is installed or not. - boolean isValidPackage = true; - if (isAppEntry) { - if (mBatteryUtils == null) { - mBatteryUtils = BatteryUtils.getInstance(mPrefContext); - } - isValidPackage = mBatteryUtils.getPackageUid(packageName) - != BatteryUtils.UID_NULL; - } mMetricsFeatureProvider.action( mPrefContext, isAppEntry @@ -233,15 +226,12 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll new Pair(ConvertUtils.METRIC_KEY_PACKAGE, packageName), new Pair(ConvertUtils.METRIC_KEY_BATTERY_LEVEL, histEntry.mBatteryLevel), new Pair(ConvertUtils.METRIC_KEY_BATTERY_USAGE, powerPref.getPercent())); - Log.d(TAG, String.format("handleClick() label=%s key=%s isValid:%b\n%s", - diffEntry.getAppLabel(), histEntry.getKey(), isValidPackage, histEntry)); - if (isValidPackage) { - AdvancedPowerUsageDetail.startBatteryDetailPage( + Log.d(TAG, String.format("handleClick() label=%s key=%s enntry=\n%s", + diffEntry.getAppLabel(), histEntry.getKey(), histEntry)); + AdvancedPowerUsageDetail.startBatteryDetailPage( mActivity, mFragment, diffEntry, powerPref.getPercent(), isValidToShowSummary(packageName), getSlotInformation()); - return true; - } - return false; + return true; } @Override @@ -434,6 +424,7 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll pref.setSingleLineTitle(true); // Sets the BatteryDiffEntry to preference for launching detailed page. pref.setBatteryDiffEntry(entry); + pref.setEnabled(entry.validForRestriction()); setPreferenceSummary(pref, entry); if (!isAdded) { mAppListPrefGroup.addPreference(pref); diff --git a/src/com/android/settings/fuelgauge/BatteryDiffEntry.java b/src/com/android/settings/fuelgauge/BatteryDiffEntry.java index 9db29f33fb7..c6b2d4542e2 100644 --- a/src/com/android/settings/fuelgauge/BatteryDiffEntry.java +++ b/src/com/android/settings/fuelgauge/BatteryDiffEntry.java @@ -39,6 +39,8 @@ public class BatteryDiffEntry { static Locale sCurrentLocale = null; // Caches app label and icon to improve loading performance. static final Map sResourceCache = new HashMap<>(); + // Whether a specific item is valid to launch restriction page? + static final Map sValidForRestriction = new HashMap<>(); /** A comparator for {@link BatteryDiffEntry} based on consumed percentage. */ public static final Comparator COMPARATOR = @@ -60,6 +62,7 @@ public class BatteryDiffEntry { @VisibleForTesting String mAppLabel = null; @VisibleForTesting Drawable mAppIcon = null; @VisibleForTesting boolean mIsLoaded = false; + @VisibleForTesting boolean mValidForRestriction = true; public BatteryDiffEntry( Context context, @@ -129,6 +132,12 @@ public class BatteryDiffEntry { ? mDefaultPackageName : mBatteryHistEntry.mPackageName; } + /** Whether this item is valid for users to launch restriction page? */ + public boolean validForRestriction() { + loadLabelAndIcon(); + return mValidForRestriction; + } + /** Whether the current BatteryDiffEntry is system component or not. */ public boolean isSystemEntry() { switch (mBatteryHistEntry.mConsumerType) { @@ -146,7 +155,29 @@ public class BatteryDiffEntry { if (mIsLoaded) { return; } + // Checks whether we have cached data or not first before fetching. + final BatteryEntry.NameAndIcon nameAndIcon = getCache(); + if (nameAndIcon != null) { + mAppLabel = nameAndIcon.name; + mAppIcon = nameAndIcon.icon; + mAppIconId = nameAndIcon.iconId; + } + final Boolean validForRestriction = sValidForRestriction.get(getKey()); + if (validForRestriction != null) { + mValidForRestriction = validForRestriction; + } + // Both nameAndIcon and restriction configuration have cached data. + if (nameAndIcon != null && validForRestriction != null) { + Log.w(TAG, String.format("cannot find cache data nameAndIcon:%s " + + "validForRestriction:%s", nameAndIcon, validForRestriction)); + return; + } mIsLoaded = true; + + // Configures whether we can launch restriction page or not. + updateRestrictionFlagState(); + sValidForRestriction.put(getKey(), Boolean.valueOf(mValidForRestriction)); + // Loads application icon and label based on consumer type. switch (mBatteryHistEntry.mConsumerType) { case ConvertUtils.CONSUMER_TYPE_USER_BATTERY: @@ -156,6 +187,9 @@ public class BatteryDiffEntry { if (nameAndIconForUser != null) { mAppIcon = nameAndIconForUser.icon; mAppLabel = nameAndIconForUser.name; + sResourceCache.put( + getKey(), + new BatteryEntry.NameAndIcon(mAppLabel, mAppIcon, /*iconId=*/ 0)); } break; case ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY: @@ -168,15 +202,12 @@ public class BatteryDiffEntry { mAppIconId = nameAndIconForSystem.iconId; mAppIcon = mContext.getDrawable(nameAndIconForSystem.iconId); } + sResourceCache.put( + getKey(), + new BatteryEntry.NameAndIcon(mAppLabel, mAppIcon, mAppIconId)); } break; case ConvertUtils.CONSUMER_TYPE_UID_BATTERY: - final BatteryEntry.NameAndIcon nameAndIcon = getCache(); - if (nameAndIcon != null) { - mAppLabel = nameAndIcon.name; - mAppIcon = nameAndIcon.icon; - break; - } loadNameAndIconForUid(); // Uses application default icon if we cannot find it from package. if (mAppIcon == null) { @@ -186,13 +217,47 @@ public class BatteryDiffEntry { mAppIcon = getBadgeIconForUser(mAppIcon); if (mAppLabel != null || mAppIcon != null) { sResourceCache.put( - mBatteryHistEntry.getKey(), + getKey(), new BatteryEntry.NameAndIcon(mAppLabel, mAppIcon, /*iconId=*/ 0)); } break; } } + @VisibleForTesting + String getKey() { + return mBatteryHistEntry.getKey(); + } + + @VisibleForTesting + void updateRestrictionFlagState() { + mValidForRestriction = true; + if (!mBatteryHistEntry.isAppEntry()) { + return; + } + final boolean isValidPackage = + BatteryUtils.getInstance(mContext).getPackageUid(getPackageName()) + != BatteryUtils.UID_NULL; + if (!isValidPackage) { + mValidForRestriction = false; + return; + } + try { + mValidForRestriction = + mContext.getPackageManager().getPackageInfo( + getPackageName(), + PackageManager.MATCH_DISABLED_COMPONENTS + | PackageManager.MATCH_ANY_USER + | PackageManager.GET_SIGNATURES + | PackageManager.GET_PERMISSIONS) + != null; + } catch (Exception e) { + Log.e(TAG, String.format("getPackageInfo() error %s for package=%s", + e.getCause(), getPackageName())); + mValidForRestriction = false; + } + } + private BatteryEntry.NameAndIcon getCache() { final Locale locale = Locale.getDefault(); if (sCurrentLocale != locale) { @@ -201,7 +266,7 @@ public class BatteryDiffEntry { sCurrentLocale = locale; clearCache(); } - return sResourceCache.get(mBatteryHistEntry.getKey()); + return sResourceCache.get(getKey()); } private void loadNameAndIconForUid() { @@ -258,7 +323,8 @@ public class BatteryDiffEntry { public String toString() { final StringBuilder builder = new StringBuilder() .append("BatteryDiffEntry{") - .append("\n\tname=" + mAppLabel) + .append(String.format("\n\tname=%s restrictable=%b", + mAppLabel, mValidForRestriction)) .append(String.format("\n\tconsume=%.2f%% %f/%f", mPercentOfTotal, mConsumePower, mTotalConsumePower)) .append(String.format("\n\tforeground:%s background:%s", @@ -274,6 +340,7 @@ public class BatteryDiffEntry { static void clearCache() { sResourceCache.clear(); + sValidForRestriction.clear(); } private Drawable getBadgeIconForUser(Drawable icon) { diff --git a/src/com/android/settings/fuelgauge/BatteryEntry.java b/src/com/android/settings/fuelgauge/BatteryEntry.java index 636d2651a8d..125409cd84f 100644 --- a/src/com/android/settings/fuelgauge/BatteryEntry.java +++ b/src/com/android/settings/fuelgauge/BatteryEntry.java @@ -241,7 +241,10 @@ public class BatteryEntry { mBatteryConsumer = null; mIsHidden = false; mPowerComponentId = powerComponentId; - mConsumedPower = devicePowerMah; + mConsumedPower = + powerComponentId == BatteryConsumer.POWER_COMPONENT_SCREEN + ? devicePowerMah + : devicePowerMah - appsPowerMah; mUsageDurationMs = usageDurationMs; mConsumerType = ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY; @@ -264,8 +267,10 @@ public class BatteryEntry { iconId = R.drawable.ic_power_system; icon = context.getDrawable(iconId); name = powerComponentName; - - mConsumedPower = devicePowerMah; + mConsumedPower = + powerComponentId == BatteryConsumer.POWER_COMPONENT_SCREEN + ? devicePowerMah + : devicePowerMah - appsPowerMah; mConsumerType = ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY; } diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryChartPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryChartPreferenceControllerTest.java index 9e2f65d6f3a..606dc194239 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryChartPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryChartPreferenceControllerTest.java @@ -307,6 +307,7 @@ public final class BatteryChartPreferenceControllerTest { doReturn(appLabel).when(mBatteryDiffEntry).getAppLabel(); doReturn(PREF_KEY).when(mBatteryHistEntry).getKey(); doReturn(null).when(mAppListGroup).findPreference(PREF_KEY); + doReturn(false).when(mBatteryDiffEntry).validForRestriction(); mBatteryChartPreferenceController.addPreferenceToScreen( Arrays.asList(mBatteryDiffEntry)); @@ -324,6 +325,7 @@ public final class BatteryChartPreferenceControllerTest { assertThat(pref.getOrder()).isEqualTo(1); assertThat(pref.getBatteryDiffEntry()).isSameInstanceAs(mBatteryDiffEntry); assertThat(pref.isSingleLineTitle()).isTrue(); + assertThat(pref.isEnabled()).isFalse(); } @Test @@ -353,7 +355,7 @@ public final class BatteryChartPreferenceControllerTest { } @Test - public void testHandlePreferenceTreeClick_validPackageName_returnTrue() { + public void testHandlePreferenceTreeClick_forAppEntry_returnTrue() { doReturn(false).when(mBatteryHistEntry).isAppEntry(); doReturn(mBatteryDiffEntry).when(mPowerGaugePreference).getBatteryDiffEntry(); @@ -371,15 +373,13 @@ public final class BatteryChartPreferenceControllerTest { } @Test - public void testHandlePreferenceTreeClick_appEntryWithInvalidPackage_returnFalse() { + public void testHandlePreferenceTreeClick_forSystemEntry_returnTrue() { mBatteryChartPreferenceController.mBatteryUtils = mBatteryUtils; doReturn(true).when(mBatteryHistEntry).isAppEntry(); - doReturn(BatteryUtils.UID_NULL).when(mBatteryUtils) - .getPackageUid(mBatteryHistEntry.mPackageName); doReturn(mBatteryDiffEntry).when(mPowerGaugePreference).getBatteryDiffEntry(); assertThat(mBatteryChartPreferenceController.handlePreferenceTreeClick( - mPowerGaugePreference)).isFalse(); + mPowerGaugePreference)).isTrue(); verify(mMetricsFeatureProvider) .action( mContext, diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryDiffEntryTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryDiffEntryTest.java index 586016399b3..0df53f1be41 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryDiffEntryTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryDiffEntryTest.java @@ -17,12 +17,15 @@ package com.android.settings.fuelgauge; import static com.google.common.truth.Truth.assertThat; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Matchers.anyInt; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.spy; import android.content.ContentValues; import android.content.Context; import android.content.pm.ApplicationInfo; +import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.graphics.drawable.Drawable; import android.os.BatteryConsumer; @@ -56,11 +59,13 @@ public final class BatteryDiffEntryTest { @Mock private Drawable mockDrawable2; @Mock private Drawable mockBadgedDrawable; @Mock private BatteryHistEntry mBatteryHistEntry; + @Mock private PackageInfo mockPackageInfo; @Before public void setUp() { MockitoAnnotations.initMocks(this); mContext = spy(RuntimeEnvironment.application); + doReturn(mContext).when(mContext).getApplicationContext(); doReturn(mockUserManager).when(mContext).getSystemService(UserManager.class); doReturn(mockPackageManager).when(mContext).getPackageManager(); BatteryDiffEntry.clearCache(); @@ -110,6 +115,7 @@ public final class BatteryDiffEntryTest { @Test public void testLoadLabelAndIcon_forSystemBattery_returnExpectedResult() { + final String expectedName = "Ambient display"; // Generates fake testing data. final ContentValues values = getContentValuesWithType( ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY); @@ -119,13 +125,22 @@ public final class BatteryDiffEntryTest { final BatteryDiffEntry entry = createBatteryDiffEntry(10, batteryHistEntry); - assertThat(entry.getAppLabel()).isEqualTo("Ambient display"); + assertThat(entry.getAppLabel()).isEqualTo(expectedName); assertThat(entry.getAppIconId()).isEqualTo(R.drawable.ic_settings_aod); - assertThat(BatteryDiffEntry.sResourceCache).isEmpty(); + assertThat(BatteryDiffEntry.sResourceCache).hasSize(1); + // Verifies the app label in the cache. + final BatteryEntry.NameAndIcon nameAndIcon = + BatteryDiffEntry.sResourceCache.get(entry.getKey()); + assertThat(nameAndIcon.name).isEqualTo(expectedName); + assertThat(nameAndIcon.iconId).isEqualTo(R.drawable.ic_settings_aod); + // Verifies the restrictable flag in the cache. + assertThat(entry.mValidForRestriction).isTrue(); + assertThat(BatteryDiffEntry.sValidForRestriction.get(entry.getKey())).isTrue(); } @Test public void testLoadLabelAndIcon_forUserBattery_returnExpectedResult() { + final String expectedName = "Removed user"; doReturn(null).when(mockUserManager).getUserInfo(1001); // Generates fake testing data. final ContentValues values = getContentValuesWithType( @@ -135,10 +150,18 @@ public final class BatteryDiffEntryTest { final BatteryDiffEntry entry = createBatteryDiffEntry(10, batteryHistEntry); - assertThat(entry.getAppLabel()).isEqualTo("Removed user"); + assertThat(entry.getAppLabel()).isEqualTo(expectedName); assertThat(entry.getAppIcon()).isNull(); assertThat(entry.getAppIconId()).isEqualTo(0); - assertThat(BatteryDiffEntry.sResourceCache).isEmpty(); + assertThat(BatteryDiffEntry.sResourceCache).hasSize(1); + // Verifies the app label in the cache. + final BatteryEntry.NameAndIcon nameAndIcon = + BatteryDiffEntry.sResourceCache.get(entry.getKey()); + assertThat(nameAndIcon.name).isEqualTo(expectedName); + assertThat(nameAndIcon.iconId).isEqualTo(0); + // Verifies the restrictable flag in the cache. + assertThat(entry.mValidForRestriction).isTrue(); + assertThat(BatteryDiffEntry.sValidForRestriction.get(entry.getKey())).isTrue(); } @Test @@ -162,8 +185,11 @@ public final class BatteryDiffEntryTest { assertThat(BatteryDiffEntry.sResourceCache).hasSize(1); // Verifies the app label in the cache. final BatteryEntry.NameAndIcon nameAndIcon = - BatteryDiffEntry.sResourceCache.get(batteryHistEntry.getKey()); + BatteryDiffEntry.sResourceCache.get(entry.getKey()); assertThat(nameAndIcon.name).isEqualTo(expectedAppLabel); + // Verifies the restrictable flag in the cache. + assertThat(entry.mValidForRestriction).isFalse(); + assertThat(BatteryDiffEntry.sValidForRestriction.get(entry.getKey())).isFalse(); } @Test @@ -179,7 +205,7 @@ public final class BatteryDiffEntryTest { assertThat(BatteryDiffEntry.sResourceCache).hasSize(1); // Verifies the app label in the cache. final BatteryEntry.NameAndIcon nameAndIcon = - BatteryDiffEntry.sResourceCache.get(batteryHistEntry.getKey()); + BatteryDiffEntry.sResourceCache.get(entry.getKey()); assertThat(nameAndIcon.name).isEqualTo(expectedAppLabel); } @@ -225,10 +251,24 @@ public final class BatteryDiffEntryTest { assertThat(BatteryDiffEntry.sResourceCache).hasSize(1); // Verifies the app label in the cache. final BatteryEntry.NameAndIcon nameAndIcon = - BatteryDiffEntry.sResourceCache.get(entry.mBatteryHistEntry.getKey()); + BatteryDiffEntry.sResourceCache.get(entry.getKey()); assertThat(nameAndIcon.icon).isEqualTo(mockBadgedDrawable); } + @Test + public void testClearCache_clearDataForResourcesAndFlags() { + BatteryDiffEntry.sResourceCache.put( + "fake application key", + new BatteryEntry.NameAndIcon("app label", null, /*iconId=*/ 0)); + BatteryDiffEntry.sValidForRestriction.put( + "fake application key", Boolean.valueOf(false)); + + BatteryDiffEntry.clearCache(); + + assertThat(BatteryDiffEntry.sResourceCache).isEmpty(); + assertThat(BatteryDiffEntry.sValidForRestriction).isEmpty(); + } + @Test public void testClearCache_switchLocale_clearCacheIconAndLabel() throws Exception { final int userId = UserHandle.getUserId(1001); @@ -248,7 +288,7 @@ public final class BatteryDiffEntryTest { assertThat(entry2.getAppIcon()).isEqualTo(mockDrawable2); // Verifies the cache is updated into the new drawable. final BatteryEntry.NameAndIcon nameAndIcon = - BatteryDiffEntry.sResourceCache.get(entry2.mBatteryHistEntry.getKey()); + BatteryDiffEntry.sResourceCache.get(entry2.getKey()); assertThat(nameAndIcon.icon).isEqualTo(mockDrawable2); } @@ -297,6 +337,40 @@ public final class BatteryDiffEntryTest { assertThat(entry.isSystemEntry()).isTrue(); } + @Test + public void testUpdateRestrictionFlagState_updateFlagAsExpected() throws Exception { + final String expectedAppLabel = "fake app label"; + final String fakePackageName = "com.fake.google.com"; + final ContentValues values = getContentValuesWithType( + ConvertUtils.CONSUMER_TYPE_UID_BATTERY); + values.put("uid", /*invalid uid*/ 10001); + values.put("packageName", fakePackageName); + final BatteryDiffEntry entry = + createBatteryDiffEntry(10, new BatteryHistEntry(values)); + + entry.updateRestrictionFlagState(); + // Sets false if the app entry cannot be found. + assertThat(entry.mValidForRestriction).isFalse(); + + doReturn(BatteryUtils.UID_NULL).when(mockPackageManager).getPackageUid( + entry.getPackageName(), PackageManager.GET_META_DATA); + entry.updateRestrictionFlagState(); + // Sets false if the app is invalid package name. + assertThat(entry.mValidForRestriction).isFalse(); + + doReturn(1000).when(mockPackageManager).getPackageUid( + entry.getPackageName(), PackageManager.GET_META_DATA); + entry.updateRestrictionFlagState(); + // Sets false if the app PackageInfo cannot be found. + assertThat(entry.mValidForRestriction).isFalse(); + + doReturn(mockPackageInfo).when(mockPackageManager).getPackageInfo( + eq(entry.getPackageName()), anyInt()); + entry.updateRestrictionFlagState(); + // Sets true if package is valid and PackageInfo can be found. + assertThat(entry.mValidForRestriction).isTrue(); + } + private BatteryDiffEntry createBatteryDiffEntry( int consumerType, long uid, boolean isHidden) { final ContentValues values = getContentValuesWithType(consumerType); From c491216243de8af8d2f313c404a3e543fb249888 Mon Sep 17 00:00:00 2001 From: Patty Date: Wed, 26 May 2021 15:46:00 +0800 Subject: [PATCH 18/23] Fix pairing dialog doesn't show the correct pairing key. When the pairing dialog doesn't show in the foreground at the first time, the pairing key will display incorrectly. This is caused by the intent doesn't contain the parameter BluetoothDevice.EXTRA_PAIRING_KEY. Correct the pairing key by passing the pairing key to intent pairingDialogIntent. Tag: #stability Bug: 188614067 Test: make RunSettingsRoboTests ROBOTEST_FILTER=BluetoothPairingServiceTest Change-Id: I3c91bf6ea51fa3fb77b4c4a5c17555606160603e --- .../settings/bluetooth/BluetoothPairingService.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/com/android/settings/bluetooth/BluetoothPairingService.java b/src/com/android/settings/bluetooth/BluetoothPairingService.java index 0bff721b8a9..47565d3f09a 100644 --- a/src/com/android/settings/bluetooth/BluetoothPairingService.java +++ b/src/com/android/settings/bluetooth/BluetoothPairingService.java @@ -177,6 +177,15 @@ public final class BluetoothPairingService extends Service { pairingDialogIntent.setClass(this, BluetoothPairingService.class); pairingDialogIntent.putExtra(BluetoothDevice.EXTRA_DEVICE, mDevice); pairingDialogIntent.putExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT, type); + + if (type == BluetoothDevice.PAIRING_VARIANT_PASSKEY_CONFIRMATION + || type == BluetoothDevice.PAIRING_VARIANT_DISPLAY_PASSKEY + || type == BluetoothDevice.PAIRING_VARIANT_DISPLAY_PIN) { + int pairingKey = intent.getIntExtra(BluetoothDevice.EXTRA_PAIRING_KEY, + BluetoothDevice.ERROR); + pairingDialogIntent.putExtra(BluetoothDevice.EXTRA_PAIRING_KEY, pairingKey); + } + PendingIntent pairIntent = PendingIntent.getService(this, 0, pairingDialogIntent, PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_IMMUTABLE); From 8871134dcd40c9c787bcbdcc008c2c72b723b21c Mon Sep 17 00:00:00 2001 From: Yi-Ling Chuang Date: Wed, 26 May 2021 14:38:28 +0800 Subject: [PATCH 19/23] Simplify the transition logic. - Only override startAcitivtyForResult() as other methods will also fall to that one. Bug: 187542491 Test: rebuild and navigate through pages Change-Id: I2d5cf0c3deaa858d44c4330600e88b0f33ce0594 --- .../settings/core/SettingsBaseActivity.java | 76 ++----------------- 1 file changed, 7 insertions(+), 69 deletions(-) diff --git a/src/com/android/settings/core/SettingsBaseActivity.java b/src/com/android/settings/core/SettingsBaseActivity.java index 8caae71b65f..c5d86e1cacd 100644 --- a/src/com/android/settings/core/SettingsBaseActivity.java +++ b/src/com/android/settings/core/SettingsBaseActivity.java @@ -163,85 +163,23 @@ public class SettingsBaseActivity extends FragmentActivity { return super.onOptionsItemSelected(item); } - @Override - public void startActivity(Intent intent) { - if (!Utils.isPageTransitionEnabled(this)) { - super.startActivity(intent); - return; - } - - final int transitionType = getTransitionType(intent); - if (transitionType == TransitionType.TRANSITION_SLIDE) { - super.startActivity(intent, null); - overridePendingTransition(R.anim.sud_slide_next_in, R.anim.sud_slide_next_out); - return; - } else if (transitionType == TransitionType.TRANSITION_NONE) { - super.startActivity(intent, null); - return; - } else if (transitionType == TransitionType.TRANSITION_FADE) { - super.startActivity(intent, null); - overridePendingTransition(android.R.anim.fade_in, R.anim.sud_stay); - return; - } - super.startActivity(intent, createActivityOptionsBundleForTransition(null)); - } - - @Override - public void startActivity(Intent intent, @androidx.annotation.Nullable Bundle options) { - final int transitionType = getTransitionType(intent); - if (!Utils.isPageTransitionEnabled(this) || - transitionType == TransitionType.TRANSITION_NONE) { - super.startActivity(intent, options); - return; - } - - if (transitionType == TransitionType.TRANSITION_SLIDE) { - super.startActivity(intent, options); - overridePendingTransition(R.anim.sud_slide_next_in, R.anim.sud_slide_next_out); - return; - } - super.startActivity(intent, createActivityOptionsBundleForTransition(options)); - } - - @Override - public void startActivityForResult(Intent intent, int requestCode) { - final int transitionType = getTransitionType(intent); - // startActivity() will eventually calls startActivityForResult() with requestCode -1. - // Adding this condition to avoid multiple calls. - if (!Utils.isPageTransitionEnabled(this) || requestCode == DEFAULT_REQUEST - || transitionType == TransitionType.TRANSITION_NONE) { - super.startActivityForResult(intent, requestCode); - return; - } - - if (transitionType == TransitionType.TRANSITION_SLIDE) { - super.startActivityForResult(intent, requestCode, null); - overridePendingTransition(R.anim.sud_slide_next_in, R.anim.sud_slide_next_out); - return; - } - - super.startActivityForResult(intent, requestCode, - createActivityOptionsBundleForTransition(null)); - } - @Override public void startActivityForResult(Intent intent, int requestCode, @androidx.annotation.Nullable Bundle options) { final int transitionType = getTransitionType(intent); - if (!Utils.isPageTransitionEnabled(this) || requestCode == DEFAULT_REQUEST - || transitionType == TransitionType.TRANSITION_NONE) { - super.startActivityForResult(intent, requestCode, options); + if (Utils.isPageTransitionEnabled(this) && + transitionType == TransitionType.TRANSITION_SHARED_AXIS) { + super.startActivityForResult(intent, requestCode, + createActivityOptionsBundleForTransition(options)); return; } + super.startActivityForResult(intent, requestCode, options); if (transitionType == TransitionType.TRANSITION_SLIDE) { - super.startActivityForResult(intent, requestCode, options); overridePendingTransition(R.anim.sud_slide_next_in, R.anim.sud_slide_next_out); - return; + } else if (transitionType == TransitionType.TRANSITION_FADE) { + overridePendingTransition(android.R.anim.fade_in, R.anim.sud_stay); } - - super.startActivityForResult(intent, requestCode, - createActivityOptionsBundleForTransition(options)); } @Override From 7b8c367d4f811d3d7a7ba4d2cc2edb14c15f5359 Mon Sep 17 00:00:00 2001 From: Weng Su Date: Mon, 24 May 2021 22:57:30 +0800 Subject: [PATCH 20/23] [Provider model] Add "Turn off/on Wi-Fi" link to Internet Panel - Replace the left menu button with "Turn off/on Wi-Fi" - Remove the TurnOnWifiSlice - Show "Wi-Fi is off" sub-title when Wi-Fi is disabled - Remove the "Wi\u-Fi is turned on" sub-title when APM is on. Bug: 188710392 Test: manual test atest -c InternetConnectivityPanelTest make RunSettingsRoboTests ROBOTEST_FILTER=com.android.settings.panel Change-Id: I53e200f6cadf8b712bf794bcbd5ff79f0f239cc0 --- res/values/strings.xml | 6 +- .../settings/network/TurnOnWifiSlice.java | 147 ------------------ .../panel/InternetConnectivityPanel.java | 57 +++---- .../android/settings/panel/PanelContent.java | 6 +- .../android/settings/panel/PanelFragment.java | 4 +- .../settings/slices/CustomSliceRegistry.java | 2 - .../settings/network/TurnOnWifiSliceTest.java | 85 ---------- .../panel/InternetConnectivityPanelTest.java | 141 +++++++---------- 8 files changed, 90 insertions(+), 358 deletions(-) delete mode 100644 src/com/android/settings/network/TurnOnWifiSlice.java delete mode 100644 tests/unit/src/com/android/settings/network/TurnOnWifiSliceTest.java diff --git a/res/values/strings.xml b/res/values/strings.xml index 34b8c2258b3..a53803b4558 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -13201,6 +13201,8 @@ network connection, internet, wireless, data, wifi, wi-fi, wi fi, cellular, mobile, cell carrier, 4g, 3g, 2g, lte Turn on Wi\u2011Fi + + Turn off Wi\u2011Fi Reset your internet? @@ -13215,8 +13217,8 @@ Networks available To switch networks, disconnect ethernet - - Wi\u2011Fi is turned on + + Wi\u2011Fi is off Tap a network to connect diff --git a/src/com/android/settings/network/TurnOnWifiSlice.java b/src/com/android/settings/network/TurnOnWifiSlice.java deleted file mode 100644 index 05a873fef0c..00000000000 --- a/src/com/android/settings/network/TurnOnWifiSlice.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - * 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.network; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.graphics.Color; -import android.graphics.drawable.ColorDrawable; -import android.graphics.drawable.Drawable; -import android.net.Uri; -import android.net.wifi.WifiManager; -import android.util.Log; - -import androidx.core.graphics.drawable.IconCompat; -import androidx.slice.Slice; -import androidx.slice.builders.ListBuilder; -import androidx.slice.builders.ListBuilder.RowBuilder; -import androidx.slice.builders.SliceAction; -import androidx.slice.core.SliceHints; - -import com.android.settings.R; -import com.android.settings.Utils; -import com.android.settings.slices.CustomSliceRegistry; -import com.android.settings.slices.CustomSliceable; -import com.android.settings.slices.SliceBackgroundWorker; -import com.android.settings.slices.SliceBroadcastReceiver; - -/** - * {@link CustomSliceable} for turning on Wi-Fi, used by generic clients. - */ -public class TurnOnWifiSlice implements CustomSliceable { - - private static final String TAG = "TurnOnWifiSlice"; - - private final Context mContext; - private final WifiManager mWifiManager; - - public TurnOnWifiSlice(Context context) { - mContext = context; - mWifiManager = mContext.getSystemService(WifiManager.class); - } - - private static void logd(String s) { - Log.d(TAG, s); - } - - @Override - public Slice getSlice() { - if (mWifiManager.isWifiEnabled()) { - return null; - } - final String title = mContext.getText(R.string.turn_on_wifi).toString(); - final SliceAction primaryAction = SliceAction.create(getBroadcastIntent(mContext), - getEndIcon(), ListBuilder.ICON_IMAGE, title); - final ListBuilder listBuilder = new ListBuilder(mContext, getUri(), ListBuilder.INFINITY) - .addRow(new RowBuilder() - .setTitle(title) - .addEndItem(getEndIcon(), SliceHints.ICON_IMAGE) - .setPrimaryAction(primaryAction)); - return listBuilder.build(); - } - - @Override - public Uri getUri() { - return CustomSliceRegistry.TURN_ON_WIFI_SLICE_URI; - } - - @Override - public void onNotifyChange(Intent intent) { - logd("Action: turn on Wi-Fi networks"); - mWifiManager.setWifiEnabled(true); - } - - @Override - public Intent getIntent() { - return new Intent(getUri().toString()) - .setData(getUri()) - .setClass(mContext, SliceBroadcastReceiver.class); - } - - private IconCompat getEndIcon() { - final Drawable drawable = mContext.getDrawable(R.drawable.ic_settings_wireless); - if (drawable == null) { - return Utils.createIconWithDrawable(new ColorDrawable(Color.TRANSPARENT)); - } - drawable.setTintList(Utils.getColorAttr(mContext, android.R.attr.colorAccent)); - return Utils.createIconWithDrawable(drawable); - } - - @Override - public Class getBackgroundWorkerClass() { - return TurnOnWifiWorker.class; - } - - /** - * The Slice background worker {@link SliceBackgroundWorker} is used to listen the Wi-Fi - * status change, and then notifies the Slice {@link Uri} to update. - */ - public static class TurnOnWifiWorker extends SliceBackgroundWorker { - - private final IntentFilter mIntentFilter; - private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(intent.getAction())) { - notifySliceChange(); - } - } - }; - - public TurnOnWifiWorker(Context context, Uri uri) { - super(context, uri); - mIntentFilter = new IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION); - } - - @Override - protected void onSlicePinned() { - getContext().registerReceiver(mBroadcastReceiver, mIntentFilter); - } - - @Override - protected void onSliceUnpinned() { - getContext().unregisterReceiver(mBroadcastReceiver); - } - - @Override - public void close() { - // Do nothing. - } - } -} diff --git a/src/com/android/settings/panel/InternetConnectivityPanel.java b/src/com/android/settings/panel/InternetConnectivityPanel.java index a6c18a5b749..e6344d806c2 100644 --- a/src/com/android/settings/panel/InternetConnectivityPanel.java +++ b/src/com/android/settings/panel/InternetConnectivityPanel.java @@ -19,8 +19,6 @@ package com.android.settings.panel; import static androidx.lifecycle.Lifecycle.Event.ON_PAUSE; import static androidx.lifecycle.Lifecycle.Event.ON_RESUME; -import static com.android.settings.network.NetworkProviderSettings.ACTION_NETWORK_PROVIDER_SETTINGS; - import android.app.settings.SettingsEnums; import android.content.BroadcastReceiver; import android.content.Context; @@ -32,7 +30,6 @@ import android.net.wifi.WifiManager; import android.os.Handler; import android.os.HandlerExecutor; import android.os.Looper; -import android.provider.Settings; import android.telephony.ServiceState; import android.telephony.SubscriptionManager; import android.telephony.TelephonyCallback; @@ -41,6 +38,7 @@ import android.text.TextUtils; import android.util.Log; import androidx.annotation.VisibleForTesting; +import androidx.fragment.app.FragmentActivity; import androidx.lifecycle.LifecycleObserver; import androidx.lifecycle.OnLifecycleEvent; @@ -64,7 +62,7 @@ public class InternetConnectivityPanel implements PanelContent, LifecycleObserve SubscriptionsChangeListener.SubscriptionsChangeListenerClient { private static final String TAG = "InternetConnectivityPanel"; private static final int SUBTITLE_TEXT_NONE = -1; - private static final int SUBTITLE_TEXT_WIFI_IS_TURNED_ON = R.string.wifi_is_turned_on_subtitle; + private static final int SUBTITLE_TEXT_WIFI_IS_OFF = R.string.wifi_is_off; private static final int SUBTITLE_TEXT_TAP_A_NETWORK_TO_CONNECT = R.string.tap_a_network_to_connect; private static final int SUBTITLE_TEXT_SEARCHING_FOR_NETWORKS = @@ -198,7 +196,6 @@ public class InternetConnectivityPanel implements PanelContent, LifecycleObserve final List uris = new ArrayList<>(); if (mIsProviderModelEnabled) { uris.add(CustomSliceRegistry.PROVIDER_MODEL_SLICE_URI); - uris.add(CustomSliceRegistry.TURN_ON_WIFI_SLICE_URI); } else { uris.add(CustomSliceRegistry.WIFI_SLICE_URI); uris.add(CustomSliceRegistry.MOBILE_DATA_SLICE_URI); @@ -209,9 +206,7 @@ public class InternetConnectivityPanel implements PanelContent, LifecycleObserve @Override public Intent getSeeMoreIntent() { - return new Intent(mIsProviderModelEnabled - ? ACTION_NETWORK_PROVIDER_SETTINGS : Settings.ACTION_WIRELESS_SETTINGS) - .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + return null; } @Override @@ -221,15 +216,14 @@ public class InternetConnectivityPanel implements PanelContent, LifecycleObserve @Override public CharSequence getCustomizedButtonTitle() { - if (mInternetUpdater.isAirplaneModeOn() && !mInternetUpdater.isWifiEnabled()) { - return null; - } - return mContext.getText(R.string.settings_button); + return mContext.getText( + mInternetUpdater.isWifiEnabled() ? R.string.turn_off_wifi : R.string.turn_on_wifi); } @Override - public void onClickCustomizedButton() { - mContext.startActivity(getSeeMoreIntent()); + public void onClickCustomizedButton(FragmentActivity panelActivity) { + // Don't finish the panel activity + mWifiManager.setWifiEnabled(!mInternetUpdater.isWifiEnabled()); } @Override @@ -290,15 +284,7 @@ public class InternetConnectivityPanel implements PanelContent, LifecycleObserve return; } updateSubtitleText(); - - log("Subtitle:" + mSubtitle); - if (mSubtitle != SUBTITLE_TEXT_NONE) { - mCallback.onHeaderChanged(); - } else { - // Other situations. - // Title: Airplane mode / Internet - mCallback.onTitleChanged(); - } + mCallback.onHeaderChanged(); mCallback.onCustomizedButtonStateChanged(); } @@ -310,15 +296,23 @@ public class InternetConnectivityPanel implements PanelContent, LifecycleObserve private void updateSubtitleText() { mSubtitle = SUBTITLE_TEXT_NONE; if (!mInternetUpdater.isWifiEnabled()) { + if (!mInternetUpdater.isAirplaneModeOn()) { + // When the airplane mode is off and Wi-Fi is disabled. + // Sub-Title: Wi-Fi is off + log("Airplane mode off + Wi-Fi off."); + mSubtitle = SUBTITLE_TEXT_WIFI_IS_OFF; + } + return; + } + + if (mIsProgressBarVisible) { + // When the Wi-Fi scan result callback is received + // Sub-Title: Searching for networks... + mSubtitle = SUBTITLE_TEXT_SEARCHING_FOR_NETWORKS; return; } if (mInternetUpdater.isAirplaneModeOn()) { - // When the airplane mode is on and Wi-Fi is enabled. - // Title: Airplane mode - // Sub-Title: Wi-Fi is turned on - log("Airplane mode is on + Wi-Fi on."); - mSubtitle = SUBTITLE_TEXT_WIFI_IS_TURNED_ON; return; } @@ -330,13 +324,6 @@ public class InternetConnectivityPanel implements PanelContent, LifecycleObserve return; } - if (mIsProgressBarVisible) { - // When the Wi-Fi scan result callback is received - // Sub-Title: Searching for networks... - mSubtitle = SUBTITLE_TEXT_SEARCHING_FOR_NETWORKS; - return; - } - // Sub-Title: // show non_carrier_network_unavailable // - while Wi-Fi on + no Wi-Fi item diff --git a/src/com/android/settings/panel/PanelContent.java b/src/com/android/settings/panel/PanelContent.java index 4c24182559d..6b582288457 100644 --- a/src/com/android/settings/panel/PanelContent.java +++ b/src/com/android/settings/panel/PanelContent.java @@ -20,6 +20,7 @@ import android.content.Intent; import android.net.Uri; import androidx.core.graphics.drawable.IconCompat; +import androidx.fragment.app.FragmentActivity; import com.android.settingslib.core.instrumentation.Instrumentable; @@ -94,8 +95,11 @@ public interface PanelContent extends Instrumentable { /** * Implement the click event for custom button. + * + * @param panelActivity the FragmentActivity from PanelFragment, the user can decide whether + * to finish activity or not. */ - default void onClickCustomizedButton() {} + default void onClickCustomizedButton(FragmentActivity panelActivity) {} /** * Register to start receiving callbacks for custom button events. diff --git a/src/com/android/settings/panel/PanelFragment.java b/src/com/android/settings/panel/PanelFragment.java index 31cb7b8d0ac..cd2bb50ce20 100644 --- a/src/com/android/settings/panel/PanelFragment.java +++ b/src/com/android/settings/panel/PanelFragment.java @@ -491,11 +491,11 @@ public class PanelFragment extends Fragment { mPanelClosedKey = PanelClosedKeys.KEY_SEE_MORE; final FragmentActivity activity = getActivity(); if (mPanel.isCustomizedButtonUsed()) { - mPanel.onClickCustomizedButton(); + mPanel.onClickCustomizedButton(activity); } else { activity.startActivityForResult(mPanel.getSeeMoreIntent(), 0); + activity.finish(); } - activity.finish(); }; } diff --git a/src/com/android/settings/slices/CustomSliceRegistry.java b/src/com/android/settings/slices/CustomSliceRegistry.java index 713d61a1ddd..d1b169c2976 100644 --- a/src/com/android/settings/slices/CustomSliceRegistry.java +++ b/src/com/android/settings/slices/CustomSliceRegistry.java @@ -40,7 +40,6 @@ import com.android.settings.location.LocationSlice; import com.android.settings.media.MediaOutputIndicatorSlice; import com.android.settings.media.RemoteMediaSlice; import com.android.settings.network.ProviderModelSlice; -import com.android.settings.network.TurnOnWifiSlice; import com.android.settings.network.telephony.MobileDataSlice; import com.android.settings.notification.zen.ZenModeButtonPreferenceController; import com.android.settings.wifi.calling.WifiCallingSliceHelper; @@ -337,7 +336,6 @@ public class CustomSliceRegistry { sUriToSlice.put(DARK_THEME_SLICE_URI, DarkThemeSlice.class); sUriToSlice.put(REMOTE_MEDIA_SLICE_URI, RemoteMediaSlice.class); sUriToSlice.put(ALWAYS_ON_SLICE_URI, AlwaysOnDisplaySlice.class); - sUriToSlice.put(TURN_ON_WIFI_SLICE_URI, TurnOnWifiSlice.class); } public static Class getSliceClassByUri(Uri uri) { diff --git a/tests/unit/src/com/android/settings/network/TurnOnWifiSliceTest.java b/tests/unit/src/com/android/settings/network/TurnOnWifiSliceTest.java deleted file mode 100644 index befa655ce97..00000000000 --- a/tests/unit/src/com/android/settings/network/TurnOnWifiSliceTest.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * 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.network; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import android.content.Context; -import android.content.Intent; -import android.net.wifi.WifiManager; - -import androidx.slice.SliceProvider; -import androidx.slice.widget.SliceLiveData; -import androidx.test.core.app.ApplicationProvider; -import androidx.test.ext.junit.runners.AndroidJUnit4; - -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.junit.MockitoJUnit; -import org.mockito.junit.MockitoRule; - -@RunWith(AndroidJUnit4.class) -public class TurnOnWifiSliceTest { - - @Rule - public MockitoRule mMocks = MockitoJUnit.rule(); - @Mock - private WifiManager mWifiManager; - - private Context mContext; - private TurnOnWifiSlice mSlice; - - @Before - public void setUp() { - mContext = spy(ApplicationProvider.getApplicationContext()); - when(mContext.getSystemService(Context.WIFI_SERVICE)).thenReturn(mWifiManager); - - // Set-up specs for SliceMetadata. - SliceProvider.setSpecs(SliceLiveData.SUPPORTED_SPECS); - mSlice = new TurnOnWifiSlice(mContext); - } - - @Test - public void getSlice_wifiEnabled_shouldBeNull() { - when(mWifiManager.isWifiEnabled()).thenReturn(true); - - assertThat(mSlice.getSlice()).isNull(); - } - - @Test - public void getSlice_wifiDisabled_shouldBeNotNull() { - when(mWifiManager.isWifiEnabled()).thenReturn(false); - - assertThat(mSlice.getSlice()).isNotNull(); - } - - @Test - public void onNotifyChange_shouldSetWifiEnabled() { - Intent intent = mSlice.getIntent(); - - mSlice.onNotifyChange(intent); - - verify(mWifiManager).setWifiEnabled(true); - } -} diff --git a/tests/unit/src/com/android/settings/panel/InternetConnectivityPanelTest.java b/tests/unit/src/com/android/settings/panel/InternetConnectivityPanelTest.java index 150c99e2945..e475e6fe1db 100644 --- a/tests/unit/src/com/android/settings/panel/InternetConnectivityPanelTest.java +++ b/tests/unit/src/com/android/settings/panel/InternetConnectivityPanelTest.java @@ -34,6 +34,7 @@ import android.net.wifi.ScanResult; import android.net.wifi.WifiManager; import android.os.Handler; +import androidx.fragment.app.FragmentActivity; import androidx.test.core.app.ApplicationProvider; import androidx.test.ext.junit.runners.AndroidJUnit4; @@ -61,19 +62,22 @@ public class InternetConnectivityPanelTest { ApplicationProvider.getApplicationContext(), "provider_internet_settings"); public static final String TITLE_APM = ResourcesUtils.getResourcesString( ApplicationProvider.getApplicationContext(), "airplane_mode"); - public static final String SUBTITLE_WIFI_IS_TURNED_ON = ResourcesUtils.getResourcesString( - ApplicationProvider.getApplicationContext(), "wifi_is_turned_on_subtitle"); + public static final String SUBTITLE_TEXT_WIFI_IS_OFF = + ResourcesUtils.getResourcesString(ApplicationProvider.getApplicationContext(), + "wifi_is_off"); public static final String SUBTITLE_TEXT_TAP_A_NETWORK_TO_CONNECT = ResourcesUtils.getResourcesString(ApplicationProvider.getApplicationContext(), "tap_a_network_to_connect"); - public static final String BUTTON_SETTINGS = ResourcesUtils.getResourcesString( - ApplicationProvider.getApplicationContext(), "settings_button"); public static final String SUBTITLE_NON_CARRIER_NETWORK_UNAVAILABLE = ResourcesUtils.getResourcesString(ApplicationProvider.getApplicationContext(), "non_carrier_network_unavailable"); public static final String SUBTITLE_ALL_NETWORK_UNAVAILABLE = ResourcesUtils.getResourcesString(ApplicationProvider.getApplicationContext(), "all_network_unavailable"); + public static final String BUTTON_TURN_ON_WIFI = ResourcesUtils.getResourcesString( + ApplicationProvider.getApplicationContext(), "turn_on_wifi"); + public static final String BUTTON_TURN_OFF_WIFI = ResourcesUtils.getResourcesString( + ApplicationProvider.getApplicationContext(), "turn_off_wifi"); @Rule public final MockitoRule mMocks = MockitoJUnit.rule(); @@ -87,6 +91,8 @@ public class InternetConnectivityPanelTest { private WifiManager mWifiManager; @Mock private ProviderModelSliceHelper mProviderModelSliceHelper; + @Mock + private FragmentActivity mPanelActivity; private Context mContext; private InternetConnectivityPanel mPanel; @@ -128,13 +134,21 @@ public class InternetConnectivityPanelTest { } @Test - public void getSubTitle_apmOnWifiOn_shouldWifiIsTurnedOn() { + public void getSubTitle_apmOnWifiOn_shouldBeNull() { doReturn(true).when(mInternetUpdater).isAirplaneModeOn(); doReturn(true).when(mInternetUpdater).isWifiEnabled(); + assertThat(mPanel.getSubTitle()).isNull(); + } + + @Test + public void getSubTitle_apmOffWifiOff_wifiIsOn() { + doReturn(false).when(mInternetUpdater).isAirplaneModeOn(); + doReturn(false).when(mInternetUpdater).isWifiEnabled(); + mPanel.updatePanelTitle(); - assertThat(mPanel.getSubTitle()).isEqualTo(SUBTITLE_WIFI_IS_TURNED_ON); + assertThat(mPanel.getSubTitle()).isEqualTo(SUBTITLE_TEXT_WIFI_IS_OFF); } @Test @@ -190,26 +204,17 @@ public class InternetConnectivityPanelTest { } @Test - public void getCustomizedButtonTitle_apmOff_shouldBeSettings() { - doReturn(false).when(mInternetUpdater).isAirplaneModeOn(); - - assertThat(mPanel.getCustomizedButtonTitle()).isEqualTo(BUTTON_SETTINGS); - } - - @Test - public void getCustomizedButtonTitle_apmOnWifiOff_shouldBeNull() { - doReturn(true).when(mInternetUpdater).isAirplaneModeOn(); + public void getCustomizedButtonTitle_wifiOff_turnOnWifi() { doReturn(false).when(mInternetUpdater).isWifiEnabled(); - assertThat(mPanel.getCustomizedButtonTitle()).isNull(); + assertThat(mPanel.getCustomizedButtonTitle()).isEqualTo(BUTTON_TURN_ON_WIFI); } @Test - public void getCustomizedButtonTitle_apmOnWifiOn_shouldBeSettings() { - doReturn(true).when(mInternetUpdater).isAirplaneModeOn(); + public void getCustomizedButtonTitle_wifiOn_turnOffWifi() { doReturn(true).when(mInternetUpdater).isWifiEnabled(); - assertThat(mPanel.getCustomizedButtonTitle()).isEqualTo(BUTTON_SETTINGS); + assertThat(mPanel.getCustomizedButtonTitle()).isEqualTo(BUTTON_TURN_OFF_WIFI); } @Test @@ -227,92 +232,60 @@ public class InternetConnectivityPanelTest { public void getSlices_providerModelEnabled_containsNecessarySlices() { List uris = mPanel.getSlices(); - assertThat(uris).containsExactly( - CustomSliceRegistry.PROVIDER_MODEL_SLICE_URI, - CustomSliceRegistry.TURN_ON_WIFI_SLICE_URI); + assertThat(uris).containsExactly(CustomSliceRegistry.PROVIDER_MODEL_SLICE_URI); } @Test - public void getSeeMoreIntent_notNull() { - assertThat(mPanel.getSeeMoreIntent()).isNotNull(); + public void getSeeMoreIntent_shouldBeNull() { + assertThat(mPanel.getSeeMoreIntent()).isNull(); } @Test - public void onAirplaneModeOn_apmOff_onTitleChanged() { - doReturn(false).when(mInternetUpdater).isAirplaneModeOn(); - clearInvocations(mPanelContentCallback); - - mPanel.onAirplaneModeChanged(false); - - verify(mPanelContentCallback).onTitleChanged(); - } - - @Test - public void onAirplaneModeOn_apmOnWifiOff_onTitleChanged() { - doReturn(true).when(mInternetUpdater).isAirplaneModeOn(); - doReturn(false).when(mInternetUpdater).isWifiEnabled(); - clearInvocations(mPanelContentCallback); - - mPanel.onAirplaneModeChanged(true); - - verify(mPanelContentCallback).onTitleChanged(); - } - - @Test - public void onAirplaneModeOn_apmOnWifiOn_onHeaderChanged() { - doReturn(true).when(mInternetUpdater).isAirplaneModeOn(); + public void onClickCustomizedButton_wifiOn_setWifiOff() { doReturn(true).when(mInternetUpdater).isWifiEnabled(); + + mPanel.onClickCustomizedButton(mPanelActivity); + + verify(mWifiManager).setWifiEnabled(false); + } + + @Test + public void onClickCustomizedButton_wifiOff_setWifiOn() { + doReturn(false).when(mInternetUpdater).isWifiEnabled(); + + mPanel.onClickCustomizedButton(mPanelActivity); + + verify(mWifiManager).setWifiEnabled(true); + } + + @Test + public void onClickCustomizedButton_shouldNotFinishActivity() { + mPanel.onClickCustomizedButton(mPanelActivity); + + verify(mPanelActivity, never()).finish(); + } + + @Test + public void updatePanelTitle_onHeaderChanged() { clearInvocations(mPanelContentCallback); - mPanel.onAirplaneModeChanged(true); + mPanel.updatePanelTitle(); verify(mPanelContentCallback).onHeaderChanged(); } @Test - public void onAirplaneModeOn_onCustomizedButtonStateChanged() { - doReturn(true).when(mInternetUpdater).isAirplaneModeOn(); + public void onWifiEnabledChanged_wifiOff_onCustomizedButtonStateChanged() { + doReturn(false).when(mInternetUpdater).isWifiEnabled(); clearInvocations(mPanelContentCallback); - mPanel.onAirplaneModeChanged(true); + mPanel.onWifiEnabledChanged(false); verify(mPanelContentCallback).onCustomizedButtonStateChanged(); } @Test - public void onWifiEnabledChanged_apmOff_onTitleChanged() { - doReturn(false).when(mInternetUpdater).isAirplaneModeOn(); - clearInvocations(mPanelContentCallback); - - mPanel.onWifiEnabledChanged(false); - - verify(mPanelContentCallback).onTitleChanged(); - } - - @Test - public void onWifiEnabledChanged_apmOnWifiOff_onTitleChanged() { - doReturn(true).when(mInternetUpdater).isAirplaneModeOn(); - doReturn(false).when(mInternetUpdater).isWifiEnabled(); - clearInvocations(mPanelContentCallback); - - mPanel.onWifiEnabledChanged(true); - - verify(mPanelContentCallback).onTitleChanged(); - } - - @Test - public void onWifiEnabledChanged_apmOnWifiOn_onHeaderChanged() { - doReturn(true).when(mInternetUpdater).isAirplaneModeOn(); - doReturn(true).when(mInternetUpdater).isWifiEnabled(); - clearInvocations(mPanelContentCallback); - - mPanel.onWifiEnabledChanged(true); - - verify(mPanelContentCallback).onHeaderChanged(); - } - - @Test - public void onWifiEnabledChanged_onCustomizedButtonStateChanged() { + public void onWifiEnabledChanged_wifiOn_onCustomizedButtonStateChanged() { doReturn(true).when(mInternetUpdater).isWifiEnabled(); clearInvocations(mPanelContentCallback); From 51b6605aef154bbbdb208c3c221c5eeea188ebbc Mon Sep 17 00:00:00 2001 From: Hugh Chen Date: Tue, 25 May 2021 11:26:08 +0800 Subject: [PATCH 21/23] Fix connected devices settings jank issue Completed the UI in displayPreference() to fix jank issue. Bug: 188752628 Test: make RunSettingsRoboTests Change-Id: Ib97b76e1b8622424ad481597f63d3540fb0bfc5b --- res/xml/connected_devices.xml | 13 +- ...toothDeviceRenamePreferenceController.java | 6 + .../AddDevicePreferenceController.java | 14 +- .../AddDeviceSummaryPreferenceController.java | 39 ----- ...lyConnectedDevicePreferenceController.java | 1 + .../AddDevicePreferenceControllerTest.java | 9 +- ...DeviceSummaryPreferenceControllerTest.java | 151 ------------------ 7 files changed, 16 insertions(+), 217 deletions(-) delete mode 100644 src/com/android/settings/connecteddevice/AddDeviceSummaryPreferenceController.java delete mode 100644 tests/robotests/src/com/android/settings/connecteddevice/AddDeviceSummaryPreferenceControllerTest.java diff --git a/res/xml/connected_devices.xml b/res/xml/connected_devices.xml index 75878f90ae0..e7e3c2ccfbe 100644 --- a/res/xml/connected_devices.xml +++ b/res/xml/connected_devices.xml @@ -40,24 +40,13 @@ android:key="add_bt_devices" android:title="@string/bluetooth_pairing_pref_title" android:icon="@drawable/ic_add_24dp" - android:fragment="com.android.settings.bluetooth.BluetoothPairingDetail" - settings:allowDividerAbove="true" - settings:keywords="@string/keywords_add_bt_device" - settings:userRestriction="no_config_bluetooth" - settings:useAdminDisabledSummary="true" - settings:controller="com.android.settings.connecteddevice.AddDevicePreferenceController"/> - - + settings:controller="com.android.settings.connecteddevice.AddDevicePreferenceController"/> Date: Wed, 26 May 2021 05:29:20 +0800 Subject: [PATCH 22/23] [Provider model] Add "See all" text link to Internet Panel - Add "See all" text link at the bottom of the network providers list - Don't show "See all" text link if the Wi-Fi network is empty Bug: 188710392 Test: manual test atest -c ProviderModelSliceTest Change-Id: If99c1e6597b4d2ef6a916fbdab3df9cfad8b464e --- res/drawable/ic_arrow_forward.xml | 26 +++++++++++++ .../settings/network/ProviderModelSlice.java | 31 ++++++++++++++- .../telephony/NetworkProviderWorker.java | 2 +- .../network/ProviderModelSliceTest.java | 38 ++++++++++++++----- 4 files changed, 85 insertions(+), 12 deletions(-) create mode 100644 res/drawable/ic_arrow_forward.xml diff --git a/res/drawable/ic_arrow_forward.xml b/res/drawable/ic_arrow_forward.xml new file mode 100644 index 00000000000..078cb693837 --- /dev/null +++ b/res/drawable/ic_arrow_forward.xml @@ -0,0 +1,26 @@ + + + + diff --git a/src/com/android/settings/network/ProviderModelSlice.java b/src/com/android/settings/network/ProviderModelSlice.java index 6b6180b3c5e..b778a05a96c 100644 --- a/src/com/android/settings/network/ProviderModelSlice.java +++ b/src/com/android/settings/network/ProviderModelSlice.java @@ -22,9 +22,12 @@ import static android.app.slice.Slice.EXTRA_TOGGLE_STATE; import static com.android.settings.slices.CustomSliceRegistry.PROVIDER_MODEL_SLICE_URI; import android.annotation.ColorInt; +import android.app.PendingIntent; import android.app.settings.SettingsEnums; import android.content.Context; import android.content.Intent; +import android.graphics.Color; +import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.net.Uri; import android.telephony.SubscriptionManager; @@ -150,11 +153,12 @@ public class ProviderModelSlice extends WifiSlice { final List disconnectedWifiList = wifiList.stream() .filter(wifiSliceItem -> wifiSliceItem.getConnectedState() != WifiEntry.CONNECTED_STATE_CONNECTED) - .limit(maxListSize) + .limit(maxListSize - 1) .collect(Collectors.toList()); for (WifiSliceItem item : disconnectedWifiList) { listBuilder.addRow(getWifiSliceItemRow(item)); } + listBuilder.addRow(getSeeAllRow()); } return listBuilder.build(); } @@ -252,6 +256,31 @@ public class ProviderModelSlice extends WifiSlice { .setSubtitle(mContext.getText(R.string.to_switch_networks_disconnect_ethernet)); } + protected ListBuilder.RowBuilder getSeeAllRow() { + final CharSequence title = mContext.getText(R.string.previous_connected_see_all); + final IconCompat icon = getSeeAllIcon(); + return new ListBuilder.RowBuilder() + .setTitleItem(icon, ListBuilder.ICON_IMAGE) + .setTitle(title) + .setPrimaryAction(getPrimaryAction(icon, title)); + } + + protected IconCompat getSeeAllIcon() { + final Drawable drawable = mContext.getDrawable(R.drawable.ic_arrow_forward); + if (drawable != null) { + drawable.setTint( + Utils.getColorAttrDefaultColor(mContext, android.R.attr.colorControlNormal)); + return Utils.createIconWithDrawable(drawable); + } + return Utils.createIconWithDrawable(new ColorDrawable(Color.TRANSPARENT)); + } + + protected SliceAction getPrimaryAction(IconCompat icon, CharSequence title) { + final PendingIntent intent = PendingIntent.getActivity(mContext, 0 /* requestCode */, + getIntent(), PendingIntent.FLAG_IMMUTABLE /* flags */); + return SliceAction.createDeeplink(intent, icon, ListBuilder.ICON_IMAGE, title); + } + @Override protected ListBuilder.RowBuilder getWifiSliceItemRow(WifiSliceItem wifiSliceItem) { final CharSequence title = wifiSliceItem.getTitle(); diff --git a/src/com/android/settings/network/telephony/NetworkProviderWorker.java b/src/com/android/settings/network/telephony/NetworkProviderWorker.java index 464ee75cc7d..49d286d6e5b 100644 --- a/src/com/android/settings/network/telephony/NetworkProviderWorker.java +++ b/src/com/android/settings/network/telephony/NetworkProviderWorker.java @@ -54,7 +54,7 @@ public class NetworkProviderWorker extends WifiScanWorker implements DataConnectivityListener.Client, InternetUpdater.InternetChangeListener, SubscriptionsChangeListener.SubscriptionsChangeListenerClient { private static final String TAG = "NetworkProviderWorker"; - private static final int PROVIDER_MODEL_DEFAULT_EXPANDED_ROW_COUNT = 4; + private static final int PROVIDER_MODEL_DEFAULT_EXPANDED_ROW_COUNT = 5; private DataContentObserver mMobileDataObserver; private SignalStrengthListener mSignalStrengthListener; private SubscriptionsChangeListener mSubscriptionsListener; diff --git a/tests/unit/src/com/android/settings/network/ProviderModelSliceTest.java b/tests/unit/src/com/android/settings/network/ProviderModelSliceTest.java index 4b06acfb66c..fb17e34a9bc 100644 --- a/tests/unit/src/com/android/settings/network/ProviderModelSliceTest.java +++ b/tests/unit/src/com/android/settings/network/ProviderModelSliceTest.java @@ -153,6 +153,7 @@ public class ProviderModelSliceTest { assertThat(slice).isNotNull(); verify(mListBuilder, times(1)).addRow(mMockCarrierRowBuild); + assertThat(mMockProviderModelSlice.hasSeeAllRow()).isFalse(); } @Test @@ -166,11 +167,12 @@ public class ProviderModelSliceTest { assertThat(slice).isNotNull(); verify(mListBuilder, times(1)).addRow(mMockCarrierRowBuild); + assertThat(mMockProviderModelSlice.hasSeeAllRow()).isFalse(); } @Test @UiThreadTest - public void getSlice_haveTwoWifiAndOneCarrier_getCarrierAndTwoWiFi() { + public void getSlice_haveTwoWifiAndOneCarrier_getCarrierAndTwoWiFiAndSeeAll() { mWifiList.clear(); mockWifiItemCondition(mMockWifiSliceItem1, "wifi1", "wifi1", WifiEntry.CONNECTED_STATE_CONNECTED, "wifi1_key", true); @@ -185,12 +187,13 @@ public class ProviderModelSliceTest { assertThat(slice).isNotNull(); verify(mListBuilder, times(1)).addRow(mMockCarrierRowBuild); - verify(mListBuilder, times(3)).addRow(any(ListBuilder.RowBuilder.class)); + verify(mListBuilder, times(4)).addRow(any(ListBuilder.RowBuilder.class)); + assertThat(mMockProviderModelSlice.hasSeeAllRow()).isTrue(); } @Test @UiThreadTest - public void getSlice_haveOneConnectedWifiAndTwoDisconnectedWifiAndNoCarrier_getTwoRow() { + public void getSlice_haveOneConnectedWifiAndTwoDisconnectedWifiAndNoCarrier_getFourRow() { mWifiList.clear(); mockWifiItemCondition(mMockWifiSliceItem1, "wifi1", "wifi1", WifiEntry.CONNECTED_STATE_CONNECTED, "wifi1_key", true); @@ -207,12 +210,13 @@ public class ProviderModelSliceTest { final Slice slice = mMockProviderModelSlice.getSlice(); assertThat(slice).isNotNull(); - verify(mListBuilder, times(3)).addRow(any(ListBuilder.RowBuilder.class)); + verify(mListBuilder, times(4)).addRow(any(ListBuilder.RowBuilder.class)); + assertThat(mMockProviderModelSlice.hasSeeAllRow()).isTrue(); } @Test @UiThreadTest - public void getSlice_haveTwoDisconnectedWifiAndNoCarrier_getTwoRow() { + public void getSlice_haveTwoDisconnectedWifiAndNoCarrier_getThreeRow() { mWifiList.clear(); mockWifiItemCondition(mMockWifiSliceItem1, "wifi1", "wifi1", WifiEntry.CONNECTED_STATE_DISCONNECTED, "wifi1_key", true); @@ -226,12 +230,13 @@ public class ProviderModelSliceTest { final Slice slice = mMockProviderModelSlice.getSlice(); assertThat(slice).isNotNull(); - verify(mListBuilder, times(2)).addRow(any(ListBuilder.RowBuilder.class)); + verify(mListBuilder, times(3)).addRow(any(ListBuilder.RowBuilder.class)); + assertThat(mMockProviderModelSlice.hasSeeAllRow()).isTrue(); } @Test @UiThreadTest - public void getSlice_haveEthernetAndCarrierAndTwoDisconnectedWifi_getFourRow() { + public void getSlice_haveEthernetAndCarrierAndTwoDisconnectedWifi_getFiveRow() { mWifiList.clear(); mockWifiItemCondition(mMockWifiSliceItem1, "wifi1", "wifi1", WifiEntry.CONNECTED_STATE_DISCONNECTED, "wifi1_key", true); @@ -249,12 +254,13 @@ public class ProviderModelSliceTest { assertThat(slice).isNotNull(); assertThat(mMockProviderModelSlice.hasCreateEthernetRow()).isTrue(); verify(mListBuilder, times(1)).addRow(mMockCarrierRowBuild); - verify(mListBuilder, times(4)).addRow(any(ListBuilder.RowBuilder.class)); + verify(mListBuilder, times(5)).addRow(any(ListBuilder.RowBuilder.class)); + assertThat(mMockProviderModelSlice.hasSeeAllRow()).isTrue(); } @Test @UiThreadTest - public void getSlice_haveEthernetAndCarrierAndConnectedWifiAndDisconnectedWifi_getFourRow() { + public void getSlice_haveEthernetAndCarrierAndConnectedWifiAndDisconnectedWifi_getFiveRow() { mWifiList.clear(); mockWifiItemCondition(mMockWifiSliceItem1, "wifi1", "wifi1", WifiEntry.CONNECTED_STATE_CONNECTED, "wifi1_key", true); @@ -272,7 +278,8 @@ public class ProviderModelSliceTest { assertThat(slice).isNotNull(); assertThat(mMockProviderModelSlice.hasCreateEthernetRow()).isTrue(); verify(mListBuilder, times(1)).addRow(mMockCarrierRowBuild); - verify(mListBuilder, times(4)).addRow(any(ListBuilder.RowBuilder.class)); + verify(mListBuilder, times(5)).addRow(any(ListBuilder.RowBuilder.class)); + assertThat(mMockProviderModelSlice.hasSeeAllRow()).isTrue(); } @Test @@ -334,6 +341,7 @@ public class ProviderModelSliceTest { public class MockProviderModelSlice extends ProviderModelSlice { private MockNetworkProviderWorker mNetworkProviderWorker; private boolean mHasCreateEthernetRow; + private boolean mHasSeeAllRow; MockProviderModelSlice(Context context, MockNetworkProviderWorker networkProviderWorker) { super(context); @@ -356,9 +364,19 @@ public class ProviderModelSliceTest { return super.createEthernetRow(); } + @Override + protected ListBuilder.RowBuilder getSeeAllRow() { + mHasSeeAllRow = true; + return super.getSeeAllRow(); + } + public boolean hasCreateEthernetRow() { return mHasCreateEthernetRow; } + + public boolean hasSeeAllRow() { + return mHasSeeAllRow; + } } @Test From 225607b6ebd2de17b4643d390b5bf54f5fd58552 Mon Sep 17 00:00:00 2001 From: Jay Aliomer Date: Wed, 26 May 2021 11:55:56 -0400 Subject: [PATCH 23/23] Rounded ripple notification history snoozed list currently the ripple has sharpe edges and outside the view bounds Fixes: b/187868531 Test: Visual Change-Id: Iedacc6b875fa3bc4319d5e81034777dd873f7e26 --- .../history/NotificationHistoryActivity.java | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/com/android/settings/notification/history/NotificationHistoryActivity.java b/src/com/android/settings/notification/history/NotificationHistoryActivity.java index 2c806688d1c..1d663fc1629 100644 --- a/src/com/android/settings/notification/history/NotificationHistoryActivity.java +++ b/src/com/android/settings/notification/history/NotificationHistoryActivity.java @@ -156,6 +156,7 @@ public class NotificationHistoryActivity extends CollapsingToolbarBaseActivity { View recyclerView = mTodayView.findViewById(R.id.apps); recyclerView.setClipToOutline(true); mTodayView.setOutlineProvider(mOutlineProvider); + mSnoozeView.setOutlineProvider(mOutlineProvider); // for each package, new header and recycler view for (int i = 0, notificationsSize = notifications.size(); i < notificationsSize; i++) { NotificationHistoryPackage nhp = notifications.get(i); @@ -219,6 +220,11 @@ public class NotificationHistoryActivity extends CollapsingToolbarBaseActivity { } }; + private void configureNotificationList(View recyclerView) { + recyclerView.setClipToOutline(true); + recyclerView.setOutlineProvider(mOutlineProvider); + } + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -227,9 +233,8 @@ public class NotificationHistoryActivity extends CollapsingToolbarBaseActivity { mTodayView = findViewById(R.id.apps); mSnoozeView = findViewById(R.id.snoozed_list); mDismissView = findViewById(R.id.recently_dismissed_list); - View recyclerView = mDismissView.findViewById(R.id.notification_list); - recyclerView.setClipToOutline(true); - recyclerView.setOutlineProvider(mOutlineProvider); + configureNotificationList(mDismissView.findViewById(R.id.notification_list)); + configureNotificationList(mSnoozeView.findViewById(R.id.notification_list)); mHistoryOff = findViewById(R.id.history_off); mHistoryOn = findViewById(R.id.history_on); mHistoryEmpty = findViewById(R.id.history_on_empty);