Show confirmation dialogs when enabling or disabling a mode
(Strings are not final, but structure is there).
Bug: 349376785
Test: atest ZenModeSetTriggerLinkPreferenceControllerTest
Flag: android.app.modes_ui
Change-Id: Ia9e604483b90bc30ad1c12e5663a07e251084073
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 08d29ea..3add15e 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -9496,6 +9496,19 @@
<!-- Priority Modes: Generic trigger summary for modes where the owner app did not provide neither a triggerDescription nor a configurationActivity to call [CHAR LIMIT=60] -->
<string name="zen_mode_trigger_summary_managed_by_app">Managed by <xliff:g id="app_name" example="The Awesome App">%1$s</xliff:g></string>
+ <!-- Priority Modes: Title of the confirmation dialog for disabling an enabled mode [CHAR LIMIT=30] -->
+ <string name="zen_mode_confirm_disable_title">Disable Mode</string>
+ <!-- Priority Modes: Message body of the confirmation dialog for disabling an enabled mode [CHAR LIMIT=NONE] -->
+ <string name="zen_mode_confirm_disable_message">If you disable this feature, the mode will no longer work as intended and its settings will be hidden.</string>
+ <!-- Priority Modes: Button to disable a mode [CHAR LIMIT=20] -->
+ <string name="zen_mode_action_disable">Disable</string>
+ <!-- Priority Modes: Title of the confirmation dialog for enabling a disabled mode [CHAR LIMIT=30] -->
+ <string name="zen_mode_confirm_enable_title">Enable Mode</string>
+ <!-- Priority Modes: Message body of the confirmation dialog for enabling a disabled mode [CHAR LIMIT=NONE] -->
+ <string name="zen_mode_confirm_enable_message">If you enable this feature, the mode will activate automatically according to its schedule.</string>
+ <!-- Priority Modes: Button to disable a mode [CHAR LIMIT=20] -->
+ <string name="zen_mode_action_enable">Enable</string>
+
<!-- Content description for help icon button [CHAR LIMIT=20] -->
<string name="warning_button_text">Warning</string>
diff --git a/src/com/android/settings/notification/modes/ZenModeSetTriggerLinkPreferenceController.java b/src/com/android/settings/notification/modes/ZenModeSetTriggerLinkPreferenceController.java
index 1f97902..24df931 100644
--- a/src/com/android/settings/notification/modes/ZenModeSetTriggerLinkPreferenceController.java
+++ b/src/com/android/settings/notification/modes/ZenModeSetTriggerLinkPreferenceController.java
@@ -25,6 +25,7 @@
import static com.google.common.base.Preconditions.checkNotNull;
import android.annotation.SuppressLint;
+import android.app.AlertDialog;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
@@ -231,12 +232,40 @@
});
private final Preference.OnPreferenceChangeListener mSwitchChangeListener = (p, newValue) -> {
- final boolean newEnabled = (Boolean) newValue;
- return saveMode((zenMode) -> {
- if (newEnabled != zenMode.getRule().isEnabled()) {
- zenMode.getRule().setEnabled(newEnabled);
+ confirmChangeEnabled(p, (boolean) newValue);
+ return true;
+ };
+
+ private void confirmChangeEnabled(Preference preference, boolean enabled) {
+ @StringRes int title = enabled ? R.string.zen_mode_confirm_enable_title
+ : R.string.zen_mode_confirm_disable_title;
+ @StringRes int message = enabled ? R.string.zen_mode_confirm_enable_message
+ : R.string.zen_mode_confirm_disable_message;
+ @StringRes int confirmButton = enabled ? R.string.zen_mode_action_enable
+ : R.string.zen_mode_action_disable;
+
+ new AlertDialog.Builder(mContext)
+ .setTitle(title)
+ .setMessage(message)
+ .setPositiveButton(confirmButton,
+ (dialog, which) -> setModeEnabled(enabled))
+ .setNegativeButton(R.string.cancel,
+ (dialog, which) -> undoToggleSwitch(preference, enabled))
+ .setOnCancelListener(dialog -> undoToggleSwitch(preference, enabled))
+ .show();
+ }
+
+ private void setModeEnabled(boolean enabled) {
+ saveMode((zenMode) -> {
+ if (enabled != zenMode.getRule().isEnabled()) {
+ zenMode.getRule().setEnabled(enabled);
}
return zenMode;
});
- };
+ }
+
+ private void undoToggleSwitch(Preference preference, boolean wasSwitchedTo) {
+ PrimarySwitchPreference switchPreference = (PrimarySwitchPreference) preference;
+ switchPreference.setChecked(!wasSwitchedTo);
+ }
}
diff --git a/tests/robotests/src/com/android/settings/notification/modes/ZenModeSetTriggerLinkPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/modes/ZenModeSetTriggerLinkPreferenceControllerTest.java
index 61ca4d8..93db4be 100644
--- a/tests/robotests/src/com/android/settings/notification/modes/ZenModeSetTriggerLinkPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/modes/ZenModeSetTriggerLinkPreferenceControllerTest.java
@@ -32,9 +32,12 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import static org.robolectric.Shadows.shadowOf;
+import android.app.AlertDialog;
import android.app.AutomaticZenRule;
import android.app.Flags;
import android.content.Context;
@@ -42,6 +45,7 @@
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.net.Uri;
+import android.os.Looper;
import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.SetFlagsRule;
import android.service.notification.SystemZenRules;
@@ -74,6 +78,7 @@
import org.mockito.MockitoAnnotations;
import org.mockito.stubbing.Answer;
import org.robolectric.RobolectricTestRunner;
+import org.robolectric.shadows.ShadowAlertDialog;
import java.util.Calendar;
@@ -161,19 +166,86 @@
}
@Test
- public void onPreferenceChange_updatesMode() {
+ public void onPreferenceChange_toggleOn_enablesModeAfterConfirmation() {
+ // Start with a disabled mode
ZenMode zenMode = new TestModeBuilder().setEnabled(false).build();
-
- // start with disabled rule
mController.updateZenMode(mPrefCategory, zenMode);
- // then flip the switch
+ // Flip the switch
mConfigPreference.callChangeListener(true);
+ verify(mBackend, never()).updateMode(any());
- // verify the backend got asked to update the mode to be enabled
+ // Oh wait, I forgot to confirm! Let's do that
+ assertThat(ShadowAlertDialog.getLatestAlertDialog()).isNotNull();
+ assertThat(ShadowAlertDialog.getLatestAlertDialog().isShowing()).isTrue();
+ ShadowAlertDialog.getLatestAlertDialog()
+ .getButton(AlertDialog.BUTTON_POSITIVE).performClick();
+ shadowOf(Looper.getMainLooper()).idle();
+
+ // Verify the backend got asked to update the mode to be enabled
ArgumentCaptor<ZenMode> captor = ArgumentCaptor.forClass(ZenMode.class);
verify(mBackend).updateMode(captor.capture());
assertThat(captor.getValue().getRule().isEnabled()).isTrue();
+ assertThat(ShadowAlertDialog.getLatestAlertDialog().isShowing()).isFalse();
+ }
+
+ @Test
+ public void onPreferenceChange_toggleOff_disablesModeAfterConfirmation() {
+ // Start with an enabled mode
+ ZenMode zenMode = new TestModeBuilder().setEnabled(true).build();
+ mController.updateZenMode(mPrefCategory, zenMode);
+
+ // Flip the switch
+ mConfigPreference.callChangeListener(false);
+ verify(mBackend, never()).updateMode(any());
+
+ // Oh wait, I forgot to confirm! Let's do that
+ assertThat(ShadowAlertDialog.getLatestAlertDialog()).isNotNull();
+ assertThat(ShadowAlertDialog.getLatestAlertDialog().isShowing()).isTrue();
+ ShadowAlertDialog.getLatestAlertDialog()
+ .getButton(AlertDialog.BUTTON_POSITIVE).performClick();
+ shadowOf(Looper.getMainLooper()).idle();
+
+ // Verify the backend got asked to update the mode to be disabled
+ ArgumentCaptor<ZenMode> captor = ArgumentCaptor.forClass(ZenMode.class);
+ verify(mBackend).updateMode(captor.capture());
+ assertThat(captor.getValue().getRule().isEnabled()).isFalse();
+ assertThat(ShadowAlertDialog.getLatestAlertDialog().isShowing()).isFalse();
+ }
+
+ @Test
+ public void onPreferenceChange_ifPressCancelButton_doesNotUpdateMode() {
+ // Start with a disabled mode
+ ZenMode zenMode = new TestModeBuilder().setEnabled(false).build();
+ mController.updateZenMode(mPrefCategory, zenMode);
+
+ // Flip the switch, then have second thoughts about it
+ mConfigPreference.callChangeListener(true);
+ ShadowAlertDialog.getLatestAlertDialog()
+ .getButton(AlertDialog.BUTTON_NEGATIVE).performClick();
+ shadowOf(Looper.getMainLooper()).idle();
+
+ // Verify nothing changed, and the switch shows the correct (pre-change) value.
+ verify(mBackend, never()).updateMode(any());
+ assertThat(mConfigPreference.isChecked()).isFalse();
+ assertThat(ShadowAlertDialog.getLatestAlertDialog().isShowing()).isFalse();
+ }
+
+ @Test
+ public void onPreferenceChange_ifExitingDialog_doesNotUpdateMode() {
+ // Start with a disabled mode
+ ZenMode zenMode = new TestModeBuilder().setEnabled(false).build();
+ mController.updateZenMode(mPrefCategory, zenMode);
+
+ // Flip the switch, but close the dialog without selecting either button.
+ mConfigPreference.callChangeListener(true);
+ ShadowAlertDialog.getLatestAlertDialog().dismiss();
+ shadowOf(Looper.getMainLooper()).idle();
+
+ // Verify nothing changed, and the switch shows the correct (pre-change) value.
+ verify(mBackend, never()).updateMode(any());
+ assertThat(mConfigPreference.isChecked()).isFalse();
+ assertThat(ShadowAlertDialog.getLatestAlertDialog().isShowing()).isFalse();
}
@Test