DND ixD changes
- Subtext in Settings > Sound updated - new icons for automatic dnd rules - no toast when toggling on/off dnd rules - dnd dialog has a warning if dnd will cause user to miss next alarm Test: make ROBOTEST_FILTER=ZenModePreferenceControllerTest RunSettingsRoboTests -j40 Fixes: 72494029 Fixes: 72655216 Fixes: 72655609 Change-Id: I9d86d82529079f35e362f93e10914f0a60229cd8
This commit is contained in:
34
res/drawable/ic_event.xml
Normal file
34
res/drawable/ic_event.xml
Normal file
@@ -0,0 +1,34 @@
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<item>
|
||||
<shape android:shape="oval">
|
||||
<solid
|
||||
android:color="?android:attr/colorAccent" />
|
||||
<size
|
||||
android:width="@dimen/dashboard_tile_image_size"
|
||||
android:height="@dimen/dashboard_tile_image_size" />
|
||||
</shape>
|
||||
</item>
|
||||
|
||||
<item
|
||||
android:width="@dimen/dashboard_tile_foreground_image_size"
|
||||
android:height="@dimen/dashboard_tile_foreground_image_size"
|
||||
android:start="@dimen/dashboard_tile_foreground_image_inset"
|
||||
android:top="@dimen/dashboard_tile_foreground_image_inset"
|
||||
android:drawable="@drawable/ic_event_white" />
|
||||
</layer-list>
|
25
res/drawable/ic_event_white.xml
Normal file
25
res/drawable/ic_event_white.xml
Normal file
@@ -0,0 +1,25 @@
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24.0dp"
|
||||
android:height="24.0dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
|
||||
<path
|
||||
android:fillColor="#FFFFFFFF"
|
||||
android:pathData="M17.0,12.0l-5.0,0.0l0.0,5.0l5.0,0.0l0.0,-5.0zM16.0,1.0l0.0,2.0L8.0,3.0L8.0,1.0L6.0,1.0l0.0,2.0L5.0,3.0c-1.11,0.0 -1.9,0.9 -1.99,2.0L3.0,19.0c0.0,1.0 0.89,2.0 2.0,2.0l14.0,0.0c1.1,0.0 2.0,-0.9 2.0,-2.0L21.0,5.0c0.0,-1.1 -0.9,-2.0 -2.0,-2.0l-1.0,0.0L18.0,1.0l-2.0,0.0zm3.0,18.0L5.0,19.0L5.0,8.0l14.0,0.0l0.0,11.0z"/>
|
||||
</vector>
|
34
res/drawable/ic_timelapse.xml
Normal file
34
res/drawable/ic_timelapse.xml
Normal file
@@ -0,0 +1,34 @@
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<item>
|
||||
<shape android:shape="oval">
|
||||
<solid
|
||||
android:color="?android:attr/colorAccent" />
|
||||
<size
|
||||
android:width="@dimen/dashboard_tile_image_size"
|
||||
android:height="@dimen/dashboard_tile_image_size" />
|
||||
</shape>
|
||||
</item>
|
||||
|
||||
<item
|
||||
android:width="@dimen/dashboard_tile_foreground_image_size"
|
||||
android:height="@dimen/dashboard_tile_foreground_image_size"
|
||||
android:start="@dimen/dashboard_tile_foreground_image_inset"
|
||||
android:top="@dimen/dashboard_tile_foreground_image_inset"
|
||||
android:drawable="@drawable/ic_timelapse_white" />
|
||||
</layer-list>
|
25
res/drawable/ic_timelapse_white.xml
Normal file
25
res/drawable/ic_timelapse_white.xml
Normal file
@@ -0,0 +1,25 @@
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24.0dp"
|
||||
android:height="24.0dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
|
||||
<path
|
||||
android:fillColor="#FFFFFFFF"
|
||||
android:pathData="M16.24,7.76C15.07,6.59 13.54,6.0 12.0,6.0l0.0,6.0l-4.24,4.24c2.34,2.34 6.14,2.34 8.49,0.0 2.34,-2.34 2.34,-6.14 -0.01,-8.48zM12.0,2.0C6.48,2.0 2.0,6.48 2.0,12.0s4.48,10.0 10.0,10.0 10.0,-4.48 10.0,-10.0S17.52,2.0 12.0,2.0zm0.0,18.0c-4.42,0.0 -8.0,-3.58 -8.0,-8.0s3.58,-8.0 8.0,-8.0 8.0,3.58 8.0,8.0 -3.58,8.0 -8.0,8.0z"/>
|
||||
</vector>
|
@@ -17,31 +17,25 @@
|
||||
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="bottom"
|
||||
android:paddingStart="72dp"
|
||||
android:paddingEnd="72dp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<Button
|
||||
android:id="@+id/zen_mode_settings_turn_on_button"
|
||||
style="@style/ActionPrimaryButton"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1"
|
||||
android:layout_marginStart="@dimen/screen_margin_sides"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="left"
|
||||
android:text="@string/zen_mode_button_turn_on"
|
||||
android:paddingEnd="8dp" />
|
||||
android:text="@string/zen_mode_button_turn_on"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/zen_mode_settings_turn_off_button"
|
||||
style="@style/ActionSecondaryButton"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1"
|
||||
android:layout_marginStart="@dimen/screen_margin_sides"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="left"
|
||||
android:text="@string/zen_mode_button_turn_off"
|
||||
android:paddingEnd="8dp" />
|
||||
android:text="@string/zen_mode_button_turn_off" />
|
||||
|
||||
</LinearLayout>
|
@@ -23,10 +23,9 @@
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/icon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
/>
|
||||
android:layout_width="@dimen/app_icon_size"
|
||||
android:layout_height="@dimen/app_icon_size"
|
||||
android:layout_gravity="center"/>
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="wrap_content"
|
||||
|
@@ -6937,6 +6937,21 @@
|
||||
<!-- [CHAR LIMIT=20] Accessibility string for current zen mode and selected exit condition. A template that simply concatenates existing mode string and the current condition description. -->
|
||||
<string name="zen_mode_and_condition"><xliff:g id="zen_mode" example="Priority interruptions only">%1$s</xliff:g>. <xliff:g id="exit_condition" example="For one hour">%2$s</xliff:g></string>
|
||||
|
||||
<!-- Sound settings screen, summary format of do not disturb when on. [CHAR LIMIT=NONE] -->
|
||||
<string name="zen_mode_sound_summary_on">On / <xliff:g name="dnd_summary" example="No sound except alarms and media">%1$s</xliff:g></string>
|
||||
|
||||
<!-- Sound settings screen, summary format of do not disturb when off with extra information. [CHAR LIMIT=NONE] -->
|
||||
<string name="zen_mode_sound_summary_off_with_info">Off / <xliff:g name="dnd_summary" example="1 rule can turn on automatically">%1$s</xliff:g></string>
|
||||
|
||||
<!-- Sound settings screen, summary format of do not disturb when off with no extra information. [CHAR LIMIT=NONE] -->
|
||||
<string name="zen_mode_sound_summary_off">Off</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>
|
||||
<item quantity="other"><xliff:g id="on_count" example="3">%d</xliff:g> rules can turn on automatically</item>
|
||||
</plurals>
|
||||
|
||||
<!-- Work Sounds: Work sound settings section header. [CHAR LIMIT=50] -->
|
||||
<string name="sound_work_settings">Work profile sounds</string>
|
||||
|
||||
|
@@ -1,467 +0,0 @@
|
||||
package com.android.settings.notification;
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import static android.util.Log.wtf;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.ActivityManager;
|
||||
import android.app.AlarmManager;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.Dialog;
|
||||
import android.app.NotificationManager;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.provider.Settings;
|
||||
import android.service.notification.Condition;
|
||||
import android.service.notification.ZenModeConfig;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
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.annotations.VisibleForTesting;
|
||||
import com.android.internal.logging.MetricsLogger;
|
||||
import com.android.internal.logging.nano.MetricsProto;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Calendar;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.Objects;
|
||||
|
||||
public class EnableZenModeDialog extends InstrumentedDialogFragment {
|
||||
|
||||
private static final String TAG = "EnableZenModeDialog";
|
||||
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
|
||||
|
||||
private static final int[] MINUTE_BUCKETS = ZenModeConfig.MINUTE_BUCKETS;
|
||||
private static final int MIN_BUCKET_MINUTES = MINUTE_BUCKETS[0];
|
||||
private 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
|
||||
public static final int FOREVER_CONDITION_INDEX = 0;
|
||||
@VisibleForTesting
|
||||
public static final int COUNTDOWN_CONDITION_INDEX = 1;
|
||||
@VisibleForTesting
|
||||
public static final int COUNTDOWN_ALARM_CONDITION_INDEX = 2;
|
||||
@VisibleForTesting
|
||||
protected Activity mActivity;
|
||||
|
||||
private static final int SECONDS_MS = 1000;
|
||||
private static final int MINUTES_MS = 60 * SECONDS_MS;
|
||||
|
||||
@VisibleForTesting
|
||||
protected Uri mForeverId;
|
||||
private int mBucketIndex = -1;
|
||||
|
||||
private AlarmManager mAlarmManager;
|
||||
private int mUserId;
|
||||
private boolean mAttached;
|
||||
|
||||
@VisibleForTesting
|
||||
protected Context mContext;
|
||||
|
||||
private RadioGroup mZenRadioGroup;
|
||||
@VisibleForTesting
|
||||
protected LinearLayout mZenRadioGroupContent;
|
||||
private int MAX_MANUAL_DND_OPTIONS = 3;
|
||||
|
||||
@Override
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
NotificationManager noMan = (NotificationManager) getContext().
|
||||
getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
mContext = getContext();
|
||||
mForeverId = Condition.newId(mContext).appendPath("forever").build();
|
||||
mAlarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
|
||||
mUserId = mContext.getUserId();
|
||||
mAttached = false;
|
||||
|
||||
final AlertDialog.Builder builder = new AlertDialog.Builder(getContext())
|
||||
.setTitle(R.string.zen_mode_settings_turn_on_dialog_title)
|
||||
.setNegativeButton(R.string.cancel, null)
|
||||
.setPositiveButton(R.string.zen_mode_enable_dialog_turn_on,
|
||||
new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
int checkedId = mZenRadioGroup.getCheckedRadioButtonId();
|
||||
ConditionTag tag = getConditionTagAt(checkedId);
|
||||
|
||||
if (isForever(tag.condition)) {
|
||||
MetricsLogger.action(getContext(),
|
||||
MetricsProto.MetricsEvent.
|
||||
NOTIFICATION_ZEN_MODE_TOGGLE_ON_FOREVER);
|
||||
} else if (isAlarm(tag.condition)) {
|
||||
MetricsLogger.action(getContext(),
|
||||
MetricsProto.MetricsEvent.
|
||||
NOTIFICATION_ZEN_MODE_TOGGLE_ON_ALARM);
|
||||
} else if (isCountdown(tag.condition)) {
|
||||
MetricsLogger.action(getContext(),
|
||||
MetricsProto.MetricsEvent.
|
||||
NOTIFICATION_ZEN_MODE_TOGGLE_ON_COUNTDOWN);
|
||||
} else {
|
||||
wtf(TAG, "Invalid manual condition: " + tag.condition);
|
||||
}
|
||||
// always triggers priority-only dnd with chosen condition
|
||||
noMan.setZenMode(Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS,
|
||||
getRealConditionId(tag.condition), TAG);
|
||||
}
|
||||
});
|
||||
|
||||
View contentView = getContentView();
|
||||
bindConditions(forever());
|
||||
builder.setView(contentView);
|
||||
return builder.create();
|
||||
}
|
||||
|
||||
private void hideAllConditions() {
|
||||
final int N = mZenRadioGroupContent.getChildCount();
|
||||
for (int i = 0; i < N; i++) {
|
||||
mZenRadioGroupContent.getChildAt(i).setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
protected View getContentView() {
|
||||
if (mActivity == null) {
|
||||
mActivity = getActivity();
|
||||
}
|
||||
final LayoutInflater inflater = mActivity.getLayoutInflater();
|
||||
View contentView = inflater.inflate(R.layout.zen_mode_turn_on_dialog_container, null);
|
||||
ScrollView container = (ScrollView) contentView.findViewById(R.id.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 = inflater.inflate(R.layout.zen_mode_radio_button,
|
||||
mZenRadioGroup, false);
|
||||
mZenRadioGroup.addView(radioButton);
|
||||
radioButton.setId(i);
|
||||
|
||||
final View radioButtonContent = inflater.inflate(R.layout.zen_mode_condition,
|
||||
mZenRadioGroupContent, false);
|
||||
radioButtonContent.setId(i + MAX_MANUAL_DND_OPTIONS);
|
||||
mZenRadioGroupContent.addView(radioButtonContent);
|
||||
}
|
||||
hideAllConditions();
|
||||
return contentView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMetricsCategory() {
|
||||
return MetricsProto.MetricsEvent.NOTIFICATION_ZEN_MODE_ENABLE_DIALOG;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
protected void bind(final Condition condition, final View row, final int rowId) {
|
||||
if (condition == null) throw new IllegalArgumentException("condition must not be null");
|
||||
final boolean enabled = condition.state == Condition.STATE_TRUE;
|
||||
final ConditionTag tag = row.getTag() != null ? (ConditionTag) row.getTag() :
|
||||
new ConditionTag();
|
||||
row.setTag(tag);
|
||||
final boolean first = tag.rb == null;
|
||||
if (tag.rb == null) {
|
||||
tag.rb = (RadioButton) mZenRadioGroup.getChildAt(rowId);
|
||||
}
|
||||
tag.condition = condition;
|
||||
final Uri conditionId = getConditionId(tag.condition);
|
||||
if (DEBUG) Log.d(TAG, "bind i=" + mZenRadioGroupContent.indexOfChild(row) + " first="
|
||||
+ first + " condition=" + conditionId);
|
||||
tag.rb.setEnabled(enabled);
|
||||
tag.rb.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
||||
if (isChecked) {
|
||||
tag.rb.setChecked(true);
|
||||
if (DEBUG) Log.d(TAG, "onCheckedChanged " + conditionId);
|
||||
MetricsLogger.action(mContext,
|
||||
MetricsProto.MetricsEvent.QS_DND_CONDITION_SELECT);
|
||||
announceConditionSelection(tag);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
updateUi(tag, row, condition, enabled, rowId, conditionId);
|
||||
row.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
protected ConditionTag getConditionTagAt(int index) {
|
||||
return (ConditionTag) mZenRadioGroupContent.getChildAt(index).getTag();
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
protected void bindConditions(Condition c) {
|
||||
// forever
|
||||
bind(forever(), mZenRadioGroupContent.getChildAt(FOREVER_CONDITION_INDEX),
|
||||
FOREVER_CONDITION_INDEX);
|
||||
if (c == null) {
|
||||
bindGenericCountdown();
|
||||
bindNextAlarm(getTimeUntilNextAlarmCondition());
|
||||
} else if (isForever(c)) {
|
||||
getConditionTagAt(FOREVER_CONDITION_INDEX).rb.setChecked(true);
|
||||
bindGenericCountdown();
|
||||
bindNextAlarm(getTimeUntilNextAlarmCondition());
|
||||
} else {
|
||||
if (isAlarm(c)) {
|
||||
bindGenericCountdown();
|
||||
bindNextAlarm(c);
|
||||
getConditionTagAt(COUNTDOWN_ALARM_CONDITION_INDEX).rb.setChecked(true);
|
||||
} else if (isCountdown(c)) {
|
||||
bindNextAlarm(getTimeUntilNextAlarmCondition());
|
||||
bind(c, mZenRadioGroupContent.getChildAt(COUNTDOWN_CONDITION_INDEX),
|
||||
COUNTDOWN_CONDITION_INDEX);
|
||||
getConditionTagAt(COUNTDOWN_CONDITION_INDEX).rb.setChecked(true);
|
||||
} else {
|
||||
wtf(TAG, "Invalid manual condition: " + c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static Uri getConditionId(Condition condition) {
|
||||
return condition != null ? condition.id : null;
|
||||
}
|
||||
|
||||
public Condition forever() {
|
||||
Uri foreverId = Condition.newId(mContext).appendPath("forever").build();
|
||||
return new Condition(foreverId, foreverSummary(mContext), "", "", 0 /*icon*/,
|
||||
Condition.STATE_TRUE, 0 /*flags*/);
|
||||
}
|
||||
|
||||
public long getNextAlarm() {
|
||||
final AlarmManager.AlarmClockInfo info = mAlarmManager.getNextAlarmClock(mUserId);
|
||||
return info != null ? info.getTriggerTime() : 0;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
protected boolean isAlarm(Condition c) {
|
||||
return c != null && ZenModeConfig.isValidCountdownToAlarmConditionId(c.id);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
protected boolean isCountdown(Condition c) {
|
||||
return c != null && ZenModeConfig.isValidCountdownConditionId(c.id);
|
||||
}
|
||||
|
||||
private boolean isForever(Condition c) {
|
||||
return c != null && mForeverId.equals(c.id);
|
||||
}
|
||||
|
||||
private Uri getRealConditionId(Condition condition) {
|
||||
return isForever(condition) ? null : getConditionId(condition);
|
||||
}
|
||||
|
||||
private String foreverSummary(Context context) {
|
||||
return context.getString(com.android.internal.R.string.zen_mode_forever);
|
||||
}
|
||||
|
||||
private static void setToMidnight(Calendar calendar) {
|
||||
calendar.set(Calendar.HOUR_OF_DAY, 0);
|
||||
calendar.set(Calendar.MINUTE, 0);
|
||||
calendar.set(Calendar.SECOND, 0);
|
||||
calendar.set(Calendar.MILLISECOND, 0);
|
||||
}
|
||||
|
||||
// Returns a time condition if the next alarm is within the next week.
|
||||
@VisibleForTesting
|
||||
protected Condition getTimeUntilNextAlarmCondition() {
|
||||
GregorianCalendar weekRange = new GregorianCalendar();
|
||||
setToMidnight(weekRange);
|
||||
weekRange.add(Calendar.DATE, 6);
|
||||
final long nextAlarmMs = getNextAlarm();
|
||||
if (nextAlarmMs > 0) {
|
||||
GregorianCalendar nextAlarm = new GregorianCalendar();
|
||||
nextAlarm.setTimeInMillis(nextAlarmMs);
|
||||
setToMidnight(nextAlarm);
|
||||
|
||||
if (weekRange.compareTo(nextAlarm) >= 0) {
|
||||
return ZenModeConfig.toNextAlarmCondition(mContext, nextAlarmMs,
|
||||
ActivityManager.getCurrentUser());
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
protected void bindGenericCountdown() {
|
||||
mBucketIndex = DEFAULT_BUCKET_INDEX;
|
||||
Condition countdown = ZenModeConfig.toTimeCondition(mContext,
|
||||
MINUTE_BUCKETS[mBucketIndex], ActivityManager.getCurrentUser());
|
||||
if (!mAttached || getConditionTagAt(COUNTDOWN_CONDITION_INDEX).condition == null) {
|
||||
bind(countdown, mZenRadioGroupContent.getChildAt(COUNTDOWN_CONDITION_INDEX),
|
||||
COUNTDOWN_CONDITION_INDEX);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateUi(ConditionTag tag, View row, Condition condition,
|
||||
boolean enabled, int rowId, Uri conditionId) {
|
||||
if (tag.lines == null) {
|
||||
tag.lines = row.findViewById(android.R.id.content);
|
||||
}
|
||||
if (tag.line1 == null) {
|
||||
tag.line1 = (TextView) row.findViewById(android.R.id.text1);
|
||||
}
|
||||
|
||||
if (tag.line2 == null) {
|
||||
tag.line2 = (TextView) row.findViewById(android.R.id.text2);
|
||||
}
|
||||
|
||||
final String line1 = !TextUtils.isEmpty(condition.line1) ? condition.line1
|
||||
: condition.summary;
|
||||
final String line2 = condition.line2;
|
||||
tag.line1.setText(line1);
|
||||
if (TextUtils.isEmpty(line2)) {
|
||||
tag.line2.setVisibility(View.GONE);
|
||||
} else {
|
||||
tag.line2.setVisibility(View.VISIBLE);
|
||||
tag.line2.setText(line2);
|
||||
}
|
||||
tag.lines.setEnabled(enabled);
|
||||
tag.lines.setAlpha(enabled ? 1 : .4f);
|
||||
|
||||
tag.lines.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
tag.rb.setChecked(true);
|
||||
}
|
||||
});
|
||||
|
||||
// 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*/, rowId);
|
||||
}
|
||||
});
|
||||
|
||||
// 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*/, rowId);
|
||||
}
|
||||
});
|
||||
|
||||
final long time = ZenModeConfig.tryParseCountdownConditionId(conditionId);
|
||||
if (rowId == COUNTDOWN_CONDITION_INDEX && time > 0) {
|
||||
button1.setVisibility(View.VISIBLE);
|
||||
button2.setVisibility(View.VISIBLE);
|
||||
if (mBucketIndex > -1) {
|
||||
button1.setEnabled(mBucketIndex > 0);
|
||||
button2.setEnabled(mBucketIndex < MINUTE_BUCKETS.length - 1);
|
||||
} else {
|
||||
final long span = time - System.currentTimeMillis();
|
||||
button1.setEnabled(span > MIN_BUCKET_MINUTES * MINUTES_MS);
|
||||
final Condition maxCondition = ZenModeConfig.toTimeCondition(mContext,
|
||||
MAX_BUCKET_MINUTES, ActivityManager.getCurrentUser());
|
||||
button2.setEnabled(!Objects.equals(condition.summary, maxCondition.summary));
|
||||
}
|
||||
|
||||
button1.setAlpha(button1.isEnabled() ? 1f : .5f);
|
||||
button2.setAlpha(button2.isEnabled() ? 1f : .5f);
|
||||
} else {
|
||||
button1.setVisibility(View.GONE);
|
||||
button2.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
protected void bindNextAlarm(Condition c) {
|
||||
View alarmContent = mZenRadioGroupContent.getChildAt(COUNTDOWN_ALARM_CONDITION_INDEX);
|
||||
ConditionTag tag = (ConditionTag) alarmContent.getTag();
|
||||
|
||||
if (c != null && (!mAttached || tag == null || tag.condition == null)) {
|
||||
bind(c, alarmContent, COUNTDOWN_ALARM_CONDITION_INDEX);
|
||||
}
|
||||
|
||||
// hide the alarm radio button if there isn't a "next alarm condition"
|
||||
tag = (ConditionTag) alarmContent.getTag();
|
||||
boolean showAlarm = tag != null && tag.condition != null;
|
||||
mZenRadioGroup.getChildAt(COUNTDOWN_ALARM_CONDITION_INDEX).setVisibility(
|
||||
showAlarm ? View.VISIBLE : View.GONE);
|
||||
alarmContent.setVisibility(showAlarm ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
|
||||
private void onClickTimeButton(View row, ConditionTag tag, boolean up, int rowId) {
|
||||
MetricsLogger.action(mContext, MetricsProto.MetricsEvent.QS_DND_TIME, up);
|
||||
Condition newCondition = null;
|
||||
final int N = MINUTE_BUCKETS.length;
|
||||
if (mBucketIndex == -1) {
|
||||
// not on a known index, search for the next or prev bucket by time
|
||||
final Uri conditionId = getConditionId(tag.condition);
|
||||
final long time = ZenModeConfig.tryParseCountdownConditionId(conditionId);
|
||||
final long now = System.currentTimeMillis();
|
||||
for (int i = 0; i < N; i++) {
|
||||
int j = up ? i : N - 1 - i;
|
||||
final int bucketMinutes = MINUTE_BUCKETS[j];
|
||||
final long bucketTime = now + bucketMinutes * MINUTES_MS;
|
||||
if (up && bucketTime > time || !up && bucketTime < time) {
|
||||
mBucketIndex = j;
|
||||
newCondition = ZenModeConfig.toTimeCondition(mContext,
|
||||
bucketTime, bucketMinutes, ActivityManager.getCurrentUser(),
|
||||
false /*shortVersion*/);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (newCondition == null) {
|
||||
mBucketIndex = DEFAULT_BUCKET_INDEX;
|
||||
newCondition = ZenModeConfig.toTimeCondition(mContext,
|
||||
MINUTE_BUCKETS[mBucketIndex], ActivityManager.getCurrentUser());
|
||||
}
|
||||
} else {
|
||||
// on a known index, simply increment or decrement
|
||||
mBucketIndex = Math.max(0, Math.min(N - 1, mBucketIndex + (up ? 1 : -1)));
|
||||
newCondition = ZenModeConfig.toTimeCondition(mContext,
|
||||
MINUTE_BUCKETS[mBucketIndex], ActivityManager.getCurrentUser());
|
||||
}
|
||||
bind(newCondition, row, rowId);
|
||||
tag.rb.setChecked(true);
|
||||
announceConditionSelection(tag);
|
||||
}
|
||||
|
||||
private void announceConditionSelection(ConditionTag tag) {
|
||||
// condition will always be priority-only
|
||||
String modeText = mContext.getString(R.string.zen_interruption_level_priority);
|
||||
if (tag.line1 != null) {
|
||||
mZenRadioGroupContent.announceForAccessibility(mContext.getString(
|
||||
R.string.zen_mode_and_condition, modeText, tag.line1.getText()));
|
||||
}
|
||||
}
|
||||
|
||||
// used as the view tag on condition rows
|
||||
@VisibleForTesting
|
||||
protected static class ConditionTag {
|
||||
public RadioButton rb;
|
||||
public View lines;
|
||||
public TextView line1;
|
||||
public TextView line2;
|
||||
public Condition condition;
|
||||
}
|
||||
}
|
@@ -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 SettingsEnableZenModeDialog extends InstrumentedDialogFragment {
|
||||
|
||||
@Override
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
return new com.android.settingslib.notification.EnableZenModeDialog(
|
||||
getContext()).createDialog();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMetricsCategory() {
|
||||
return MetricsProto.MetricsEvent.NOTIFICATION_ZEN_MODE_ENABLE_DIALOG;
|
||||
}
|
||||
}
|
@@ -180,7 +180,7 @@ public class SoundSettings extends DashboardFragment {
|
||||
SoundSettings fragment, VolumeSeekBarPreference.Callback callback,
|
||||
Lifecycle lifecycle) {
|
||||
final List<AbstractPreferenceController> controllers = new ArrayList<>();
|
||||
controllers.add(new ZenModePreferenceController(context));
|
||||
controllers.add(new ZenModePreferenceController(context, lifecycle));
|
||||
controllers.add(new VibrateWhenRingPreferenceController(context));
|
||||
|
||||
// === Volumes ===
|
||||
@@ -264,7 +264,7 @@ public class SoundSettings extends DashboardFragment {
|
||||
public List<String> getNonIndexableKeys(Context context) {
|
||||
List<String> keys = super.getNonIndexableKeys(context);
|
||||
// Duplicate results
|
||||
keys.add((new ZenModePreferenceController(context)).getPreferenceKey());
|
||||
keys.add((new ZenModePreferenceController(context, null)).getPreferenceKey());
|
||||
return keys;
|
||||
}
|
||||
};
|
||||
|
@@ -24,6 +24,7 @@ import android.content.Context;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.service.notification.ZenModeConfig;
|
||||
import android.support.v14.preference.PreferenceFragment;
|
||||
import android.support.v7.preference.Preference;
|
||||
import android.util.Slog;
|
||||
@@ -101,6 +102,13 @@ public class ZenAutomaticRuleHeaderPreferenceController extends AbstractZenModeP
|
||||
PackageManager packageManager = mContext.getPackageManager();
|
||||
ApplicationInfo info = packageManager.getApplicationInfo(
|
||||
mRule.getOwner().getPackageName(), 0);
|
||||
if (info.isSystemApp()) {
|
||||
if (ZenModeConfig.isValidScheduleConditionId(mRule.getConditionId())) {
|
||||
return mContext.getDrawable(R.drawable.ic_timelapse);
|
||||
} else if (ZenModeConfig.isValidEventConditionId(mRule.getConditionId())) {
|
||||
return mContext.getDrawable(R.drawable.ic_event);
|
||||
}
|
||||
}
|
||||
return info.loadIcon(packageManager);
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
Slog.w(TAG, "Unable to load icon - PackageManager.NameNotFoundException");
|
||||
|
@@ -22,7 +22,6 @@ import android.content.Context;
|
||||
import android.support.v7.preference.Preference;
|
||||
import android.support.v7.preference.PreferenceScreen;
|
||||
import android.widget.Switch;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.applications.LayoutPreference;
|
||||
@@ -36,14 +35,11 @@ public class ZenAutomaticRuleSwitchPreferenceController extends
|
||||
private static final String KEY = "zen_automatic_rule_switch";
|
||||
private AutomaticZenRule mRule;
|
||||
private String mId;
|
||||
private Toast mEnabledToast;
|
||||
private int mToastTextResource;
|
||||
private SwitchBar mSwitchBar;
|
||||
|
||||
public ZenAutomaticRuleSwitchPreferenceController(Context context, Fragment parent,
|
||||
int toastTextResource, Lifecycle lifecycle) {
|
||||
Lifecycle lifecycle) {
|
||||
super(context, KEY, parent, lifecycle);
|
||||
mToastTextResource = toastTextResource;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -92,16 +88,5 @@ public class ZenAutomaticRuleSwitchPreferenceController extends
|
||||
if (enabled == mRule.isEnabled()) return;
|
||||
mRule.setEnabled(enabled);
|
||||
mBackend.setZenRule(mId, mRule);
|
||||
if (enabled) {
|
||||
final int toastText = mToastTextResource;
|
||||
if (toastText != 0) {
|
||||
mEnabledToast = Toast.makeText(mContext, toastText, Toast.LENGTH_SHORT);
|
||||
mEnabledToast.show();
|
||||
}
|
||||
} else {
|
||||
if (mEnabledToast != null) {
|
||||
mEnabledToast.cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -62,7 +62,7 @@ public class ZenModeButtonPreferenceController extends AbstractZenModePreference
|
||||
mZenButtonOn = (Button) ((LayoutPreference) preference)
|
||||
.findViewById(R.id.zen_mode_settings_turn_on_button);
|
||||
mZenButtonOn.setOnClickListener(v ->
|
||||
new EnableZenModeDialog().show(mFragment, TAG));
|
||||
new SettingsEnableZenModeDialog().show(mFragment, TAG));
|
||||
}
|
||||
|
||||
if (null == mZenButtonOff) {
|
||||
|
@@ -82,8 +82,7 @@ public class ZenModeEventRuleSettings extends ZenModeRuleSettingsBase {
|
||||
List<AbstractPreferenceController> controllers = new ArrayList<>();
|
||||
mHeader = new ZenAutomaticRuleHeaderPreferenceController(context, this,
|
||||
getLifecycle());
|
||||
mSwitch = new ZenAutomaticRuleSwitchPreferenceController(context, this,
|
||||
R.string.zen_event_rule_enabled_toast, getLifecycle());
|
||||
mSwitch = new ZenAutomaticRuleSwitchPreferenceController(context, this, getLifecycle());
|
||||
controllers.add(mHeader);
|
||||
controllers.add(mSwitch);
|
||||
return controllers;
|
||||
|
@@ -16,18 +16,56 @@
|
||||
|
||||
package com.android.settings.notification;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.database.ContentObserver;
|
||||
import android.net.Uri;
|
||||
import android.os.Handler;
|
||||
import android.os.UserHandle;
|
||||
import android.provider.Settings;
|
||||
import android.support.v7.preference.Preference;
|
||||
import android.support.v7.preference.PreferenceScreen;
|
||||
import android.util.Slog;
|
||||
|
||||
public class ZenModePreferenceController extends AdjustVolumeRestrictedPreferenceController {
|
||||
import com.android.settingslib.core.lifecycle.Lifecycle;
|
||||
import com.android.settingslib.core.lifecycle.LifecycleObserver;
|
||||
import com.android.settingslib.core.lifecycle.events.OnPause;
|
||||
import com.android.settingslib.core.lifecycle.events.OnResume;
|
||||
|
||||
public class ZenModePreferenceController extends AdjustVolumeRestrictedPreferenceController
|
||||
implements LifecycleObserver, OnResume, OnPause {
|
||||
|
||||
private static final String KEY_ZEN_MODE = "zen_mode";
|
||||
|
||||
private SettingObserver mSettingObserver;
|
||||
private ZenModeSettings.SummaryBuilder mSummaryBuilder;
|
||||
|
||||
public ZenModePreferenceController(Context context) {
|
||||
public ZenModePreferenceController(Context context, Lifecycle lifecycle) {
|
||||
super(context);
|
||||
mSummaryBuilder = new ZenModeSettings.SummaryBuilder(context);
|
||||
|
||||
if (lifecycle != null) {
|
||||
lifecycle.addObserver(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void displayPreference(PreferenceScreen screen) {
|
||||
super.displayPreference(screen);
|
||||
mSettingObserver = new SettingObserver(screen.findPreference(KEY_ZEN_MODE));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
if (mSettingObserver != null) {
|
||||
mSettingObserver.register(mContext.getContentResolver());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
if (mSettingObserver != null) {
|
||||
mSettingObserver.unregister(mContext.getContentResolver());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -44,7 +82,41 @@ public class ZenModePreferenceController extends AdjustVolumeRestrictedPreferenc
|
||||
public void updateState(Preference preference) {
|
||||
super.updateState(preference);
|
||||
if (preference.isEnabled()) {
|
||||
preference.setSummary(mSummaryBuilder.getAutomaticRulesSummary());
|
||||
preference.setSummary(mSummaryBuilder.getSoundSummary());
|
||||
}
|
||||
}
|
||||
|
||||
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 Preference mPreference;
|
||||
|
||||
public SettingObserver(Preference preference) {
|
||||
super(new Handler());
|
||||
mPreference = preference;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
public void unregister(ContentResolver cr) {
|
||||
cr.unregisterContentObserver(this);
|
||||
}
|
||||
|
||||
@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)) {
|
||||
updateState(mPreference);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -200,8 +200,7 @@ public class ZenModeScheduleRuleSettings extends ZenModeRuleSettingsBase {
|
||||
List<AbstractPreferenceController> controllers = new ArrayList<>();
|
||||
mHeader = new ZenAutomaticRuleHeaderPreferenceController(context, this,
|
||||
getLifecycle());
|
||||
mSwitch = new ZenAutomaticRuleSwitchPreferenceController(context, this,
|
||||
R.string.zen_schedule_rule_enabled_toast, getLifecycle());
|
||||
mSwitch = new ZenAutomaticRuleSwitchPreferenceController(context, this, getLifecycle());
|
||||
|
||||
controllers.add(mHeader);
|
||||
controllers.add(mSwitch);
|
||||
|
@@ -115,6 +115,26 @@ public class ZenModeSettings extends ZenModeSettingsBase {
|
||||
return mContext.getString(R.string.zen_mode_behavior_summary_custom);
|
||||
}
|
||||
|
||||
String getSoundSummary() {
|
||||
int zenMode = NotificationManager.from(mContext).getZenMode();
|
||||
|
||||
if (zenMode != Settings.Global.ZEN_MODE_OFF) {
|
||||
Policy policy = NotificationManager.from(mContext).getNotificationPolicy();
|
||||
return mContext.getString(R.string.zen_mode_sound_summary_on,
|
||||
getBehaviorSettingSummary(policy, zenMode));
|
||||
} else {
|
||||
final int count = getEnabledAutomaticRulesCount();
|
||||
if (count > 0) {
|
||||
return mContext.getString(R.string.zen_mode_sound_summary_off_with_info,
|
||||
mContext.getResources().getQuantityString(
|
||||
R.plurals.zen_mode_sound_summary_summary_off_info,
|
||||
count, count));
|
||||
}
|
||||
|
||||
return mContext.getString(R.string.zen_mode_sound_summary_off);
|
||||
}
|
||||
}
|
||||
|
||||
String getAutomaticRulesSummary() {
|
||||
final int count = getEnabledAutomaticRulesCount();
|
||||
return count == 0 ? mContext.getString(R.string.zen_mode_settings_summary_off)
|
||||
|
@@ -119,13 +119,21 @@ public class ZenRuleSelectionDialog extends InstrumentedDialogFragment {
|
||||
final LinearLayout v = (LinearLayout) LayoutInflater.from(mContext).inflate(
|
||||
R.layout.zen_rule_type, null, false);
|
||||
|
||||
LoadIconTask task = new LoadIconTask((ImageView) v.findViewById(R.id.icon));
|
||||
task.execute(info);
|
||||
ImageView iconView = v.findViewById(R.id.icon);
|
||||
((TextView) v.findViewById(R.id.title)).setText(ri.title);
|
||||
if (!ri.isSystem) {
|
||||
LoadIconTask task = new LoadIconTask(iconView);
|
||||
task.execute(info);
|
||||
|
||||
TextView subtitle = (TextView) v.findViewById(R.id.subtitle);
|
||||
subtitle.setText(info.loadLabel(mPm));
|
||||
subtitle.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
if (ZenModeConfig.isValidScheduleConditionId(ri.defaultConditionId)) {
|
||||
iconView.setImageDrawable(mContext.getDrawable(R.drawable.ic_timelapse));
|
||||
} else if (ZenModeConfig.isValidEventConditionId(ri.defaultConditionId)) {
|
||||
iconView.setImageDrawable(mContext.getDrawable(R.drawable.ic_event));
|
||||
}
|
||||
}
|
||||
v.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
|
@@ -1,152 +0,0 @@
|
||||
/*
|
||||
* 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 junit.framework.Assert.assertFalse;
|
||||
import static junit.framework.Assert.assertTrue;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
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.Activity;
|
||||
import android.app.Fragment;
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
import android.service.notification.Condition;
|
||||
import android.view.LayoutInflater;
|
||||
|
||||
import com.android.settings.TestConfig;
|
||||
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||
|
||||
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;
|
||||
|
||||
@RunWith(SettingsRobolectricTestRunner.class)
|
||||
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
|
||||
public class EnableZenModeDialogTest {
|
||||
private EnableZenModeDialog mController;
|
||||
|
||||
@Mock
|
||||
private Context mContext;
|
||||
@Mock
|
||||
private Activity mActivity;
|
||||
@Mock
|
||||
private Fragment mFragment;
|
||||
|
||||
private Context mShadowContext;
|
||||
private LayoutInflater mLayoutInflater;
|
||||
private Condition mCountdownCondition;
|
||||
private Condition mAlarmCondition;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mShadowContext = RuntimeEnvironment.application;
|
||||
when(mActivity.getApplicationContext()).thenReturn(mShadowContext);
|
||||
when(mContext.getApplicationContext()).thenReturn(mContext);
|
||||
when(mFragment.getContext()).thenReturn(mShadowContext);
|
||||
mLayoutInflater = LayoutInflater.from(mShadowContext);
|
||||
when(mActivity.getLayoutInflater()).thenReturn(mLayoutInflater);
|
||||
|
||||
mController = spy(new EnableZenModeDialog());
|
||||
mController.mContext = mContext;
|
||||
mController.mActivity = mActivity;
|
||||
mController.mForeverId = Condition.newId(mContext).appendPath("forever").build();
|
||||
when(mContext.getString(com.android.internal.R.string.zen_mode_forever))
|
||||
.thenReturn("testSummary");
|
||||
mController.getContentView();
|
||||
|
||||
// these methods use static calls to ZenModeConfig which would normally fail in robotests,
|
||||
// so instead do nothing:
|
||||
doNothing().when(mController).bindGenericCountdown();
|
||||
doReturn(null).when(mController).getTimeUntilNextAlarmCondition();
|
||||
doNothing().when(mController).bindNextAlarm(any());
|
||||
|
||||
// as a result of doing nothing above, must bind manually:
|
||||
Uri alarm = Condition.newId(mContext).appendPath("alarm").build();
|
||||
mAlarmCondition = new Condition(alarm, "alarm", "", "", 0, 0, 0);
|
||||
Uri countdown = Condition.newId(mContext).appendPath("countdown").build();
|
||||
mCountdownCondition = new Condition(countdown, "countdown", "", "", 0, 0, 0);
|
||||
mController.bind(mCountdownCondition,
|
||||
mController.mZenRadioGroupContent.getChildAt(
|
||||
EnableZenModeDialog.COUNTDOWN_CONDITION_INDEX),
|
||||
EnableZenModeDialog.COUNTDOWN_CONDITION_INDEX);
|
||||
mController.bind(mAlarmCondition,
|
||||
mController.mZenRadioGroupContent.getChildAt(
|
||||
EnableZenModeDialog.COUNTDOWN_ALARM_CONDITION_INDEX),
|
||||
EnableZenModeDialog.COUNTDOWN_ALARM_CONDITION_INDEX);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testForeverChecked() {
|
||||
mController.bindConditions(mController.forever());
|
||||
|
||||
assertTrue(mController.getConditionTagAt(EnableZenModeDialog.FOREVER_CONDITION_INDEX).rb
|
||||
.isChecked());
|
||||
assertFalse(mController.getConditionTagAt(EnableZenModeDialog.COUNTDOWN_CONDITION_INDEX).rb
|
||||
.isChecked());
|
||||
assertFalse(mController.getConditionTagAt(
|
||||
EnableZenModeDialog.COUNTDOWN_ALARM_CONDITION_INDEX).rb.isChecked());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNoneChecked() {
|
||||
mController.bindConditions(null);
|
||||
assertFalse(mController.getConditionTagAt(EnableZenModeDialog.FOREVER_CONDITION_INDEX).rb
|
||||
.isChecked());
|
||||
assertFalse(mController.getConditionTagAt(EnableZenModeDialog.COUNTDOWN_CONDITION_INDEX).rb
|
||||
.isChecked());
|
||||
assertFalse(mController.getConditionTagAt(
|
||||
EnableZenModeDialog.COUNTDOWN_ALARM_CONDITION_INDEX).rb.isChecked());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAlarmChecked() {
|
||||
doReturn(false).when(mController).isCountdown(mAlarmCondition);
|
||||
doReturn(true).when(mController).isAlarm(mAlarmCondition);
|
||||
|
||||
mController.bindConditions(mAlarmCondition);
|
||||
assertFalse(mController.getConditionTagAt(EnableZenModeDialog.FOREVER_CONDITION_INDEX).rb
|
||||
.isChecked());
|
||||
assertFalse(mController.getConditionTagAt(EnableZenModeDialog.COUNTDOWN_CONDITION_INDEX).rb
|
||||
.isChecked());
|
||||
assertTrue(mController.getConditionTagAt(
|
||||
EnableZenModeDialog.COUNTDOWN_ALARM_CONDITION_INDEX).rb.isChecked());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCountdownChecked() {
|
||||
doReturn(false).when(mController).isAlarm(mCountdownCondition);
|
||||
doReturn(true).when(mController).isCountdown(mCountdownCondition);
|
||||
|
||||
mController.bindConditions(mCountdownCondition);
|
||||
assertFalse(mController.getConditionTagAt(EnableZenModeDialog.FOREVER_CONDITION_INDEX).rb
|
||||
.isChecked());
|
||||
assertTrue(mController.getConditionTagAt(EnableZenModeDialog.COUNTDOWN_CONDITION_INDEX).rb
|
||||
.isChecked());
|
||||
assertFalse(mController.getConditionTagAt(
|
||||
EnableZenModeDialog.COUNTDOWN_ALARM_CONDITION_INDEX).rb.isChecked());
|
||||
}
|
||||
}
|
@@ -19,6 +19,7 @@ package com.android.settings.notification;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.NotificationManager.Policy;
|
||||
import android.content.Context;
|
||||
import android.provider.Settings;
|
||||
import android.support.v7.preference.Preference;
|
||||
|
||||
import com.android.settings.R;
|
||||
@@ -63,7 +64,7 @@ public class ZenModePreferenceControllerTest {
|
||||
ShadowApplication shadowApplication = ShadowApplication.getInstance();
|
||||
shadowApplication.setSystemService(Context.NOTIFICATION_SERVICE, mNotificationManager);
|
||||
mContext = shadowApplication.getApplicationContext();
|
||||
mController = new ZenModePreferenceController(mContext);
|
||||
mController = new ZenModePreferenceController(mContext, null);
|
||||
when(mNotificationManager.getNotificationPolicy()).thenReturn(mPolicy);
|
||||
mSummaryBuilder = spy(new ZenModeSettings.SummaryBuilder(mContext));
|
||||
ReflectionHelpers.setField(mController, "mSummaryBuilder", mSummaryBuilder);
|
||||
@@ -76,16 +77,16 @@ public class ZenModePreferenceControllerTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateState_preferenceEnabled_shouldSetSummary() {
|
||||
public void updateState_automaticRuleEnabled_shouldSetSummary() {
|
||||
when(mPreference.isEnabled()).thenReturn(true);
|
||||
|
||||
mController.updateState(mPreference);
|
||||
verify(mPreference).setSummary(mContext.getString(R.string.zen_mode_settings_summary_off));
|
||||
verify(mPreference).setSummary(mContext.getResources().getString(
|
||||
R.string.zen_mode_sound_summary_off));
|
||||
|
||||
doReturn(1).when(mSummaryBuilder).getEnabledAutomaticRulesCount();
|
||||
mController.updateState(mPreference);
|
||||
verify(mPreference).setSummary(mContext.getResources().getQuantityString(
|
||||
R.plurals.zen_mode_settings_summary_on, 1, 1));
|
||||
verify(mPreference).setSummary(mSummaryBuilder.getSoundSummary());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
Reference in New Issue
Block a user