diff --git a/res/values/arrays.xml b/res/values/arrays.xml index a8bd35cd793..f8b7f008c60 100644 --- a/res/values/arrays.xml +++ b/res/values/arrays.xml @@ -1216,6 +1216,20 @@ 90 + + + @string/screensaver_settings_summary_sleep + @string/screensaver_settings_summary_dock_and_charging + + + + + while_charging_only + while_docked_only + + @string/screensaver_settings_summary_sleep @string/screensaver_settings_summary_dock diff --git a/res/values/strings.xml b/res/values/strings.xml index 42f8e4c0811..03a103e8125 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -3365,6 +3365,8 @@ Use screen saver While charging or docked + + While docked and charging While charging @@ -9895,6 +9897,9 @@ At your request, Android is blocking this group of notifications from appearing on this device + + This app does not send notifications + Categories diff --git a/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java b/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java index d92fb7fd99b..70fbefc36f4 100644 --- a/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java +++ b/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java @@ -60,6 +60,7 @@ import com.android.settings.development.bluetooth.BluetoothQualityDialogPreferen import com.android.settings.development.bluetooth.BluetoothSampleRateDialogPreferenceController; import com.android.settings.development.qstile.DevelopmentTiles; import com.android.settings.development.storage.SharedDataPreferenceController; +import com.android.settings.overlay.FeatureFactory; import com.android.settings.search.BaseSearchIndexProvider; import com.android.settings.search.actionbar.SearchMenuController; import com.android.settings.widget.SettingsMainSwitchBar; @@ -308,6 +309,8 @@ public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFra DisableDevSettingsDialogFragment.show(this /* host */); } } + FeatureFactory.getFactory( + getContext()).getSearchFeatureProvider().sendPreIndexIntent(getContext()); } } @@ -369,12 +372,12 @@ public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFra final BluetoothLeAudioHwOffloadPreferenceController leAudioController = getDevelopmentOptionsController( - BluetoothLeAudioHwOffloadPreferenceController.class); + BluetoothLeAudioHwOffloadPreferenceController.class); leAudioController.onRebootDialogConfirmed(); final BluetoothLeAudioPreferenceController leAudioFeatureController = getDevelopmentOptionsController( - BluetoothLeAudioPreferenceController.class); + BluetoothLeAudioPreferenceController.class); leAudioFeatureController.onRebootDialogConfirmed(); } @@ -386,12 +389,12 @@ public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFra final BluetoothLeAudioHwOffloadPreferenceController leAudioController = getDevelopmentOptionsController( - BluetoothLeAudioHwOffloadPreferenceController.class); + BluetoothLeAudioHwOffloadPreferenceController.class); leAudioController.onRebootDialogCanceled(); final BluetoothLeAudioPreferenceController leAudioFeatureController = getDevelopmentOptionsController( - BluetoothLeAudioPreferenceController.class); + BluetoothLeAudioPreferenceController.class); leAudioFeatureController.onRebootDialogCanceled(); } diff --git a/src/com/android/settings/deviceinfo/BuildNumberPreferenceController.java b/src/com/android/settings/deviceinfo/BuildNumberPreferenceController.java index 7ddca793f59..6af58b5bc6b 100644 --- a/src/com/android/settings/deviceinfo/BuildNumberPreferenceController.java +++ b/src/com/android/settings/deviceinfo/BuildNumberPreferenceController.java @@ -240,6 +240,8 @@ public class BuildNumberPreferenceController extends BasePreferenceController im mDevHitToast = Toast.makeText(mContext, R.string.show_dev_on, Toast.LENGTH_LONG); mDevHitToast.show(); + + FeatureFactory.getFactory(mContext).getSearchFeatureProvider().sendPreIndexIntent(mContext); } @VisibleForTesting diff --git a/src/com/android/settings/dream/DreamSettings.java b/src/com/android/settings/dream/DreamSettings.java index 1d12c1aecd5..580211a7d5b 100644 --- a/src/com/android/settings/dream/DreamSettings.java +++ b/src/com/android/settings/dream/DreamSettings.java @@ -90,12 +90,14 @@ public class DreamSettings extends DashboardFragment implements OnMainSwitchChan } } - static int getDreamSettingDescriptionResId(@WhenToDream int dreamSetting) { + static int getDreamSettingDescriptionResId(@WhenToDream int dreamSetting, + boolean enabledOnBattery) { switch (dreamSetting) { case WHILE_CHARGING: return R.string.screensaver_settings_summary_sleep; case WHILE_DOCKED: - return R.string.screensaver_settings_summary_dock; + return enabledOnBattery ? R.string.screensaver_settings_summary_dock + : R.string.screensaver_settings_summary_dock_and_charging; case EITHER: return R.string.screensaver_settings_summary_either_long; case NEVER: diff --git a/src/com/android/settings/dream/WhenToDreamPicker.java b/src/com/android/settings/dream/WhenToDreamPicker.java index 1c5e25ebac2..13cdadf1981 100644 --- a/src/com/android/settings/dream/WhenToDreamPicker.java +++ b/src/com/android/settings/dream/WhenToDreamPicker.java @@ -32,12 +32,15 @@ public class WhenToDreamPicker extends RadioButtonPickerFragment { private static final String TAG = "WhenToDreamPicker"; private DreamBackend mBackend; + private boolean mDreamsSupportedOnBattery; @Override public void onAttach(Context context) { super.onAttach(context); mBackend = DreamBackend.getInstance(context); + mDreamsSupportedOnBattery = getResources().getBoolean( + com.android.internal.R.bool.config_dreamsEnabledOnBattery); } @Override @@ -69,11 +72,17 @@ public class WhenToDreamPicker extends RadioButtonPickerFragment { } private String[] entries() { - return getResources().getStringArray(R.array.when_to_start_screensaver_entries); + if (mDreamsSupportedOnBattery) { + return getResources().getStringArray(R.array.when_to_start_screensaver_entries); + } + return getResources().getStringArray(R.array.when_to_start_screensaver_entries_no_battery); } private String[] keys() { - return getResources().getStringArray(R.array.when_to_start_screensaver_values); + if (mDreamsSupportedOnBattery) { + return getResources().getStringArray(R.array.when_to_start_screensaver_values); + } + return getResources().getStringArray(R.array.when_to_start_screensaver_values_no_battery); } @Override diff --git a/src/com/android/settings/dream/WhenToDreamPreferenceController.java b/src/com/android/settings/dream/WhenToDreamPreferenceController.java index 02ae6a75f39..c3bae0064c9 100644 --- a/src/com/android/settings/dream/WhenToDreamPreferenceController.java +++ b/src/com/android/settings/dream/WhenToDreamPreferenceController.java @@ -33,19 +33,24 @@ public class WhenToDreamPreferenceController extends AbstractPreferenceControlle private static final String WHEN_TO_START = "when_to_start"; private final DreamBackend mBackend; private final boolean mDreamsDisabledByAmbientModeSuppression; + private final boolean mDreamsEnabledOnBattery; WhenToDreamPreferenceController(Context context) { this(context, context.getResources().getBoolean( - com.android.internal.R.bool.config_dreamsDisabledByAmbientModeSuppressionConfig)); + com.android.internal.R.bool.config_dreamsDisabledByAmbientModeSuppressionConfig), + context.getResources().getBoolean( + com.android.internal.R.bool.config_dreamsEnabledOnBattery)); } @VisibleForTesting WhenToDreamPreferenceController(Context context, - boolean dreamsDisabledByAmbientModeSuppression) { + boolean dreamsDisabledByAmbientModeSuppression, + boolean dreamsEnabledOnBattery) { super(context); mBackend = DreamBackend.getInstance(context); mDreamsDisabledByAmbientModeSuppression = dreamsDisabledByAmbientModeSuppression; + mDreamsEnabledOnBattery = dreamsEnabledOnBattery; } @Override @@ -57,7 +62,7 @@ public class WhenToDreamPreferenceController extends AbstractPreferenceControlle preference.setSummary(R.string.screensaver_settings_when_to_dream_bedtime); } else { final int resId = DreamSettings.getDreamSettingDescriptionResId( - mBackend.getWhenToDreamSetting()); + mBackend.getWhenToDreamSetting(), mDreamsEnabledOnBattery); preference.setSummary(resId); } } diff --git a/src/com/android/settings/homepage/TopLevelSettings.java b/src/com/android/settings/homepage/TopLevelSettings.java index 70530fc8cd3..8c122ef2ad6 100644 --- a/src/com/android/settings/homepage/TopLevelSettings.java +++ b/src/com/android/settings/homepage/TopLevelSettings.java @@ -43,6 +43,7 @@ import com.android.settings.activityembedding.ActivityEmbeddingRulesController; import com.android.settings.activityembedding.ActivityEmbeddingUtils; import com.android.settings.core.SubSettingLauncher; import com.android.settings.dashboard.DashboardFragment; +import com.android.settings.overlay.FeatureFactory; import com.android.settings.search.BaseSearchIndexProvider; import com.android.settings.support.SupportPreferenceController; import com.android.settings.widget.HomepagePreference; @@ -157,6 +158,8 @@ public class TopLevelSettings extends DashboardFragment implements SplitLayoutLi public void onStart() { if (mFirstStarted) { mFirstStarted = false; + FeatureFactory.getFactory(getContext()).getSearchFeatureProvider().sendPreIndexIntent( + getContext()); } else if (mIsEmbeddingActivityEnabled && isOnlyOneActivityInTask() && !SplitController.getInstance().isActivityEmbedded(getActivity())) { // Set default highlight menu key for 1-pane homepage since it will show the placeholder @@ -346,7 +349,9 @@ public class TopLevelSettings extends DashboardFragment implements SplitLayoutLi } private interface PreferenceJob { - default void init() {} + default void init() { + } + void doForEach(Preference preference); } diff --git a/src/com/android/settings/notification/NotificationBackend.java b/src/com/android/settings/notification/NotificationBackend.java index 150dbe0483d..68f5d081d11 100644 --- a/src/com/android/settings/notification/NotificationBackend.java +++ b/src/com/android/settings/notification/NotificationBackend.java @@ -126,6 +126,7 @@ public class NotificationBackend { if (app.requestedPermissions == null || Arrays.stream(app.requestedPermissions) .noneMatch(p -> p.equals(android.Manifest.permission.POST_NOTIFICATIONS))) { row.lockedImportance = true; + row.permissionStateLocked = true; } } } @@ -684,6 +685,9 @@ public class NotificationBackend { public boolean systemApp; public boolean lockedImportance; public boolean showBadge; + // For apps target T but have not but has not requested the permission + // we cannot change the permission state + public boolean permissionStateLocked; public int bubblePreference = NotificationManager.BUBBLE_PREFERENCE_NONE; public int userId; public int blockedChannelCount; diff --git a/src/com/android/settings/notification/VibrateIconPreferenceController.java b/src/com/android/settings/notification/VibrateIconPreferenceController.java index 25d23264131..d772b47d59e 100644 --- a/src/com/android/settings/notification/VibrateIconPreferenceController.java +++ b/src/com/android/settings/notification/VibrateIconPreferenceController.java @@ -19,6 +19,7 @@ package com.android.settings.notification; import static com.android.settings.notification.SettingPref.TYPE_SECURE; import android.content.Context; +import android.os.Vibrator; import android.provider.Settings.Secure; import com.android.settings.SettingsPreferenceFragment; @@ -27,16 +28,18 @@ import com.android.settingslib.core.lifecycle.Lifecycle; public class VibrateIconPreferenceController extends SettingPrefController { private static final String KEY_VIBRATE_ICON = "vibrate_icon"; + private final boolean mHasVibrator; public VibrateIconPreferenceController(Context context, SettingsPreferenceFragment parent, Lifecycle lifecycle) { super(context, parent, lifecycle); + mHasVibrator = context.getSystemService(Vibrator.class).hasVibrator(); mPreference = new SettingPref( TYPE_SECURE, KEY_VIBRATE_ICON, Secure.STATUS_BAR_SHOW_VIBRATE_ICON, 0 /*default off*/); } @Override public boolean isAvailable() { - return true; + return mHasVibrator; } } diff --git a/src/com/android/settings/notification/app/NotificationsOffPreferenceController.java b/src/com/android/settings/notification/app/NotificationsOffPreferenceController.java index 0c7cd2361e2..04e3f0e311b 100644 --- a/src/com/android/settings/notification/app/NotificationsOffPreferenceController.java +++ b/src/com/android/settings/notification/app/NotificationsOffPreferenceController.java @@ -62,6 +62,8 @@ public class NotificationsOffPreferenceController extends NotificationPreference preference.setTitle(R.string.channel_notifications_off_desc); } else if (mChannelGroup != null) { preference.setTitle(R.string.channel_group_notifications_off_desc); + } else if (mAppRow.permissionStateLocked) { + preference.setTitle(R.string.app_notifications_not_send_desc); } else { preference.setTitle(R.string.app_notifications_off_desc); } diff --git a/src/com/android/settings/search/SearchFeatureProvider.java b/src/com/android/settings/search/SearchFeatureProvider.java index 1785361d3b2..b14a4d7fbf5 100644 --- a/src/com/android/settings/search/SearchFeatureProvider.java +++ b/src/com/android/settings/search/SearchFeatureProvider.java @@ -71,6 +71,12 @@ public interface SearchFeatureProvider { return context.getString(R.string.config_settingsintelligence_package_name); } + /** + * Send the pre-index intent. + */ + default void sendPreIndexIntent(Context context){ + } + /** * Initializes the search toolbar. */ diff --git a/tests/robotests/src/com/android/settings/dream/DreamSettingsTest.java b/tests/robotests/src/com/android/settings/dream/DreamSettingsTest.java index a5545645e9b..c1cc6ae043f 100644 --- a/tests/robotests/src/com/android/settings/dream/DreamSettingsTest.java +++ b/tests/robotests/src/com/android/settings/dream/DreamSettingsTest.java @@ -29,33 +29,40 @@ import com.android.settingslib.dream.DreamBackend.WhenToDream; import org.junit.Test; import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; import java.util.Arrays; import java.util.List; -import org.robolectric.RobolectricTestRunner; @RunWith(RobolectricTestRunner.class) public class DreamSettingsTest { private static final List KEYS = Arrays.asList( - DreamSettings.WHILE_CHARGING_ONLY, - DreamSettings.WHILE_DOCKED_ONLY, - DreamSettings.EITHER_CHARGING_OR_DOCKED, - DreamSettings.NEVER_DREAM + DreamSettings.WHILE_CHARGING_ONLY, + DreamSettings.WHILE_DOCKED_ONLY, + DreamSettings.EITHER_CHARGING_OR_DOCKED, + DreamSettings.NEVER_DREAM ); private static final @WhenToDream int[] SETTINGS = { - DreamBackend.WHILE_CHARGING, - DreamBackend.WHILE_DOCKED, - DreamBackend.EITHER, - DreamBackend.NEVER, + DreamBackend.WHILE_CHARGING, + DreamBackend.WHILE_DOCKED, + DreamBackend.EITHER, + DreamBackend.NEVER, }; private static final int[] RES_IDS = { - R.string.screensaver_settings_summary_sleep, - R.string.screensaver_settings_summary_dock, - R.string.screensaver_settings_summary_either_long, - R.string.screensaver_settings_summary_never + R.string.screensaver_settings_summary_sleep, + R.string.screensaver_settings_summary_dock, + R.string.screensaver_settings_summary_either_long, + R.string.screensaver_settings_summary_never + }; + + private static final int[] RES_IDS_NO_BATTERY = { + R.string.screensaver_settings_summary_sleep, + R.string.screensaver_settings_summary_dock_and_charging, + R.string.screensaver_settings_summary_either_long, + R.string.screensaver_settings_summary_never }; @Test @@ -81,11 +88,17 @@ public class DreamSettingsTest { @Test public void getDreamSettingDescriptionResId() { for (int i = 0; i < SETTINGS.length; i++) { - assertThat(DreamSettings.getDreamSettingDescriptionResId(SETTINGS[i])) + assertThat(DreamSettings.getDreamSettingDescriptionResId( + SETTINGS[i], /* enabledOnBattery= */ false)) + .isEqualTo(RES_IDS_NO_BATTERY[i]); + assertThat(DreamSettings.getDreamSettingDescriptionResId( + SETTINGS[i], /* enabledOnBattery= */ true)) .isEqualTo(RES_IDS[i]); } // Default - assertThat(DreamSettings.getDreamSettingDescriptionResId(-1)) + assertThat(DreamSettings.getDreamSettingDescriptionResId(-1, /* enabledOnBattery= */ false)) + .isEqualTo(R.string.screensaver_settings_summary_never); + assertThat(DreamSettings.getDreamSettingDescriptionResId(-1, /* enabledOnBattery= */ true)) .isEqualTo(R.string.screensaver_settings_summary_never); } diff --git a/tests/robotests/src/com/android/settings/dream/WhenToDreamPickerTest.java b/tests/robotests/src/com/android/settings/dream/WhenToDreamPickerTest.java index 16f8599f2f1..91ec2993893 100644 --- a/tests/robotests/src/com/android/settings/dream/WhenToDreamPickerTest.java +++ b/tests/robotests/src/com/android/settings/dream/WhenToDreamPickerTest.java @@ -28,6 +28,7 @@ import android.os.UserManager; import androidx.test.core.app.ApplicationProvider; import com.android.settings.testutils.FakeFeatureFactory; +import com.android.settings.testutils.shadow.SettingsShadowResources; import com.android.settingslib.dream.DreamBackend; import org.junit.Before; @@ -37,9 +38,11 @@ import org.mockito.Answers; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.robolectric.RobolectricTestRunner; +import org.robolectric.annotation.Config; import org.robolectric.util.ReflectionHelpers; @RunWith(RobolectricTestRunner.class) +@Config(shadows = SettingsShadowResources.class) public class WhenToDreamPickerTest { private WhenToDreamPicker mPicker; @@ -53,10 +56,15 @@ public class WhenToDreamPickerTest { MockitoAnnotations.initMocks(this); final Context context = spy(ApplicationProvider.getApplicationContext()); + SettingsShadowResources.overrideResource( + com.android.internal.R.bool.config_dreamsEnabledOnBattery, + true); + when(context.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager); FakeFeatureFactory.setupForTest(); - mPicker = new WhenToDreamPicker(); + mPicker = spy(new WhenToDreamPicker()); + when(mPicker.getContext()).thenReturn(context); mPicker.onAttach(context); ReflectionHelpers.setField(mPicker, "mBackend", mBackend); diff --git a/tests/robotests/src/com/android/settings/dream/WhenToDreamPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/dream/WhenToDreamPreferenceControllerTest.java index 458c5c6ceee..6e687bba7d9 100644 --- a/tests/robotests/src/com/android/settings/dream/WhenToDreamPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/dream/WhenToDreamPreferenceControllerTest.java @@ -64,7 +64,7 @@ public class WhenToDreamPreferenceControllerTest { public void setup() throws Exception { MockitoAnnotations.initMocks(this); mContext = spy(ApplicationProvider.getApplicationContext()); - mController = new WhenToDreamPreferenceController(mContext, true); + mController = new WhenToDreamPreferenceController(mContext, true, true); ReflectionHelpers.setField(mController, "mBackend", mBackend); when(mContext.getSystemService(PowerManager.class)).thenReturn(mPowerManager); when(mPowerManager.isAmbientDisplaySuppressedForTokenByApp(anyString(), anyInt())) @@ -88,7 +88,7 @@ public class WhenToDreamPreferenceControllerTest { final Preference mockPref = mock(Preference.class); when(mockPref.getContext()).thenReturn(mContext); when(mBackend.getWhenToDreamSetting()).thenReturn(testSetting); - final int expectedResId = DreamSettings.getDreamSettingDescriptionResId(testSetting); + final int expectedResId = DreamSettings.getDreamSettingDescriptionResId(testSetting, true); mController.updateState(mockPref); verify(mockPref).setSummary(expectedResId); diff --git a/tests/robotests/src/com/android/settings/notification/app/NotificationsOffPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/app/NotificationsOffPreferenceControllerTest.java index 34e94a042f9..2eebd3a2eab 100644 --- a/tests/robotests/src/com/android/settings/notification/app/NotificationsOffPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/notification/app/NotificationsOffPreferenceControllerTest.java @@ -20,6 +20,7 @@ import static android.app.NotificationManager.IMPORTANCE_NONE; import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; @@ -32,6 +33,7 @@ import android.os.UserManager; import androidx.preference.Preference; +import com.android.settings.R; import com.android.settings.notification.NotificationBackend; import com.google.common.collect.ImmutableList; @@ -157,4 +159,23 @@ public class NotificationsOffPreferenceControllerTest { assertThat(pref.getTitle().toString()).contains("app"); assertThat(pref.isSelectable()).isFalse(); } + + @Test + public void testUpdateState_whenToggleDisabled() { + // Given: the app does not request to post notifications + // and it's preference toggle is disabled + NotificationBackend.AppRow appRow = new NotificationBackend.AppRow(); + appRow.banned = true; + appRow.permissionStateLocked = true; + mController.onResume(appRow, null, null, null, null, null, null); + Preference pref = new Preference(RuntimeEnvironment.application); + + // When: updateState(Preference preference) is called + mController.updateState(pref); + + // Then: title of pref should be app_notifications_not_send_desc + assertEquals( + RuntimeEnvironment.application.getString(R.string.app_notifications_not_send_desc), + pref.getTitle().toString()); + } }