OSDN Git Service

Adding zen duration preference
authorBeverly <beverlyt@google.com>
Mon, 26 Feb 2018 14:19:41 +0000 (09:19 -0500)
committerBeverly <beverlyt@google.com>
Mon, 12 Mar 2018 17:46:32 +0000 (13:46 -0400)
Test: make ROBOTEST_FILTER=ZenModeDurationPreferenceControllerTest RunSettingsRoboTests -j40
Bug: 73741459
Change-Id: I55a75897045ef059dc872bf6403a62f46cedc417

res/values/strings.xml
res/xml/zen_mode_settings.xml
src/com/android/settings/notification/AbstractZenModePreferenceController.java
src/com/android/settings/notification/SettingsZenDurationDialog.java [new file with mode: 0644]
src/com/android/settings/notification/ZenModeAutomationPreferenceController.java
src/com/android/settings/notification/ZenModeBackend.java
src/com/android/settings/notification/ZenModeBehaviorPreferenceController.java
src/com/android/settings/notification/ZenModeButtonPreferenceController.java
src/com/android/settings/notification/ZenModeDurationPreferenceController.java [new file with mode: 0644]
src/com/android/settings/notification/ZenModeSettings.java
tests/robotests/src/com/android/settings/notification/ZenModeDurationPreferenceControllerTest.java [new file with mode: 0644]

index ab8c011..c84853f 100644 (file)
     <!-- Do not disturb: Title for the page describing what can bypass DND. [CHAR LIMIT=30] -->
     <string name="zen_mode_behavior_settings_title">Exceptions</string>
 
+    <!-- Do not disturb: Title for the dnd duration setting (user can specify how long dnd will last when toggling dnd on from qs or settings) [CHAR LIMIT=30] -->
+    <string name="zen_mode_duration_settings_title">Duration</string>
+
     <!-- Do not disturb: Instructions indicating what types of sounds can bypass DND. [CHAR LIMIT=52] -->
     <string name="zen_mode_behavior_allow_title">Allow sounds and vibrations from</string>
 
     <!-- Sound settings screen, summary format of do not disturb when on with no extra information. [CHAR LIMIT=NONE] -->
     <string name="zen_mode_sound_summary_on">On</string>
 
+    <!--  Do not disturb: Summary for zen mode duration setting indicating user will be prompted to set dnd duration whenever dnd is manually toggled on [CHAR LIMIT=NONE]-->
+    <string name="zen_mode_duration_summary_always_prompt">Ask every time (unless turned on automatically)</string>
+
+    <!--  Do not disturb: Summary for zen mode duration setting indicating how long dnd will last when dnd is manually toggled on [CHAR LIMIT=NONE] -->
+    <string name="zen_mode_duration_summary_forever">Until you turn off (unless turned on automatically)</string>
+
+    <!--  Do not disturb: Summary for zen mode duration setting indicating how long dnd will last when dnd is manually toggled on [CHAR LIMIT=NONE] -->
+    <plurals name="zen_mode_duration_summary_time_hours">
+        <item quantity="one">1 hour (unless turned on automatically)</item>
+        <item quantity="other"><xliff:g id="num_hours" example="3">%d</xliff:g> hours (unless turned on automatically)</item>
+    </plurals>
+
+    <!--  Do not disturb: Summary for zen mode duration setting indicating how long dnd will last when toggled on -->
+    <string name="zen_mode_duration_summary_time_minutes"><xliff:g id="num_minutes" example="5">%d</xliff:g> minutes (unless turned on automatically)</string>
+
     <!-- Summary for the Sound Do not Disturb option when at least one automatic rules is enabled. [CHAR LIMIT=NONE]-->
     <plurals name="zen_mode_sound_summary_summary_off_info">
         <item quantity="one">1 rule can turn on automatically</item>
index 1f863c2..65fb7ab 100644 (file)
             android:title="@string/zen_mode_behavior_settings_title"
             android:fragment="com.android.settings.notification.ZenModeBehaviorSettings" />
 
+    <!-- DND duration settings -->
+    <Preference
+        android:key="zen_mode_duration_settings"
+        android:title="@string/zen_mode_duration_settings_title" />
+
     <!-- Automatic rules -->
     <Preference
         android:key="zen_mode_automation_settings"
index 9180791..c60299e 100644 (file)
@@ -112,10 +112,17 @@ abstract public class AbstractZenModePreferenceController extends
                 mBackend.mZenMode);
     }
 
+    protected int getZenDuration() {
+        return Settings.Global.getInt(mContext.getContentResolver(), Settings.Global.ZEN_DURATION,
+                0);
+    }
+
     class SettingObserver extends ContentObserver {
         private final Uri ZEN_MODE_URI = Settings.Global.getUriFor(Settings.Global.ZEN_MODE);
         private final Uri ZEN_MODE_CONFIG_ETAG_URI = Settings.Global.getUriFor(
                 Settings.Global.ZEN_MODE_CONFIG_ETAG);
+        private final Uri ZEN_MODE_DURATION_URI = Settings.Global.getUriFor(
+                Settings.Global.ZEN_DURATION);
 
         private final Preference mPreference;
 
@@ -127,6 +134,7 @@ abstract public class AbstractZenModePreferenceController extends
         public void register(ContentResolver cr) {
             cr.registerContentObserver(ZEN_MODE_URI, false, this, UserHandle.USER_ALL);
             cr.registerContentObserver(ZEN_MODE_CONFIG_ETAG_URI, false, this, UserHandle.USER_ALL);
+            cr.registerContentObserver(ZEN_MODE_DURATION_URI, false, this, UserHandle.USER_ALL);
         }
 
         public void unregister(ContentResolver cr) {
@@ -136,11 +144,8 @@ abstract public class AbstractZenModePreferenceController extends
         @Override
         public void onChange(boolean selfChange, Uri uri) {
             super.onChange(selfChange, uri);
-            if (ZEN_MODE_URI.equals(uri)) {
-                updateState(mPreference);
-            }
-
-            if (ZEN_MODE_CONFIG_ETAG_URI.equals(uri)) {
+            if (ZEN_MODE_URI.equals(uri) || ZEN_MODE_CONFIG_ETAG_URI.equals(uri)
+                    || ZEN_MODE_DURATION_URI.equals(uri)) {
                 updateState(mPreference);
             }
         }
diff --git a/src/com/android/settings/notification/SettingsZenDurationDialog.java b/src/com/android/settings/notification/SettingsZenDurationDialog.java
new file mode 100644 (file)
index 0000000..23bf1a9
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * 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.Dialog;
+import android.os.Bundle;
+
+import com.android.internal.logging.nano.MetricsProto;
+import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
+
+public class SettingsZenDurationDialog extends InstrumentedDialogFragment {
+
+    @Override
+    public Dialog onCreateDialog(Bundle savedInstanceState) {
+        return new com.android.settingslib.notification.ZenDurationDialog(
+                getContext()).createDialog();
+    }
+
+    @Override
+    public int getMetricsCategory() {
+        return MetricsProto.MetricsEvent.NOTIFICATION_ZEN_MODE_DURATION_DIALOG;
+    }
+}
index aa46d4e..792a272 100644 (file)
@@ -1,3 +1,19 @@
+/*
+ * 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.notification;
 
 import android.content.Context;
index 8817417..3c6a026 100644 (file)
 
 package com.android.settings.notification;
 
+import android.app.ActivityManager;
 import android.app.AutomaticZenRule;
 import android.app.NotificationManager;
 import android.content.Context;
+import android.net.Uri;
 import android.provider.Settings;
 import android.service.notification.ZenModeConfig;
 import android.support.annotation.VisibleForTesting;
@@ -79,7 +81,15 @@ public class ZenModeBackend {
 
     protected void setZenMode(int zenMode) {
         NotificationManager.from(mContext).setZenMode(zenMode, null, TAG);
-        mZenMode = zenMode;
+        mZenMode = getZenMode();
+    }
+
+    protected void setZenModeForDuration(int minutes) {
+        Uri conditionId = ZenModeConfig.toTimeCondition(mContext, minutes,
+                ActivityManager.getCurrentUser(), true).id;
+        mNotificationManager.setZenMode(Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS,
+                conditionId, TAG);
+        mZenMode = getZenMode();
     }
 
     protected int getZenMode() {
index 0e1f066..cf6218c 100644 (file)
@@ -1,3 +1,19 @@
+/*
+ * 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.notification;
 
 import android.content.Context;
index d9c9691..12008a1 100644 (file)
@@ -61,8 +61,7 @@ public class ZenModeButtonPreferenceController extends AbstractZenModePreference
         if (null == mZenButtonOn) {
             mZenButtonOn = (Button) ((LayoutPreference) preference)
                     .findViewById(R.id.zen_mode_settings_turn_on_button);
-            mZenButtonOn.setOnClickListener(v ->
-                    new SettingsEnableZenModeDialog().show(mFragment, TAG));
+            updateZenButtonOnClickListener();
         }
 
         if (null == mZenButtonOff) {
@@ -89,7 +88,34 @@ public class ZenModeButtonPreferenceController extends AbstractZenModePreference
             case Settings.Global.ZEN_MODE_OFF:
             default:
                 mZenButtonOff.setVisibility(View.GONE);
+                updateZenButtonOnClickListener();
                 mZenButtonOn.setVisibility(View.VISIBLE);
         }
     }
+
+    private void updateZenButtonOnClickListener() {
+        int zenDuration = getZenDuration();
+        switch (zenDuration) {
+            case Settings.Global.ZEN_DURATION_PROMPT:
+                mZenButtonOn.setOnClickListener(v -> {
+                    mMetricsFeatureProvider.action(mContext,
+                            MetricsProto.MetricsEvent.ACTION_ZEN_TOGGLE_DND_BUTTON, false);
+                    new SettingsEnableZenModeDialog().show(mFragment, TAG);
+                });
+                break;
+            case Settings.Global.ZEN_DURATION_FOREVER:
+                mZenButtonOn.setOnClickListener(v -> {
+                    mMetricsFeatureProvider.action(mContext,
+                            MetricsProto.MetricsEvent.ACTION_ZEN_TOGGLE_DND_BUTTON, false);
+                    mBackend.setZenMode(Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS);
+                });
+                break;
+            default:
+                mZenButtonOn.setOnClickListener(v -> {
+                    mMetricsFeatureProvider.action(mContext,
+                            MetricsProto.MetricsEvent.ACTION_ZEN_TOGGLE_DND_BUTTON, false);
+                    mBackend.setZenModeForDuration(zenDuration);
+                });
+        }
+    }
 }
\ No newline at end of file
diff --git a/src/com/android/settings/notification/ZenModeDurationPreferenceController.java b/src/com/android/settings/notification/ZenModeDurationPreferenceController.java
new file mode 100644 (file)
index 0000000..0cd0eb3
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * 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.FragmentManager;
+import android.content.Context;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceScreen;
+
+import com.android.settings.R;
+import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+
+public class ZenModeDurationPreferenceController extends AbstractZenModePreferenceController
+        implements PreferenceControllerMixin, Preference.OnPreferenceClickListener {
+
+    private static final String TAG = "ZenModeDurationDialog";
+    protected static final String KEY = "zen_mode_duration_settings";
+    private FragmentManager mFragment;
+
+    public ZenModeDurationPreferenceController(Context context, Lifecycle lifecycle, FragmentManager
+            fragment) {
+        super(context, KEY, lifecycle);
+        mFragment = fragment;
+    }
+
+    @Override
+    public boolean isAvailable() {
+        return true;
+    }
+
+    @Override
+    public String getPreferenceKey() {
+        return KEY;
+    }
+
+    @Override
+    public void displayPreference(PreferenceScreen screen) {
+        super.displayPreference(screen);
+        screen.findPreference(KEY).setOnPreferenceClickListener(this);
+    }
+
+    @Override
+    public void updateState(Preference preference) {
+        super.updateState(preference);
+
+        String summary = "";
+        int zenDuration = getZenDuration();
+        if (zenDuration < 0) {
+            summary = mContext.getString(R.string.zen_mode_duration_summary_always_prompt);
+        } else if (zenDuration == 0) {
+            summary = mContext.getString(R.string.zen_mode_duration_summary_forever);
+        } else {
+            if (zenDuration >= 60) {
+                int hours = zenDuration / 60;
+                summary = mContext.getResources().getQuantityString(
+                        R.plurals.zen_mode_duration_summary_time_hours, hours, hours);
+            } else {
+                summary = mContext.getResources().getString(
+                        R.string.zen_mode_duration_summary_time_minutes, zenDuration);
+            }
+        }
+
+        preference.setSummary(summary);
+    }
+
+    @Override
+    public boolean onPreferenceClick(Preference preference) {
+        new SettingsZenDurationDialog().show(mFragment, TAG);
+        return true;
+    }
+}
\ No newline at end of file
index 557d624..b143b42 100644 (file)
@@ -65,6 +65,8 @@ public class ZenModeSettings extends ZenModeSettingsBase {
         List<AbstractPreferenceController> controllers = new ArrayList<>();
         controllers.add(new ZenModeBehaviorPreferenceController(context, lifecycle));
         controllers.add(new ZenModeBlockedEffectsPreferenceController(context, lifecycle));
+        controllers.add(new ZenModeDurationPreferenceController(context, lifecycle,
+                fragmentManager));
         controllers.add(new ZenModeAutomationPreferenceController(context));
         controllers.add(new ZenModeButtonPreferenceController(context, lifecycle, fragmentManager));
         controllers.add(new ZenModeSettingsFooterPreferenceController(context, lifecycle));
@@ -250,6 +252,7 @@ public class ZenModeSettings extends ZenModeSettingsBase {
                 @Override
                 public List<String> getNonIndexableKeys(Context context) {
                     List<String> keys = super.getNonIndexableKeys(context);
+                    keys.add(ZenModeDurationPreferenceController.KEY);
                     keys.add(ZenModeButtonPreferenceController.KEY);
                     return keys;
                 }
diff --git a/tests/robotests/src/com/android/settings/notification/ZenModeDurationPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/ZenModeDurationPreferenceControllerTest.java
new file mode 100644 (file)
index 0000000..9a94e6c
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * 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 org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.FragmentManager;
+import android.app.NotificationManager;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.provider.Settings;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceScreen;
+
+import com.android.settings.R;
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+import org.robolectric.shadows.ShadowApplication;
+import org.robolectric.util.ReflectionHelpers;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+public class ZenModeDurationPreferenceControllerTest {
+    private ZenModeDurationPreferenceController mController;
+
+    @Mock
+    private ZenModeBackend mBackend;
+    @Mock
+    private NotificationManager mNotificationManager;
+    @Mock
+    private Preference mockPref;
+    @Mock
+    private NotificationManager.Policy mPolicy;
+    @Mock
+    private PreferenceScreen mPreferenceScreen;
+    private ContentResolver mContentResolver;
+    private Context mContext;
+
+    @Before
+    public void setup() {
+        MockitoAnnotations.initMocks(this);
+        ShadowApplication shadowApplication = ShadowApplication.getInstance();
+        shadowApplication.setSystemService(Context.NOTIFICATION_SERVICE, mNotificationManager);
+
+        mContext = shadowApplication.getApplicationContext();
+        mContentResolver = RuntimeEnvironment.application.getContentResolver();
+        mController = new ZenModeDurationPreferenceController(mContext, mock(Lifecycle.class),
+                mock(FragmentManager.class));
+        when(mNotificationManager.getNotificationPolicy()).thenReturn(mPolicy);
+        ReflectionHelpers.setField(mController, "mBackend", mBackend);
+        when(mPreferenceScreen.findPreference(mController.getPreferenceKey())).thenReturn(
+                mockPref);
+        mController.displayPreference(mPreferenceScreen);
+    }
+
+    @Test
+    public void updateState_DurationForever() {
+        Settings.Global.putInt(mContentResolver, Settings.Global.ZEN_DURATION,
+                Settings.Global.ZEN_DURATION_FOREVER);
+        final Preference mockPref = mock(Preference.class);
+        mController.updateState(mockPref);
+
+        verify(mockPref).setSummary(mContext.getString(R.string.zen_mode_duration_summary_forever));
+    }
+
+    @Test
+    public void updateState_DurationPrompt() {
+        Settings.Global.putInt(mContentResolver, Settings.Global.ZEN_DURATION,
+                Settings.Global.ZEN_DURATION_PROMPT);
+        final Preference mockPref = mock(Preference.class);
+        mController.updateState(mockPref);
+
+        verify(mockPref).setSummary(mContext.getString(
+                R.string.zen_mode_duration_summary_always_prompt));
+    }
+
+    @Test
+    public void updateState_DurationCustom() {
+        int zenDuration = 45;
+        Settings.Global.putInt(mContentResolver, Settings.Global.ZEN_DURATION,
+                zenDuration);
+        final Preference mockPref = mock(Preference.class);
+        mController.updateState(mockPref);
+
+        verify(mockPref).setSummary(mContext.getResources().getString(
+                R.string.zen_mode_duration_summary_time_minutes, zenDuration));
+    }
+}
\ No newline at end of file