Merge "Using zen duration preference" into pi-dev
am: 75431913ef
Change-Id: Ic50e017f72e520da141580227648a7e639cc8cea
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
52
packages/SettingsLib/res/layout/zen_mode_duration_dialog.xml
Normal file
52
packages/SettingsLib/res/layout/zen_mode_duration_dialog.xml
Normal 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>
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
|
||||
@@ -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.
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -5363,7 +5363,6 @@ message MetricsEvent {
|
||||
// OS: P
|
||||
ACTION_PANEL_VIEW_EXPAND = 1328;
|
||||
|
||||
|
||||
// FIELD: Rotation of the device
|
||||
// CATEGORY: GLOBAL_SYSTEM_UI
|
||||
// OS: P
|
||||
|
||||
Reference in New Issue
Block a user