Merge "Using zen duration preference" into pi-dev

am: 75431913ef

Change-Id: Ic50e017f72e520da141580227648a7e639cc8cea
This commit is contained in:
Beverly Tai
2018-03-12 23:28:58 +00:00
committed by android-build-merger
12 changed files with 676 additions and 17 deletions

View File

@@ -11194,6 +11194,20 @@ public final class Settings {
*/
public static final String ZEN_MODE_CONFIG_ETAG = "zen_mode_config_etag";
/**
* If 0, turning on dnd manually will last indefinitely.
* Else if non-negative, turning on dnd manually will last for this many minutes.
* Else (if negative), turning on dnd manually will surface a dialog that prompts
* user to specify a duration.
* @hide
*/
public static final String ZEN_DURATION = "zen_duration";
private static final Validator ZEN_DURATION_VALIDATOR = ANY_INTEGER_VALIDATOR;
/** @hide */ public static final int ZEN_DURATION_PROMPT = -1;
/** @hide */ public static final int ZEN_DURATION_FOREVER = 0;
/**
* Defines global heads up toggle. One of HEADS_UP_OFF, HEADS_UP_ON.
*
@@ -11575,7 +11589,8 @@ public final class Settings {
BLUETOOTH_ON,
PRIVATE_DNS_MODE,
PRIVATE_DNS_SPECIFIER,
SOFT_AP_TIMEOUT_ENABLED
SOFT_AP_TIMEOUT_ENABLED,
ZEN_DURATION,
};
/**
@@ -11616,6 +11631,7 @@ public final class Settings {
VALIDATORS.put(WIFI_CARRIER_NETWORKS_AVAILABLE_NOTIFICATION_ON,
WIFI_CARRIER_NETWORKS_AVAILABLE_NOTIFICATION_ON_VALIDATOR);
VALIDATORS.put(APP_AUTO_RESTRICTION_ENABLED, APP_AUTO_RESTRICTION_ENABLED_VALIDATOR);
VALIDATORS.put(ZEN_DURATION, ZEN_DURATION_VALIDATOR);
}
/**

View File

@@ -433,9 +433,11 @@ message GlobalSettingsProto {
optional SettingProto show_mute_in_crash_dialog = 352 [ (android.privacy).dest = DEST_AUTOMATIC ];
optional SettingsProto show_zen_upgrade_notification = 354 [ (android.privacy).dest = DEST_AUTOMATIC ];
optional SettingsProto app_auto_restriction_enabled = 359 [ (android.privacy).dest = DEST_AUTOMATIC ];
optional SettingsProto zen_duration = 360 [ (android.privacy).dest = DEST_AUTOMATIC ];
// Please insert fields in the same order as in
// frameworks/base/core/java/android/provider/Settings.java.
// Next tag = 360;
// Next tag = 361;
}
message SecureSettingsProto {

View File

@@ -4490,7 +4490,7 @@
<!-- Zen mode condition - summary: time duration in hours. [CHAR LIMIT=NONE] -->
<plurals name="zen_mode_duration_hours_summary">
<item quantity="one">For one hour (until <xliff:g id="formattedTime" example="10:00 PM">%2$s</xliff:g>)</item>
<item quantity="one">For 1 hour (until <xliff:g id="formattedTime" example="10:00 PM">%2$s</xliff:g>)</item>
<item quantity="other">For %1$d hours (until <xliff:g id="formattedTime" example="10:00 PM">%2$s</xliff:g>)</item>
</plurals>
@@ -4514,7 +4514,7 @@
<!-- Zen mode condition - line one: time duration in hours. [CHAR LIMIT=NONE] -->
<plurals name="zen_mode_duration_hours">
<item quantity="one">For one hour</item>
<item quantity="one">For 1 hour</item>
<item quantity="other">For %d hours</item>
</plurals>

View File

@@ -0,0 +1,52 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
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.
-->
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/zen_duration_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport ="true"
android:orientation="vertical">
<LinearLayout
android:id="@+id/zen_duration_dialog_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.android.settingslib.notification.ZenRadioLayout
android:id="@+id/zen_duration_conditions"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginEnd="4dp"
android:layout_marginStart="4dp"
android:paddingBottom="4dp"
android:orientation="horizontal">
<RadioGroup
android:id="@+id/zen_radio_buttons"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<LinearLayout
android:id="@+id/zen_radio_buttons_content"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"/>
</com.android.settingslib.notification.ZenRadioLayout>
</LinearLayout>
</ScrollView>

View File

@@ -1062,10 +1062,13 @@
<!-- Content description of zen mode time condition minus button (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_manual_zen_less_time">Less time.</string>
<!-- Do not disturb: Label for button in enable zen dialog that will turn on zen mode. [CHAR LIMIT=30] -->
<string name="zen_mode_enable_dialog_turn_on">Turn on</string>
<!-- Button label for generic cancel action [CHAR LIMIT=20] -->
<string name="cancel">Cancel</string>
<!-- Button label for generic OK action [CHAR LIMIT=20] -->
<string name="okay">OK</string>
<!-- Do not disturb: Label for button in enable zen dialog that will turn on zen mode. [CHAR LIMIT=30] -->
<string name="zen_mode_enable_dialog_turn_on">Turn on</string>
<!-- Do not disturb: Title for the Do not Disturb dialog to turn on Do not disturb. [CHAR LIMIT=50]-->
<string name="zen_mode_settings_turn_on_dialog_title">Turn on Do Not Disturb</string>
<!-- Sound: Summary for the Do not Disturb option when there is no automatic rules turned on. [CHAR LIMIT=NONE]-->
@@ -1083,4 +1086,8 @@
<!-- Alarm template for far in the future alarms [CHAR LIMIT=25] -->
<string name="alarm_template_far">on <xliff:g id="when" example="Fri 7:00 AM">%1$s</xliff:g></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: Duration option to always prompt for the duration of dnd -->
<string name="zen_mode_duration_always_prompt_title">Ask every time</string>
</resources>

View File

@@ -0,0 +1,321 @@
/*
* 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.settingslib.notification;
import android.app.ActivityManager;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.provider.Settings;
import android.service.notification.Condition;
import android.service.notification.ZenModeConfig;
import android.support.annotation.VisibleForTesting;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.CompoundButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.ScrollView;
import android.widget.TextView;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto;
import com.android.internal.policy.PhoneWindow;
import com.android.settingslib.R;
import java.util.Arrays;
public class ZenDurationDialog {
private static final int[] MINUTE_BUCKETS = ZenModeConfig.MINUTE_BUCKETS;
@VisibleForTesting protected static final int MIN_BUCKET_MINUTES = MINUTE_BUCKETS[0];
@VisibleForTesting protected static final int MAX_BUCKET_MINUTES =
MINUTE_BUCKETS[MINUTE_BUCKETS.length - 1];
private static final int DEFAULT_BUCKET_INDEX = Arrays.binarySearch(MINUTE_BUCKETS, 60);
@VisibleForTesting protected int mBucketIndex = -1;
@VisibleForTesting protected static final int FOREVER_CONDITION_INDEX = 0;
@VisibleForTesting protected static final int COUNTDOWN_CONDITION_INDEX = 1;
@VisibleForTesting protected static final int ALWAYS_ASK_CONDITION_INDEX = 2;
@VisibleForTesting protected Context mContext;
@VisibleForTesting protected LinearLayout mZenRadioGroupContent;
private RadioGroup mZenRadioGroup;
private int MAX_MANUAL_DND_OPTIONS = 3;
@VisibleForTesting protected LayoutInflater mLayoutInflater;
public ZenDurationDialog(Context context) {
mContext = context;
}
public Dialog createDialog() {
int zenDuration = Settings.Global.getInt(
mContext.getContentResolver(), Settings.Global.ZEN_DURATION,
Settings.Global.ZEN_DURATION_FOREVER);
final AlertDialog.Builder builder = new AlertDialog.Builder(mContext)
.setTitle(R.string.zen_mode_duration_settings_title)
.setNegativeButton(R.string.cancel, null)
.setPositiveButton(R.string.okay,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
updateZenDuration(zenDuration);
}
});
View contentView = getContentView();
setupRadioButtons(zenDuration);
builder.setView(contentView);
return builder.create();
}
@VisibleForTesting
protected void updateZenDuration(int currZenDuration) {
final int checkedRadioButtonId = mZenRadioGroup.getCheckedRadioButtonId();
int newZenDuration = Settings.Global.getInt(
mContext.getContentResolver(), Settings.Global.ZEN_DURATION,
Settings.Global.ZEN_DURATION_FOREVER);
switch (checkedRadioButtonId) {
case FOREVER_CONDITION_INDEX:
newZenDuration = Settings.Global.ZEN_DURATION_FOREVER;
MetricsLogger.action(mContext,
MetricsProto.MetricsEvent.
NOTIFICATION_ZEN_MODE_DURATION_FOREVER);
break;
case COUNTDOWN_CONDITION_INDEX:
ConditionTag tag = getConditionTagAt(checkedRadioButtonId);
newZenDuration = tag.countdownZenDuration;
MetricsLogger.action(mContext,
MetricsProto.MetricsEvent.
NOTIFICATION_ZEN_MODE_DURATION_TIME,
newZenDuration);
break;
case ALWAYS_ASK_CONDITION_INDEX:
newZenDuration = Settings.Global.ZEN_DURATION_PROMPT;
MetricsLogger.action(mContext,
MetricsProto.MetricsEvent.
NOTIFICATION_ZEN_MODE_DURATION_PROMPT);
break;
}
if (currZenDuration != newZenDuration) {
Settings.Global.putInt(mContext.getContentResolver(),
Settings.Global.ZEN_DURATION, newZenDuration);
}
}
@VisibleForTesting
protected View getContentView() {
if (mLayoutInflater == null) {
mLayoutInflater = new PhoneWindow(mContext).getLayoutInflater();
}
View contentView = mLayoutInflater.inflate(R.layout.zen_mode_duration_dialog,
null);
ScrollView container = (ScrollView) contentView.findViewById(R.id.zen_duration_container);
mZenRadioGroup = container.findViewById(R.id.zen_radio_buttons);
mZenRadioGroupContent = container.findViewById(R.id.zen_radio_buttons_content);
for (int i = 0; i < MAX_MANUAL_DND_OPTIONS; i++) {
final View radioButton = mLayoutInflater.inflate(R.layout.zen_mode_radio_button,
mZenRadioGroup, false);
mZenRadioGroup.addView(radioButton);
radioButton.setId(i);
final View radioButtonContent = mLayoutInflater.inflate(R.layout.zen_mode_condition,
mZenRadioGroupContent, false);
radioButtonContent.setId(i + MAX_MANUAL_DND_OPTIONS);
mZenRadioGroupContent.addView(radioButtonContent);
}
return contentView;
}
@VisibleForTesting
protected void setupRadioButtons(int zenDuration) {
int checkedIndex = ALWAYS_ASK_CONDITION_INDEX;
if (zenDuration == 0) {
checkedIndex = FOREVER_CONDITION_INDEX;
} else if (zenDuration > 0) {
checkedIndex = COUNTDOWN_CONDITION_INDEX;
}
bindTag(zenDuration, mZenRadioGroupContent.getChildAt(FOREVER_CONDITION_INDEX),
FOREVER_CONDITION_INDEX);
bindTag(zenDuration, mZenRadioGroupContent.getChildAt(COUNTDOWN_CONDITION_INDEX),
COUNTDOWN_CONDITION_INDEX);
bindTag(zenDuration, mZenRadioGroupContent.getChildAt(ALWAYS_ASK_CONDITION_INDEX),
ALWAYS_ASK_CONDITION_INDEX);
getConditionTagAt(checkedIndex).rb.setChecked(true);
}
private void bindTag(final int currZenDuration, final View row, final int rowIndex) {
final ConditionTag tag = row.getTag() != null ? (ConditionTag) row.getTag() :
new ConditionTag();
row.setTag(tag);
if (tag.rb == null) {
tag.rb = (RadioButton) mZenRadioGroup.getChildAt(rowIndex);
}
// if duration is set to forever or always prompt, then countdown time defaults to 1 hour
if (currZenDuration <= 0) {
tag.countdownZenDuration = MINUTE_BUCKETS[DEFAULT_BUCKET_INDEX];
} else {
tag.countdownZenDuration = currZenDuration;
}
tag.rb.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked) {
tag.rb.setChecked(true);
}
}
});
updateUi(tag, row, rowIndex);
}
@VisibleForTesting
protected ConditionTag getConditionTagAt(int index) {
return (ConditionTag) mZenRadioGroupContent.getChildAt(index).getTag();
}
private void setupUi(ConditionTag tag, View row) {
tag.lines = row.findViewById(android.R.id.content);
tag.line1 = (TextView) row.findViewById(android.R.id.text1);
// text2 is not used in zen duration dialog
row.findViewById(android.R.id.text2).setVisibility(View.GONE);
tag.lines.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
tag.rb.setChecked(true);
}
});
}
private void updateButtons(ConditionTag tag, View row, int rowIndex) {
// minus button
final ImageView button1 = (ImageView) row.findViewById(android.R.id.button1);
button1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
onClickTimeButton(row, tag, false /*down*/, rowIndex);
}
});
// plus button
final ImageView button2 = (ImageView) row.findViewById(android.R.id.button2);
button2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
onClickTimeButton(row, tag, true /*up*/, rowIndex);
}
});
final long time = tag.countdownZenDuration;
if (rowIndex == COUNTDOWN_CONDITION_INDEX) {
button1.setVisibility(View.VISIBLE);
button2.setVisibility(View.VISIBLE);
button1.setEnabled(time > MIN_BUCKET_MINUTES);
button2.setEnabled(tag.countdownZenDuration != MAX_BUCKET_MINUTES);
button1.setAlpha(button1.isEnabled() ? 1f : .5f);
button2.setAlpha(button2.isEnabled() ? 1f : .5f);
} else {
button1.setVisibility(View.GONE);
button2.setVisibility(View.GONE);
}
}
@VisibleForTesting
protected void updateUi(ConditionTag tag, View row, int rowIndex) {
if (tag.lines == null) {
setupUi(tag, row);
}
updateButtons(tag, row, rowIndex);
String radioContentText = "";
switch (rowIndex) {
case FOREVER_CONDITION_INDEX:
radioContentText = mContext.getString(
com.android.internal.R.string.zen_mode_forever);
break;
case COUNTDOWN_CONDITION_INDEX:
Condition condition = ZenModeConfig.toTimeCondition(mContext,
tag.countdownZenDuration, ActivityManager.getCurrentUser(), false);
radioContentText = condition.line1;
break;
case ALWAYS_ASK_CONDITION_INDEX:
radioContentText = mContext.getString(
R.string.zen_mode_duration_always_prompt_title);
break;
}
tag.line1.setText(radioContentText);
}
@VisibleForTesting
protected void onClickTimeButton(View row, ConditionTag tag, boolean up, int rowId) {
int newDndTimeDuration = -1;
final int N = MINUTE_BUCKETS.length;
if (mBucketIndex == -1) {
// not on a known index, search for the next or prev bucket by time
final long time = tag.countdownZenDuration;
for (int i = 0; i < N; i++) {
int j = up ? i : N - 1 - i;
final int bucketMinutes = MINUTE_BUCKETS[j];
if (up && bucketMinutes > time || !up && bucketMinutes < time) {
mBucketIndex = j;
newDndTimeDuration = bucketMinutes;
break;
}
}
if (newDndTimeDuration == -1) {
mBucketIndex = DEFAULT_BUCKET_INDEX;
newDndTimeDuration = MINUTE_BUCKETS[mBucketIndex];
}
} else {
// on a known index, simply increment or decrement
mBucketIndex = Math.max(0, Math.min(N - 1, mBucketIndex + (up ? 1 : -1)));
newDndTimeDuration = MINUTE_BUCKETS[mBucketIndex];
}
tag.countdownZenDuration = newDndTimeDuration;
bindTag(newDndTimeDuration, row, rowId);
tag.rb.setChecked(true);
}
// used as the view tag on condition rows
@VisibleForTesting
protected static class ConditionTag {
public RadioButton rb;
public View lines;
public TextView line1;
public int countdownZenDuration; // only important for countdown radio button
}
}

View File

@@ -0,0 +1,222 @@
/*
* 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.settingslib.notification;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyObject;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import android.app.AlertDialog;
import android.app.Fragment;
import android.app.NotificationManager;
import android.content.Context;
import android.content.ContentResolver;
import android.content.DialogInterface;
import android.content.res.Resources;
import android.net.Uri;
import android.provider.Settings;
import android.service.notification.Condition;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
import com.android.settingslib.SettingsLibRobolectricTestRunner;
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;
@RunWith(SettingsLibRobolectricTestRunner.class)
public class ZenDurationDialogTest {
private ZenDurationDialog mController;
private Context mContext;
private LayoutInflater mLayoutInflater;
private Condition mCountdownCondition;
private Condition mAlarmCondition;
private ContentResolver mContentResolver;
@Before
public void setup() {
mContext = RuntimeEnvironment.application;
mContentResolver = RuntimeEnvironment.application.getContentResolver();
mLayoutInflater = LayoutInflater.from(mContext);
mController = spy(new ZenDurationDialog(mContext));
mController.mLayoutInflater = mLayoutInflater;
mController.getContentView();
}
@Test
public void testAlwaysPrompt() {
Settings.Global.putInt(mContentResolver, Settings.Global.ZEN_DURATION,
Settings.Global.ZEN_DURATION_PROMPT);
mController.createDialog();
assertFalse(mController.getConditionTagAt(ZenDurationDialog.FOREVER_CONDITION_INDEX).rb
.isChecked());
assertFalse(mController.getConditionTagAt(ZenDurationDialog.COUNTDOWN_CONDITION_INDEX).rb
.isChecked());
assertTrue(mController.getConditionTagAt(
ZenDurationDialog.ALWAYS_ASK_CONDITION_INDEX).rb.isChecked());
}
@Test
public void testForever() {
Settings.Global.putInt(mContentResolver, Settings.Global.ZEN_DURATION,
Settings.Global.ZEN_DURATION_FOREVER);
mController.createDialog();
assertTrue(mController.getConditionTagAt(ZenDurationDialog.FOREVER_CONDITION_INDEX).rb
.isChecked());
assertFalse(mController.getConditionTagAt(ZenDurationDialog.COUNTDOWN_CONDITION_INDEX).rb
.isChecked());
assertFalse(mController.getConditionTagAt(
ZenDurationDialog.ALWAYS_ASK_CONDITION_INDEX).rb.isChecked());
}
@Test
public void testSpecificDuration() {
Settings.Global.putInt(mContentResolver, Settings.Global.ZEN_DURATION, 45);
mController.createDialog();
assertFalse(mController.getConditionTagAt(ZenDurationDialog.FOREVER_CONDITION_INDEX).rb
.isChecked());
assertTrue(mController.getConditionTagAt(ZenDurationDialog.COUNTDOWN_CONDITION_INDEX).rb
.isChecked());
assertFalse(mController.getConditionTagAt(
ZenDurationDialog.ALWAYS_ASK_CONDITION_INDEX).rb.isChecked());
}
@Test
public void testChooseAlwaysPromptSetting() {
Settings.Global.putInt(mContentResolver, Settings.Global.ZEN_DURATION,
Settings.Global.ZEN_DURATION_FOREVER);
AlertDialog dialog = (AlertDialog) mController.createDialog();
mController.getConditionTagAt(ZenDurationDialog.ALWAYS_ASK_CONDITION_INDEX).rb.setChecked(
true);
mController.updateZenDuration(Settings.Global.ZEN_DURATION_FOREVER);
assertEquals(Settings.Global.ZEN_DURATION_PROMPT, Settings.Global.getInt(mContentResolver,
Settings.Global.ZEN_DURATION, Settings.Global.ZEN_DURATION_FOREVER));
}
@Test
public void testChooseForeverSetting() {
Settings.Global.putInt(mContentResolver, Settings.Global.ZEN_DURATION,
Settings.Global.ZEN_DURATION_PROMPT);
AlertDialog dialog = (AlertDialog) mController.createDialog();
mController.getConditionTagAt(ZenDurationDialog.FOREVER_CONDITION_INDEX).rb.setChecked(
true);
mController.updateZenDuration(Settings.Global.ZEN_DURATION_PROMPT);
assertEquals(Settings.Global.ZEN_DURATION_FOREVER, Settings.Global.getInt(mContentResolver,
Settings.Global.ZEN_DURATION, Settings.Global.ZEN_DURATION_PROMPT));
}
@Test
public void testChooseTimeSetting() {
Settings.Global.putInt(mContentResolver, Settings.Global.ZEN_DURATION,
Settings.Global.ZEN_DURATION_PROMPT);
AlertDialog dialog = (AlertDialog) mController.createDialog();
mController.getConditionTagAt(ZenDurationDialog.COUNTDOWN_CONDITION_INDEX).rb.setChecked(
true);
mController.updateZenDuration(Settings.Global.ZEN_DURATION_PROMPT);
// countdown defaults to 60 minutes:
assertEquals(60, Settings.Global.getInt(mContentResolver,
Settings.Global.ZEN_DURATION, Settings.Global.ZEN_DURATION_PROMPT));
}
@Test
public void testGetTimeFromBucket() {
Settings.Global.putInt(mContentResolver, Settings.Global.ZEN_DURATION,
Settings.Global.ZEN_DURATION_PROMPT);
AlertDialog dialog = (AlertDialog) mController.createDialog();
// click time button starts at 60 minutes
// - 1 hour to MAX_BUCKET_MINUTES (12 hours), increments by 1 hour
// - 0-60 minutes increments by 15 minutes
View view = mController.mZenRadioGroupContent.getChildAt(
ZenDurationDialog.COUNTDOWN_CONDITION_INDEX);
ZenDurationDialog.ConditionTag tag = mController.getConditionTagAt(
ZenDurationDialog.COUNTDOWN_CONDITION_INDEX);
// test incrementing up:
mController.onClickTimeButton(view, tag, true, ZenDurationDialog.COUNTDOWN_CONDITION_INDEX);
assertEquals(120, tag.countdownZenDuration); // goes from 1 hour to 2 hours
// try clicking up 50 times - should max out at ZenDurationDialog.MAX_BUCKET_MINUTES
for (int i = 0; i < 50; i++) {
mController.onClickTimeButton(view, tag, true,
ZenDurationDialog.COUNTDOWN_CONDITION_INDEX);
}
assertEquals(ZenDurationDialog.MAX_BUCKET_MINUTES, tag.countdownZenDuration);
// reset, test incrementing down:
mController.mBucketIndex = -1; // reset current bucket index to reset countdownZenDuration
tag.countdownZenDuration = 60; // back to default
mController.onClickTimeButton(view, tag, false,
ZenDurationDialog.COUNTDOWN_CONDITION_INDEX);
assertEquals(45, tag.countdownZenDuration); // goes from 60 minutes to 45 minutes
// try clicking down 50 times - should stop at MIN_BUCKET_MINUTES
for (int i = 0; i < 50; i++) {
mController.onClickTimeButton(view, tag, false,
ZenDurationDialog.COUNTDOWN_CONDITION_INDEX);
}
assertEquals(ZenDurationDialog.MIN_BUCKET_MINUTES, tag.countdownZenDuration);
// reset countdownZenDuration to unbucketed number, should round change to nearest bucket
mController.mBucketIndex = -1;
tag.countdownZenDuration = 50;
mController.onClickTimeButton(view, tag, false,
ZenDurationDialog.COUNTDOWN_CONDITION_INDEX);
assertEquals(45, tag.countdownZenDuration);
mController.mBucketIndex = -1;
tag.countdownZenDuration = 50;
mController.onClickTimeButton(view, tag, true,
ZenDurationDialog.COUNTDOWN_CONDITION_INDEX);
assertEquals(60, tag.countdownZenDuration);
mController.mBucketIndex = -1;
tag.countdownZenDuration = 75;
mController.onClickTimeButton(view, tag, false,
ZenDurationDialog.COUNTDOWN_CONDITION_INDEX);
assertEquals(60, tag.countdownZenDuration);
mController.mBucketIndex = -1;
tag.countdownZenDuration = 75;
mController.onClickTimeButton(view, tag, true,
ZenDurationDialog.COUNTDOWN_CONDITION_INDEX);
assertEquals(120, tag.countdownZenDuration);
}
}

View File

@@ -200,4 +200,11 @@
<!-- Default for Settings.Secure.BACKUP_LOCAL_TRANSPORT_PARAMETERS -->
<string name="def_backup_local_transport_parameters"></string>
<!-- Default for Settings.Global.ZEN_DURATION
If 0, turning on dnd manually will last indefinitely.
Else if non-negative, turning on dnd manually will last for this many minutes.
Else (if negative), turning on dnd manually will surface a dialog that prompts
user to specify a duration.-->
<integer name="def_zen_duration">0</integer>
</resources>

View File

@@ -1141,6 +1141,9 @@ class SettingsProtoDumpUtil {
dumpSetting(s, p,
Settings.Global.APP_AUTO_RESTRICTION_ENABLED,
GlobalSettingsProto.APP_AUTO_RESTRICTION_ENABLED);
dumpSetting(s, p,
Settings.Global.ZEN_DURATION,
GlobalSettingsProto.ZEN_DURATION);
// Please insert new settings using the same order as in Settings.Global.
}

View File

@@ -2938,7 +2938,7 @@ public class SettingsProvider extends ContentProvider {
}
private final class UpgradeController {
private static final int SETTINGS_VERSION = 156;
private static final int SETTINGS_VERSION = 157;
private final int mUserId;
@@ -3604,7 +3604,21 @@ public class SettingsProvider extends ContentProvider {
currentVersion = 156;
}
if (currentVersion == 156) {
// Version 156: Set a default value for zen duration
final SettingsState globalSettings = getGlobalSettingsLocked();
final Setting currentSetting = globalSettings.getSettingLocked(
Global.ZEN_DURATION);
if (currentSetting.isNull()) {
String defaultZenDuration = Integer.toString(getContext()
.getResources().getInteger(R.integer.def_zen_duration));
globalSettings.insertSettingLocked(
Global.ZEN_DURATION, defaultZenDuration,
null, true, SettingsState.SYSTEM_PACKAGE_NAME);
}
currentVersion = 157;
}
// vXXX: Add new settings above this point.
if (currentVersion != newVersion) {

View File

@@ -19,6 +19,7 @@ package com.android.systemui.qs.tiles;
import static android.provider.Settings.Global.ZEN_MODE_ALARMS;
import static android.provider.Settings.Global.ZEN_MODE_OFF;
import android.app.ActivityManager;
import android.app.Dialog;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -28,6 +29,7 @@ import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.UserManager;
import android.provider.Settings;
import android.provider.Settings.Global;
@@ -139,15 +141,29 @@ public class DndTile extends QSTileImpl<BooleanState> {
@Override
public void showDetail(boolean show) {
mUiHandler.post(() -> {
Dialog mDialog = new EnableZenModeDialog(mContext).createDialog();
mDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
SystemUIDialog.setShowForAllUsers(mDialog, true);
SystemUIDialog.registerDismissListener(mDialog);
SystemUIDialog.setWindowOnTop(mDialog);
mUiHandler.post(() -> mDialog.show());
mHost.collapsePanels();
});
int zenDuration = Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.ZEN_DURATION, 0);
switch (zenDuration) {
case Settings.Global.ZEN_DURATION_PROMPT:
mUiHandler.post(() -> {
Dialog mDialog = new EnableZenModeDialog(mContext).createDialog();
mDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
SystemUIDialog.setShowForAllUsers(mDialog, true);
SystemUIDialog.registerDismissListener(mDialog);
SystemUIDialog.setWindowOnTop(mDialog);
mUiHandler.post(() -> mDialog.show());
mHost.collapsePanels();
});
break;
case Settings.Global.ZEN_DURATION_FOREVER:
mController.setZen(Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS, null, TAG);
break;
default:
Uri conditionId = ZenModeConfig.toTimeCondition(mContext, zenDuration,
ActivityManager.getCurrentUser(), true).id;
mController.setZen(Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS,
conditionId, TAG);
}
}
@Override

View File

@@ -5363,7 +5363,6 @@ message MetricsEvent {
// OS: P
ACTION_PANEL_VIEW_EXPAND = 1328;
// FIELD: Rotation of the device
// CATEGORY: GLOBAL_SYSTEM_UI
// OS: P