blob: fda57eb188ff36cd8576cc9300c4e6d89a67fac1 [file] [log] [blame]
Julia Reynolds0842fe82015-10-01 14:34:22 -04001/**
John Spurlock86005342014-05-23 11:58:00 -04002 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.systemui.volume;
18
John Spurlock3e077012014-11-29 13:22:21 -050019import android.animation.LayoutTransition;
John Spurlock530052a2014-11-30 16:26:19 -050020import android.animation.LayoutTransition.TransitionListener;
Selim Cinek9c4a7072014-11-21 17:44:34 +010021import android.app.ActivityManager;
John Spurlock86005342014-05-23 11:58:00 -040022import android.content.Context;
23import android.content.Intent;
John Spurlock856edeb2014-06-01 20:36:47 -040024import android.content.SharedPreferences;
25import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
John Spurlock814ee6ab2015-05-18 11:16:38 -040026import android.content.res.Configuration;
John Spurlock86005342014-05-23 11:58:00 -040027import android.net.Uri;
John Spurlock530052a2014-11-30 16:26:19 -050028import android.os.AsyncTask;
John Spurlock86005342014-05-23 11:58:00 -040029import android.os.Handler;
30import android.os.Looper;
31import android.os.Message;
32import android.provider.Settings;
John Spurlockae641c92014-06-30 18:11:40 -040033import android.provider.Settings.Global;
John Spurlock86005342014-05-23 11:58:00 -040034import android.service.notification.Condition;
John Spurlock856edeb2014-06-01 20:36:47 -040035import android.service.notification.ZenModeConfig;
John Spurlockb2278d62015-04-07 12:47:12 -040036import android.service.notification.ZenModeConfig.ZenRule;
John Spurlockc90e6fe2014-10-28 11:21:42 -040037import android.text.TextUtils;
John Spurlock8be53ea2015-05-29 12:04:21 -040038import android.text.format.DateFormat;
John Spurlock530052a2014-11-30 16:26:19 -050039import android.util.ArraySet;
John Spurlock86005342014-05-23 11:58:00 -040040import android.util.AttributeSet;
John Spurlock856edeb2014-06-01 20:36:47 -040041import android.util.Log;
John Spurlock8f8ecd62014-08-27 17:46:03 -040042import android.util.MathUtils;
John Spurlock86005342014-05-23 11:58:00 -040043import android.view.LayoutInflater;
44import android.view.View;
John Spurlock3e077012014-11-29 13:22:21 -050045import android.view.ViewGroup;
John Spurlock86005342014-05-23 11:58:00 -040046import android.widget.CompoundButton;
47import android.widget.CompoundButton.OnCheckedChangeListener;
48import android.widget.ImageView;
49import android.widget.LinearLayout;
50import android.widget.RadioButton;
51import android.widget.TextView;
52
Chris Wren9e7283f2015-05-08 17:23:47 -040053import com.android.internal.logging.MetricsLogger;
Chris Wrenf6e9228b2016-01-26 18:04:35 -050054import com.android.internal.logging.MetricsProto.MetricsEvent;
John Spurlockf55b7f22015-04-13 19:21:26 -040055import com.android.systemui.Prefs;
John Spurlock86005342014-05-23 11:58:00 -040056import com.android.systemui.R;
57import com.android.systemui.statusbar.policy.ZenModeController;
58
John Spurlock530052a2014-11-30 16:26:19 -050059import java.io.FileDescriptor;
60import java.io.PrintWriter;
John Spurlock86005342014-05-23 11:58:00 -040061import java.util.Arrays;
Julia Reynolds0842fe82015-10-01 14:34:22 -040062import java.util.Calendar;
63import java.util.GregorianCalendar;
John Spurlock8be53ea2015-05-29 12:04:21 -040064import java.util.Locale;
John Spurlock856edeb2014-06-01 20:36:47 -040065import java.util.Objects;
John Spurlock86005342014-05-23 11:58:00 -040066
67public class ZenModePanel extends LinearLayout {
John Spurlockae641c92014-06-30 18:11:40 -040068 private static final String TAG = "ZenModePanel";
69 private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
John Spurlock856edeb2014-06-01 20:36:47 -040070
John Spurlock50806fc2014-07-15 10:22:02 -040071 private static final int SECONDS_MS = 1000;
72 private static final int MINUTES_MS = 60 * SECONDS_MS;
73
Julia Reynolds0ca82fe2015-11-05 11:08:02 -050074 private static final int[] MINUTE_BUCKETS = ZenModeConfig.MINUTE_BUCKETS;
John Spurlock856edeb2014-06-01 20:36:47 -040075 private static final int MIN_BUCKET_MINUTES = MINUTE_BUCKETS[0];
76 private static final int MAX_BUCKET_MINUTES = MINUTE_BUCKETS[MINUTE_BUCKETS.length - 1];
77 private static final int DEFAULT_BUCKET_INDEX = Arrays.binarySearch(MINUTE_BUCKETS, 60);
John Spurlockae641c92014-06-30 18:11:40 -040078 private static final int FOREVER_CONDITION_INDEX = 0;
John Spurlock530052a2014-11-30 16:26:19 -050079 private static final int COUNTDOWN_CONDITION_INDEX = 1;
Julia Reynolds0842fe82015-10-01 14:34:22 -040080 private static final int COUNTDOWN_ALARM_CONDITION_INDEX = 2;
Julia Reynolds8e2d2bb2015-10-01 14:34:22 -040081 private static final int COUNTDOWN_CONDITION_COUNT = 2;
John Spurlock856edeb2014-06-01 20:36:47 -040082
John Spurlockf55b7f22015-04-13 19:21:26 -040083 public static final Intent ZEN_SETTINGS
84 = new Intent(Settings.ACTION_ZEN_MODE_SETTINGS);
85 public static final Intent ZEN_PRIORITY_SETTINGS
86 = new Intent(Settings.ACTION_ZEN_MODE_PRIORITY_SETTINGS);
John Spurlock86005342014-05-23 11:58:00 -040087
John Spurlock7f1df5e2014-05-31 19:11:40 -040088 private final Context mContext;
Muyuan Li94fa1df2016-03-23 12:09:38 -070089 protected final LayoutInflater mInflater;
John Spurlock86005342014-05-23 11:58:00 -040090 private final H mHandler = new H();
John Spurlockf55b7f22015-04-13 19:21:26 -040091 private final ZenPrefs mPrefs;
John Spurlock530052a2014-11-30 16:26:19 -050092 private final TransitionHelper mTransitionHelper = new TransitionHelper();
John Spurlock0b688502014-12-22 15:13:30 -050093 private final Uri mForeverId;
John Spurlockd8963232015-06-08 16:26:12 -040094 private final SpTexts mSpTexts;
John Spurlock856edeb2014-06-01 20:36:47 -040095
John Spurlockeb2727b2014-07-19 23:11:36 -040096 private String mTag = TAG + "/" + Integer.toHexString(System.identityHashCode(this));
John Spurlockae641c92014-06-30 18:11:40 -040097
Muyuan Li8303bd22016-03-23 20:08:26 -070098 protected SegmentedButtons mZenButtons;
John Spurlockf55b7f22015-04-13 19:21:26 -040099 private View mZenIntroduction;
John Spurlockd9c75db2015-04-28 11:19:13 -0400100 private TextView mZenIntroductionMessage;
John Spurlockf55b7f22015-04-13 19:21:26 -0400101 private View mZenIntroductionConfirm;
John Spurlockd8963232015-06-08 16:26:12 -0400102 private TextView mZenIntroductionCustomize;
Muyuan Li94fa1df2016-03-23 12:09:38 -0700103 protected LinearLayout mZenConditions;
John Spurlock8be53ea2015-05-29 12:04:21 -0400104 private TextView mZenAlarmWarning;
John Spurlockae641c92014-06-30 18:11:40 -0400105
John Spurlock86005342014-05-23 11:58:00 -0400106 private Callback mCallback;
107 private ZenModeController mController;
John Spurlockad680d42015-01-30 15:48:15 -0500108 private boolean mCountdownConditionSupported;
John Spurlock86005342014-05-23 11:58:00 -0400109 private boolean mRequestingConditions;
John Spurlock4db0d982014-08-13 09:19:03 -0400110 private Condition mExitCondition;
John Spurlock856edeb2014-06-01 20:36:47 -0400111 private int mBucketIndex = -1;
John Spurlockae641c92014-06-30 18:11:40 -0400112 private boolean mExpanded;
John Spurlock530052a2014-11-30 16:26:19 -0500113 private boolean mHidden;
John Spurlockfbb3d6f2014-07-17 11:17:11 -0400114 private int mSessionZen;
John Spurlock8f8ecd62014-08-27 17:46:03 -0400115 private int mAttachedZen;
John Spurlock3e077012014-11-29 13:22:21 -0500116 private boolean mAttached;
John Spurlock4db0d982014-08-13 09:19:03 -0400117 private Condition mSessionExitCondition;
John Spurlock4db0d982014-08-13 09:19:03 -0400118 private Condition[] mConditions;
119 private Condition mTimeCondition;
Julia Reynolds0842fe82015-10-01 14:34:22 -0400120 private Condition mTimeUntilAlarmCondition;
John Spurlockcbd7a312015-06-21 10:46:28 -0400121 private boolean mVoiceCapable;
John Spurlock86005342014-05-23 11:58:00 -0400122
123 public ZenModePanel(Context context, AttributeSet attrs) {
124 super(context, attrs);
John Spurlock7f1df5e2014-05-31 19:11:40 -0400125 mContext = context;
John Spurlockf55b7f22015-04-13 19:21:26 -0400126 mPrefs = new ZenPrefs();
John Spurlockf7d22132014-07-10 19:03:00 -0400127 mInflater = LayoutInflater.from(mContext.getApplicationContext());
John Spurlock0b688502014-12-22 15:13:30 -0500128 mForeverId = Condition.newId(mContext).appendPath("forever").build();
John Spurlockd8963232015-06-08 16:26:12 -0400129 mSpTexts = new SpTexts(mContext);
John Spurlockcbd7a312015-06-21 10:46:28 -0400130 mVoiceCapable = Util.isVoiceCapable(mContext);
John Spurlock856edeb2014-06-01 20:36:47 -0400131 if (DEBUG) Log.d(mTag, "new ZenModePanel");
132 }
133
John Spurlock530052a2014-11-30 16:26:19 -0500134 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
135 pw.println("ZenModePanel state:");
136 pw.print(" mCountdownConditionSupported="); pw.println(mCountdownConditionSupported);
John Spurlock530052a2014-11-30 16:26:19 -0500137 pw.print(" mRequestingConditions="); pw.println(mRequestingConditions);
138 pw.print(" mAttached="); pw.println(mAttached);
139 pw.print(" mHidden="); pw.println(mHidden);
140 pw.print(" mExpanded="); pw.println(mExpanded);
141 pw.print(" mSessionZen="); pw.println(mSessionZen);
142 pw.print(" mAttachedZen="); pw.println(mAttachedZen);
John Spurlockd9c75db2015-04-28 11:19:13 -0400143 pw.print(" mConfirmedPriorityIntroduction=");
144 pw.println(mPrefs.mConfirmedPriorityIntroduction);
145 pw.print(" mConfirmedSilenceIntroduction=");
146 pw.println(mPrefs.mConfirmedSilenceIntroduction);
John Spurlockcbd7a312015-06-21 10:46:28 -0400147 pw.print(" mVoiceCapable="); pw.println(mVoiceCapable);
John Spurlock530052a2014-11-30 16:26:19 -0500148 mTransitionHelper.dump(fd, pw, args);
149 }
150
Muyuan Li8303bd22016-03-23 20:08:26 -0700151 protected void createZenButtons() {
John Spurlockae641c92014-06-30 18:11:40 -0400152 mZenButtons = (SegmentedButtons) findViewById(R.id.zen_buttons);
John Spurlock4f1163c2015-04-02 17:41:21 -0400153 mZenButtons.addButton(R.string.interruption_level_none_twoline,
John Spurlockbd1abe62015-06-10 17:18:38 -0400154 R.string.interruption_level_none_with_warning,
John Spurlock4f1163c2015-04-02 17:41:21 -0400155 Global.ZEN_MODE_NO_INTERRUPTIONS);
156 mZenButtons.addButton(R.string.interruption_level_alarms_twoline,
John Spurlocka1c7ffe2015-06-08 15:34:05 -0400157 R.string.interruption_level_alarms,
John Spurlock4f1163c2015-04-02 17:41:21 -0400158 Global.ZEN_MODE_ALARMS);
159 mZenButtons.addButton(R.string.interruption_level_priority_twoline,
John Spurlocka1c7ffe2015-06-08 15:34:05 -0400160 R.string.interruption_level_priority,
John Spurlock4291fb72014-09-16 17:02:23 -0400161 Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS);
John Spurlockae641c92014-06-30 18:11:40 -0400162 mZenButtons.setCallback(mZenButtonsCallback);
Muyuan Li8303bd22016-03-23 20:08:26 -0700163 }
John Spurlockae641c92014-06-30 18:11:40 -0400164
Muyuan Li8303bd22016-03-23 20:08:26 -0700165 @Override
166 protected void onFinishInflate() {
167 super.onFinishInflate();
168 createZenButtons();
John Spurlockf55b7f22015-04-13 19:21:26 -0400169 mZenIntroduction = findViewById(R.id.zen_introduction);
John Spurlockd9c75db2015-04-28 11:19:13 -0400170 mZenIntroductionMessage = (TextView) findViewById(R.id.zen_introduction_message);
John Spurlockd8963232015-06-08 16:26:12 -0400171 mSpTexts.add(mZenIntroductionMessage);
John Spurlockf55b7f22015-04-13 19:21:26 -0400172 mZenIntroductionConfirm = findViewById(R.id.zen_introduction_confirm);
173 mZenIntroductionConfirm.setOnClickListener(new OnClickListener() {
174 @Override
175 public void onClick(View v) {
176 confirmZenIntroduction();
177 }
178 });
John Spurlockd8963232015-06-08 16:26:12 -0400179 mZenIntroductionCustomize = (TextView) findViewById(R.id.zen_introduction_customize);
John Spurlockf55b7f22015-04-13 19:21:26 -0400180 mZenIntroductionCustomize.setOnClickListener(new OnClickListener() {
181 @Override
182 public void onClick(View v) {
183 confirmZenIntroduction();
184 if (mCallback != null) {
185 mCallback.onPrioritySettings();
186 }
187 }
188 });
John Spurlockd8963232015-06-08 16:26:12 -0400189 mSpTexts.add(mZenIntroductionCustomize);
John Spurlockf55b7f22015-04-13 19:21:26 -0400190
John Spurlockae641c92014-06-30 18:11:40 -0400191 mZenConditions = (LinearLayout) findViewById(R.id.zen_conditions);
John Spurlock8be53ea2015-05-29 12:04:21 -0400192 mZenAlarmWarning = (TextView) findViewById(R.id.zen_alarm_warning);
John Spurlock814ee6ab2015-05-18 11:16:38 -0400193 }
John Spurlock530052a2014-11-30 16:26:19 -0500194
John Spurlock814ee6ab2015-05-18 11:16:38 -0400195 @Override
196 protected void onConfigurationChanged(Configuration newConfig) {
197 super.onConfigurationChanged(newConfig);
198 if (mZenButtons != null) {
199 mZenButtons.updateLocale();
200 }
John Spurlock3e077012014-11-29 13:22:21 -0500201 }
202
John Spurlockf55b7f22015-04-13 19:21:26 -0400203 private void confirmZenIntroduction() {
John Spurlockd9c75db2015-04-28 11:19:13 -0400204 final String prefKey = prefKeyForConfirmation(getSelectedZen(Global.ZEN_MODE_OFF));
205 if (prefKey == null) return;
206 if (DEBUG) Log.d(TAG, "confirmZenIntroduction " + prefKey);
207 Prefs.putBoolean(mContext, prefKey, true);
John Spurlockf55b7f22015-04-13 19:21:26 -0400208 mHandler.sendEmptyMessage(H.UPDATE_WIDGETS);
209 }
210
John Spurlockd9c75db2015-04-28 11:19:13 -0400211 private static String prefKeyForConfirmation(int zen) {
212 switch (zen) {
213 case Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS:
214 return Prefs.Key.DND_CONFIRMED_PRIORITY_INTRODUCTION;
215 case Global.ZEN_MODE_NO_INTERRUPTIONS:
216 return Prefs.Key.DND_CONFIRMED_SILENCE_INTRODUCTION;
217 default:
218 return null;
John Spurlock530052a2014-11-30 16:26:19 -0500219 }
John Spurlock86005342014-05-23 11:58:00 -0400220 }
221
222 @Override
John Spurlock856edeb2014-06-01 20:36:47 -0400223 protected void onAttachedToWindow() {
224 super.onAttachedToWindow();
225 if (DEBUG) Log.d(mTag, "onAttachedToWindow");
John Spurlock3e077012014-11-29 13:22:21 -0500226 mAttached = true;
John Spurlock8f8ecd62014-08-27 17:46:03 -0400227 mAttachedZen = getSelectedZen(-1);
228 mSessionZen = mAttachedZen;
John Spurlock530052a2014-11-30 16:26:19 -0500229 mTransitionHelper.clear();
230 setSessionExitCondition(copy(mExitCondition));
John Spurlock50806fc2014-07-15 10:22:02 -0400231 updateWidgets();
John Spurlock3e077012014-11-29 13:22:21 -0500232 setRequestingConditions(!mHidden);
John Spurlock856edeb2014-06-01 20:36:47 -0400233 }
234
235 @Override
236 protected void onDetachedFromWindow() {
237 super.onDetachedFromWindow();
238 if (DEBUG) Log.d(mTag, "onDetachedFromWindow");
John Spurlock8f8ecd62014-08-27 17:46:03 -0400239 checkForAttachedZenChange();
John Spurlock3e077012014-11-29 13:22:21 -0500240 mAttached = false;
John Spurlock8f8ecd62014-08-27 17:46:03 -0400241 mAttachedZen = -1;
John Spurlockfbb3d6f2014-07-17 11:17:11 -0400242 mSessionZen = -1;
John Spurlock530052a2014-11-30 16:26:19 -0500243 setSessionExitCondition(null);
John Spurlock3e077012014-11-29 13:22:21 -0500244 setRequestingConditions(false);
John Spurlock530052a2014-11-30 16:26:19 -0500245 mTransitionHelper.clear();
246 }
247
248 private void setSessionExitCondition(Condition condition) {
249 if (Objects.equals(condition, mSessionExitCondition)) return;
250 if (DEBUG) Log.d(mTag, "mSessionExitCondition=" + getConditionId(condition));
251 mSessionExitCondition = condition;
John Spurlock856edeb2014-06-01 20:36:47 -0400252 }
253
John Spurlockeb2727b2014-07-19 23:11:36 -0400254 public void setHidden(boolean hidden) {
255 if (mHidden == hidden) return;
John Spurlock3e077012014-11-29 13:22:21 -0500256 if (DEBUG) Log.d(mTag, "hidden=" + hidden);
John Spurlockeb2727b2014-07-19 23:11:36 -0400257 mHidden = hidden;
John Spurlock3e077012014-11-29 13:22:21 -0500258 setRequestingConditions(mAttached && !mHidden);
John Spurlockeb2727b2014-07-19 23:11:36 -0400259 updateWidgets();
260 }
261
John Spurlock8f8ecd62014-08-27 17:46:03 -0400262 private void checkForAttachedZenChange() {
263 final int selectedZen = getSelectedZen(-1);
264 if (DEBUG) Log.d(mTag, "selectedZen=" + selectedZen);
265 if (selectedZen != mAttachedZen) {
266 if (DEBUG) Log.d(mTag, "attachedZen: " + mAttachedZen + " -> " + selectedZen);
267 if (selectedZen == Global.ZEN_MODE_NO_INTERRUPTIONS) {
268 mPrefs.trackNoneSelected();
269 }
270 }
271 }
272
John Spurlockae641c92014-06-30 18:11:40 -0400273 private void setExpanded(boolean expanded) {
274 if (expanded == mExpanded) return;
John Spurlockf88d8082015-03-25 18:09:51 -0400275 if (DEBUG) Log.d(mTag, "setExpanded " + expanded);
John Spurlockae641c92014-06-30 18:11:40 -0400276 mExpanded = expanded;
John Spurlockb2278d62015-04-07 12:47:12 -0400277 if (mExpanded && isShown()) {
John Spurlock3e077012014-11-29 13:22:21 -0500278 ensureSelection();
279 }
John Spurlockae641c92014-06-30 18:11:40 -0400280 updateWidgets();
John Spurlockae641c92014-06-30 18:11:40 -0400281 fireExpanded();
John Spurlock86005342014-05-23 11:58:00 -0400282 }
283
284 /** Start or stop requesting relevant zen mode exit conditions */
John Spurlock530052a2014-11-30 16:26:19 -0500285 private void setRequestingConditions(final boolean requesting) {
John Spurlock86005342014-05-23 11:58:00 -0400286 if (mRequestingConditions == requesting) return;
John Spurlock856edeb2014-06-01 20:36:47 -0400287 if (DEBUG) Log.d(mTag, "setRequestingConditions " + requesting);
John Spurlock86005342014-05-23 11:58:00 -0400288 mRequestingConditions = requesting;
John Spurlock856edeb2014-06-01 20:36:47 -0400289 if (mRequestingConditions) {
John Spurlockb2278d62015-04-07 12:47:12 -0400290 mTimeCondition = parseExistingTimeCondition(mContext, mExitCondition);
John Spurlock4db0d982014-08-13 09:19:03 -0400291 if (mTimeCondition != null) {
John Spurlock856edeb2014-06-01 20:36:47 -0400292 mBucketIndex = -1;
293 } else {
294 mBucketIndex = DEFAULT_BUCKET_INDEX;
John Spurlockc90e6fe2014-10-28 11:21:42 -0400295 mTimeCondition = ZenModeConfig.toTimeCondition(mContext,
Selim Cinek9c4a7072014-11-21 17:44:34 +0100296 MINUTE_BUCKETS[mBucketIndex], ActivityManager.getCurrentUser());
John Spurlock856edeb2014-06-01 20:36:47 -0400297 }
298 if (DEBUG) Log.d(mTag, "Initial bucket index: " + mBucketIndex);
Julia Reynolds0842fe82015-10-01 14:34:22 -0400299
John Spurlock4db0d982014-08-13 09:19:03 -0400300 mConditions = null; // reset conditions
301 handleUpdateConditions();
John Spurlock856edeb2014-06-01 20:36:47 -0400302 } else {
John Spurlock530052a2014-11-30 16:26:19 -0500303 hideAllConditions();
John Spurlock856edeb2014-06-01 20:36:47 -0400304 }
John Spurlock86005342014-05-23 11:58:00 -0400305 }
306
Muyuan Li94fa1df2016-03-23 12:09:38 -0700307 protected void addZenConditions(int count) {
308 for (int i = 0; i < count; i++) {
309 mZenConditions.addView(mInflater.inflate(R.layout.zen_mode_condition, this, false));
310 }
311 }
312
John Spurlockeb2727b2014-07-19 23:11:36 -0400313 public void init(ZenModeController controller) {
John Spurlock86005342014-05-23 11:58:00 -0400314 mController = controller;
John Spurlockad680d42015-01-30 15:48:15 -0500315 mCountdownConditionSupported = mController.isCountdownConditionSupported();
Julia Reynolds8e2d2bb2015-10-01 14:34:22 -0400316 final int countdownDelta = mCountdownConditionSupported ? COUNTDOWN_CONDITION_COUNT : 0;
John Spurlockad680d42015-01-30 15:48:15 -0500317 final int minConditions = 1 /*forever*/ + countdownDelta;
Muyuan Li94fa1df2016-03-23 12:09:38 -0700318 addZenConditions(minConditions);
John Spurlockfbb3d6f2014-07-17 11:17:11 -0400319 mSessionZen = getSelectedZen(-1);
John Spurlockb2278d62015-04-07 12:47:12 -0400320 handleUpdateManualRule(mController.getManualRule());
John Spurlock4db0d982014-08-13 09:19:03 -0400321 if (DEBUG) Log.d(mTag, "init mExitCondition=" + mExitCondition);
John Spurlock530052a2014-11-30 16:26:19 -0500322 hideAllConditions();
John Spurlock856edeb2014-06-01 20:36:47 -0400323 mController.addCallback(mZenCallback);
John Spurlockae641c92014-06-30 18:11:40 -0400324 }
325
Jason Monke2f47712014-09-09 09:35:55 -0400326 public void updateLocale() {
John Spurlock4291fb72014-09-16 17:02:23 -0400327 mZenButtons.updateLocale();
Jason Monke2f47712014-09-09 09:35:55 -0400328 }
329
John Spurlock4db0d982014-08-13 09:19:03 -0400330 private void setExitCondition(Condition exitCondition) {
John Spurlock25c34212014-11-12 09:16:49 -0500331 if (Objects.equals(mExitCondition, exitCondition)) return;
John Spurlock4db0d982014-08-13 09:19:03 -0400332 mExitCondition = exitCondition;
John Spurlock530052a2014-11-30 16:26:19 -0500333 if (DEBUG) Log.d(mTag, "mExitCondition=" + getConditionId(mExitCondition));
John Spurlock89f060a2014-07-16 21:03:15 -0400334 updateWidgets();
John Spurlockae641c92014-06-30 18:11:40 -0400335 }
336
John Spurlock4db0d982014-08-13 09:19:03 -0400337 private static Uri getConditionId(Condition condition) {
338 return condition != null ? condition.id : null;
339 }
340
John Spurlockb2278d62015-04-07 12:47:12 -0400341 private Uri getRealConditionId(Condition condition) {
342 return isForever(condition) ? null : getConditionId(condition);
343 }
344
John Spurlock4db0d982014-08-13 09:19:03 -0400345 private static boolean sameConditionId(Condition lhs, Condition rhs) {
346 return lhs == null ? rhs == null : rhs != null && lhs.id.equals(rhs.id);
347 }
348
349 private static Condition copy(Condition condition) {
350 return condition == null ? null : condition.copy();
351 }
352
John Spurlock86005342014-05-23 11:58:00 -0400353 public void setCallback(Callback callback) {
354 mCallback = callback;
355 }
356
John Spurlockb2278d62015-04-07 12:47:12 -0400357 private void handleUpdateManualRule(ZenRule rule) {
358 final int zen = rule != null ? rule.zenMode : Global.ZEN_MODE_OFF;
359 handleUpdateZen(zen);
360 final Condition c = rule != null ? rule.condition : null;
361 handleExitConditionChanged(c);
362 }
363
John Spurlockae641c92014-06-30 18:11:40 -0400364 private void handleUpdateZen(int zen) {
John Spurlockfbb3d6f2014-07-17 11:17:11 -0400365 if (mSessionZen != -1 && mSessionZen != zen) {
John Spurlockd9c75db2015-04-28 11:19:13 -0400366 setExpanded(isShown());
John Spurlockfbb3d6f2014-07-17 11:17:11 -0400367 mSessionZen = zen;
John Spurlockae641c92014-06-30 18:11:40 -0400368 }
Chris Wren4572cbc2015-06-29 11:27:18 -0400369 mZenButtons.setSelectedValue(zen, false /* fromClick */);
John Spurlockae641c92014-06-30 18:11:40 -0400370 updateWidgets();
John Spurlock530052a2014-11-30 16:26:19 -0500371 handleUpdateConditions();
372 if (mExpanded) {
373 final Condition selected = getSelectedCondition();
374 if (!Objects.equals(mExitCondition, selected)) {
375 select(selected);
376 }
377 }
378 }
379
John Spurlockb2278d62015-04-07 12:47:12 -0400380 private void handleExitConditionChanged(Condition exitCondition) {
381 setExitCondition(exitCondition);
382 if (DEBUG) Log.d(mTag, "handleExitConditionChanged " + mExitCondition);
383 final int N = getVisibleConditions();
384 for (int i = 0; i < N; i++) {
385 final ConditionTag tag = getConditionTagAt(i);
386 if (tag != null) {
387 if (sameConditionId(tag.condition, mExitCondition)) {
Julia Reynolds0842fe82015-10-01 14:34:22 -0400388 bind(exitCondition, mZenConditions.getChildAt(i), i);
John Spurlockb2278d62015-04-07 12:47:12 -0400389 }
390 }
391 }
392 }
393
John Spurlock530052a2014-11-30 16:26:19 -0500394 private Condition getSelectedCondition() {
395 final int N = getVisibleConditions();
396 for (int i = 0; i < N; i++) {
397 final ConditionTag tag = getConditionTagAt(i);
398 if (tag != null && tag.rb.isChecked()) {
399 return tag.condition;
400 }
401 }
402 return null;
John Spurlockae641c92014-06-30 18:11:40 -0400403 }
404
405 private int getSelectedZen(int defValue) {
406 final Object zen = mZenButtons.getSelectedValue();
407 return zen != null ? (Integer) zen : defValue;
408 }
409
410 private void updateWidgets() {
John Spurlock530052a2014-11-30 16:26:19 -0500411 if (mTransitionHelper.isTransitioning()) {
412 mTransitionHelper.pendingUpdateWidgets();
413 return;
414 }
John Spurlockae641c92014-06-30 18:11:40 -0400415 final int zen = getSelectedZen(Global.ZEN_MODE_OFF);
John Spurlockae641c92014-06-30 18:11:40 -0400416 final boolean zenImportant = zen == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
417 final boolean zenNone = zen == Global.ZEN_MODE_NO_INTERRUPTIONS;
John Spurlockd9c75db2015-04-28 11:19:13 -0400418 final boolean introduction = (zenImportant && !mPrefs.mConfirmedPriorityIntroduction
419 || zenNone && !mPrefs.mConfirmedSilenceIntroduction);
John Spurlockae641c92014-06-30 18:11:40 -0400420
John Spurlockeb2727b2014-07-19 23:11:36 -0400421 mZenButtons.setVisibility(mHidden ? GONE : VISIBLE);
John Spurlockf55b7f22015-04-13 19:21:26 -0400422 mZenIntroduction.setVisibility(introduction ? VISIBLE : GONE);
John Spurlockd9c75db2015-04-28 11:19:13 -0400423 if (introduction) {
424 mZenIntroductionMessage.setText(zenImportant ? R.string.zen_priority_introduction
John Spurlockcbd7a312015-06-21 10:46:28 -0400425 : mVoiceCapable ? R.string.zen_silence_introduction_voice
John Spurlockd9c75db2015-04-28 11:19:13 -0400426 : R.string.zen_silence_introduction);
427 mZenIntroductionCustomize.setVisibility(zenImportant ? VISIBLE : GONE);
428 }
John Spurlock8be53ea2015-05-29 12:04:21 -0400429 final String warning = computeAlarmWarningText(zenNone);
430 mZenAlarmWarning.setVisibility(warning != null ? VISIBLE : GONE);
431 mZenAlarmWarning.setText(warning);
432 }
433
434 private String computeAlarmWarningText(boolean zenNone) {
435 if (!zenNone) {
436 return null;
437 }
438 final long now = System.currentTimeMillis();
439 final long nextAlarm = mController.getNextAlarm();
440 if (nextAlarm < now) {
441 return null;
442 }
443 int warningRes = 0;
444 if (mSessionExitCondition == null || isForever(mSessionExitCondition)) {
445 warningRes = R.string.zen_alarm_warning_indef;
446 } else {
447 final long time = ZenModeConfig.tryParseCountdownConditionId(mSessionExitCondition.id);
448 if (time > now && nextAlarm < time) {
449 warningRes = R.string.zen_alarm_warning;
450 }
451 }
452 if (warningRes == 0) {
453 return null;
454 }
455 final boolean soon = (nextAlarm - now) < 24 * 60 * 60 * 1000;
456 final boolean is24 = DateFormat.is24HourFormat(mContext, ActivityManager.getCurrentUser());
457 final String skeleton = soon ? (is24 ? "Hm" : "hma") : (is24 ? "EEEHm" : "EEEhma");
458 final String pattern = DateFormat.getBestDateTimePattern(Locale.getDefault(), skeleton);
459 final CharSequence formattedTime = DateFormat.format(pattern, nextAlarm);
460 final int templateRes = soon ? R.string.alarm_template : R.string.alarm_template_far;
461 final String template = getResources().getString(templateRes, formattedTime);
462 return getResources().getString(warningRes, template);
John Spurlock89f060a2014-07-16 21:03:15 -0400463 }
464
John Spurlockb2278d62015-04-07 12:47:12 -0400465 private static Condition parseExistingTimeCondition(Context context, Condition condition) {
John Spurlock4db0d982014-08-13 09:19:03 -0400466 if (condition == null) return null;
467 final long time = ZenModeConfig.tryParseCountdownConditionId(condition.id);
John Spurlock856edeb2014-06-01 20:36:47 -0400468 if (time == 0) return null;
John Spurlockc90e6fe2014-10-28 11:21:42 -0400469 final long now = System.currentTimeMillis();
470 final long span = time - now;
John Spurlock856edeb2014-06-01 20:36:47 -0400471 if (span <= 0 || span > MAX_BUCKET_MINUTES * MINUTES_MS) return null;
John Spurlockb2278d62015-04-07 12:47:12 -0400472 return ZenModeConfig.toTimeCondition(context,
Julia Reynolds0842fe82015-10-01 14:34:22 -0400473 time, Math.round(span / (float) MINUTES_MS), ActivityManager.getCurrentUser(),
John Spurlockbbde2672015-05-13 15:42:04 -0400474 false /*shortVersion*/);
John Spurlock86005342014-05-23 11:58:00 -0400475 }
476
John Spurlock4db0d982014-08-13 09:19:03 -0400477 private void handleUpdateConditions() {
John Spurlock530052a2014-11-30 16:26:19 -0500478 if (mTransitionHelper.isTransitioning()) {
John Spurlock530052a2014-11-30 16:26:19 -0500479 return;
480 }
John Spurlock4db0d982014-08-13 09:19:03 -0400481 final int conditionCount = mConditions == null ? 0 : mConditions.length;
482 if (DEBUG) Log.d(mTag, "handleUpdateConditions conditionCount=" + conditionCount);
John Spurlock4db0d982014-08-13 09:19:03 -0400483 // forever
Julia Reynolds0842fe82015-10-01 14:34:22 -0400484 bind(forever(), mZenConditions.getChildAt(FOREVER_CONDITION_INDEX),
485 FOREVER_CONDITION_INDEX);
John Spurlock4db0d982014-08-13 09:19:03 -0400486 // countdown
John Spurlock0b688502014-12-22 15:13:30 -0500487 if (mCountdownConditionSupported && mTimeCondition != null) {
Julia Reynolds0842fe82015-10-01 14:34:22 -0400488 bind(mTimeCondition, mZenConditions.getChildAt(COUNTDOWN_CONDITION_INDEX),
489 COUNTDOWN_CONDITION_INDEX);
John Spurlock86005342014-05-23 11:58:00 -0400490 }
Julia Reynolds0842fe82015-10-01 14:34:22 -0400491 // countdown until alarm
Julia Reynolds8e2d2bb2015-10-01 14:34:22 -0400492 if (mCountdownConditionSupported) {
493 Condition nextAlarmCondition = getTimeUntilNextAlarmCondition();
494 if (nextAlarmCondition != null) {
495 bind(nextAlarmCondition,
496 mZenConditions.getChildAt(COUNTDOWN_ALARM_CONDITION_INDEX),
497 COUNTDOWN_ALARM_CONDITION_INDEX);
498 }
John Spurlock4db0d982014-08-13 09:19:03 -0400499 }
John Spurlock3e077012014-11-29 13:22:21 -0500500 // ensure something is selected
John Spurlockb2278d62015-04-07 12:47:12 -0400501 if (mExpanded && isShown()) {
John Spurlock3e077012014-11-29 13:22:21 -0500502 ensureSelection();
503 }
Jason Monke138f552016-01-18 09:21:45 -0500504 mZenConditions.setVisibility(mSessionZen != Global.ZEN_MODE_OFF ? View.VISIBLE : View.GONE);
John Spurlock4db0d982014-08-13 09:19:03 -0400505 }
506
John Spurlock0b688502014-12-22 15:13:30 -0500507 private Condition forever() {
John Spurlockb2278d62015-04-07 12:47:12 -0400508 return new Condition(mForeverId, foreverSummary(mContext), "", "", 0 /*icon*/,
509 Condition.STATE_TRUE, 0 /*flags*/);
John Spurlock0b688502014-12-22 15:13:30 -0500510 }
511
John Spurlockb2278d62015-04-07 12:47:12 -0400512 private static String foreverSummary(Context context) {
513 return context.getString(com.android.internal.R.string.zen_mode_forever);
John Spurlock0b688502014-12-22 15:13:30 -0500514 }
515
Julia Reynolds0842fe82015-10-01 14:34:22 -0400516 // Returns a time condition if the next alarm is within the next week.
517 private Condition getTimeUntilNextAlarmCondition() {
518 GregorianCalendar weekRange = new GregorianCalendar();
519 final long now = weekRange.getTimeInMillis();
520 setToMidnight(weekRange);
Dan Sandler12d33932015-12-29 15:45:39 -0500521 weekRange.add(Calendar.DATE, 6);
Julia Reynolds0842fe82015-10-01 14:34:22 -0400522 final long nextAlarmMs = mController.getNextAlarm();
523 if (nextAlarmMs > 0) {
524 GregorianCalendar nextAlarm = new GregorianCalendar();
525 nextAlarm.setTimeInMillis(nextAlarmMs);
526 setToMidnight(nextAlarm);
527
528 if (weekRange.compareTo(nextAlarm) >= 0) {
Julia Reynolds1998ee52016-02-11 13:49:08 -0500529 return ZenModeConfig.toNextAlarmCondition(mContext, now,
530 nextAlarmMs, ActivityManager.getCurrentUser());
Julia Reynolds0842fe82015-10-01 14:34:22 -0400531 }
532 }
533 return null;
534 }
535
536 private void setToMidnight(Calendar calendar) {
537 calendar.set(Calendar.HOUR_OF_DAY, 0);
538 calendar.set(Calendar.MINUTE, 0);
539 calendar.set(Calendar.SECOND, 0);
540 calendar.set(Calendar.MILLISECOND, 0);
541 }
542
John Spurlock856edeb2014-06-01 20:36:47 -0400543 private ConditionTag getConditionTagAt(int index) {
John Spurlockae641c92014-06-30 18:11:40 -0400544 return (ConditionTag) mZenConditions.getChildAt(index).getTag();
John Spurlock856edeb2014-06-01 20:36:47 -0400545 }
546
John Spurlock530052a2014-11-30 16:26:19 -0500547 private int getVisibleConditions() {
548 int rt = 0;
549 final int N = mZenConditions.getChildCount();
550 for (int i = 0; i < N; i++) {
551 rt += mZenConditions.getChildAt(i).getVisibility() == VISIBLE ? 1 : 0;
552 }
553 return rt;
554 }
555
556 private void hideAllConditions() {
557 final int N = mZenConditions.getChildCount();
558 for (int i = 0; i < N; i++) {
559 mZenConditions.getChildAt(i).setVisibility(GONE);
560 }
561 }
562
John Spurlock3e077012014-11-29 13:22:21 -0500563 private void ensureSelection() {
John Spurlock856edeb2014-06-01 20:36:47 -0400564 // are we left without anything selected? if so, set a default
John Spurlock530052a2014-11-30 16:26:19 -0500565 final int visibleConditions = getVisibleConditions();
566 if (visibleConditions == 0) return;
567 for (int i = 0; i < visibleConditions; i++) {
568 final ConditionTag tag = getConditionTagAt(i);
569 if (tag != null && tag.rb.isChecked()) {
570 if (DEBUG) Log.d(mTag, "Not selecting a default, checked=" + tag.condition);
John Spurlock856edeb2014-06-01 20:36:47 -0400571 return;
572 }
573 }
John Spurlock530052a2014-11-30 16:26:19 -0500574 final ConditionTag foreverTag = getConditionTagAt(FOREVER_CONDITION_INDEX);
575 if (foreverTag == null) return;
John Spurlock856edeb2014-06-01 20:36:47 -0400576 if (DEBUG) Log.d(mTag, "Selecting a default");
John Spurlock8f8ecd62014-08-27 17:46:03 -0400577 final int favoriteIndex = mPrefs.getMinuteIndex();
John Spurlock530052a2014-11-30 16:26:19 -0500578 if (favoriteIndex == -1 || !mCountdownConditionSupported) {
Julia Reynolds617a7802016-04-29 14:32:46 -0400579 setChecked(foreverTag.rb, true);
John Spurlock856edeb2014-06-01 20:36:47 -0400580 } else {
Selim Cinek9c4a7072014-11-21 17:44:34 +0100581 mTimeCondition = ZenModeConfig.toTimeCondition(mContext,
582 MINUTE_BUCKETS[favoriteIndex], ActivityManager.getCurrentUser());
John Spurlock856edeb2014-06-01 20:36:47 -0400583 mBucketIndex = favoriteIndex;
Julia Reynolds0842fe82015-10-01 14:34:22 -0400584 bind(mTimeCondition, mZenConditions.getChildAt(COUNTDOWN_CONDITION_INDEX),
585 COUNTDOWN_CONDITION_INDEX);
Julia Reynolds617a7802016-04-29 14:32:46 -0400586 setChecked(getConditionTagAt(COUNTDOWN_CONDITION_INDEX).rb, true);
587 }
588 }
589
590 private void setChecked(RadioButton rb, boolean checked) {
591 final int N = getVisibleConditions();
592 for (int i = 0; i < N; i++) {
593 final ConditionTag tag = getConditionTagAt(i);
594 if (tag != null && tag.rb.isChecked() && !Objects.equals(tag.rb, rb)) {
595 tag.rb.setChecked(false);
596 }
597 }
598 if (rb.isChecked() != checked) {
599 rb.setChecked(checked);
John Spurlock856edeb2014-06-01 20:36:47 -0400600 }
601 }
602
John Spurlockb2278d62015-04-07 12:47:12 -0400603 private static boolean isCountdown(Condition c) {
John Spurlock530052a2014-11-30 16:26:19 -0500604 return c != null && ZenModeConfig.isValidCountdownConditionId(c.id);
605 }
606
John Spurlock0b688502014-12-22 15:13:30 -0500607 private boolean isForever(Condition c) {
608 return c != null && mForeverId.equals(c.id);
609 }
610
Julia Reynolds0842fe82015-10-01 14:34:22 -0400611 private void bind(final Condition condition, final View row, final int rowId) {
John Spurlock0b688502014-12-22 15:13:30 -0500612 if (condition == null) throw new IllegalArgumentException("condition must not be null");
613 final boolean enabled = condition.state == Condition.STATE_TRUE;
John Spurlock856edeb2014-06-01 20:36:47 -0400614 final ConditionTag tag =
615 row.getTag() != null ? (ConditionTag) row.getTag() : new ConditionTag();
616 row.setTag(tag);
John Spurlock530052a2014-11-30 16:26:19 -0500617 final boolean first = tag.rb == null;
John Spurlock856edeb2014-06-01 20:36:47 -0400618 if (tag.rb == null) {
619 tag.rb = (RadioButton) row.findViewById(android.R.id.checkbox);
620 }
John Spurlock4db0d982014-08-13 09:19:03 -0400621 tag.condition = condition;
John Spurlock530052a2014-11-30 16:26:19 -0500622 final Uri conditionId = getConditionId(tag.condition);
623 if (DEBUG) Log.d(mTag, "bind i=" + mZenConditions.indexOfChild(row) + " first=" + first
624 + " condition=" + conditionId);
John Spurlock856edeb2014-06-01 20:36:47 -0400625 tag.rb.setEnabled(enabled);
626 tag.rb.setOnCheckedChangeListener(new OnCheckedChangeListener() {
John Spurlock86005342014-05-23 11:58:00 -0400627 @Override
628 public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
John Spurlockae641c92014-06-30 18:11:40 -0400629 if (mExpanded && isChecked) {
Julia Reynolds617a7802016-04-29 14:32:46 -0400630 setChecked(tag.rb, isChecked);
John Spurlock530052a2014-11-30 16:26:19 -0500631 if (DEBUG) Log.d(mTag, "onCheckedChanged " + conditionId);
Chris Wrenf6e9228b2016-01-26 18:04:35 -0500632 MetricsLogger.action(mContext, MetricsEvent.QS_DND_CONDITION_SELECT);
John Spurlock4db0d982014-08-13 09:19:03 -0400633 select(tag.condition);
John Spurlocka0457c22014-09-26 13:22:08 -0400634 announceConditionSelection(tag);
John Spurlock86005342014-05-23 11:58:00 -0400635 }
636 }
637 });
John Spurlocka0457c22014-09-26 13:22:08 -0400638
John Spurlockc90e6fe2014-10-28 11:21:42 -0400639 if (tag.lines == null) {
640 tag.lines = row.findViewById(android.R.id.content);
John Spurlock86005342014-05-23 11:58:00 -0400641 }
John Spurlockc90e6fe2014-10-28 11:21:42 -0400642 if (tag.line1 == null) {
643 tag.line1 = (TextView) row.findViewById(android.R.id.text1);
John Spurlockd8963232015-06-08 16:26:12 -0400644 mSpTexts.add(tag.line1);
John Spurlockc90e6fe2014-10-28 11:21:42 -0400645 }
646 if (tag.line2 == null) {
647 tag.line2 = (TextView) row.findViewById(android.R.id.text2);
John Spurlockd8963232015-06-08 16:26:12 -0400648 mSpTexts.add(tag.line2);
John Spurlockc90e6fe2014-10-28 11:21:42 -0400649 }
John Spurlock0b688502014-12-22 15:13:30 -0500650 final String line1 = !TextUtils.isEmpty(condition.line1) ? condition.line1
651 : condition.summary;
652 final String line2 = condition.line2;
John Spurlockc90e6fe2014-10-28 11:21:42 -0400653 tag.line1.setText(line1);
654 if (TextUtils.isEmpty(line2)) {
655 tag.line2.setVisibility(GONE);
656 } else {
657 tag.line2.setVisibility(VISIBLE);
658 tag.line2.setText(line2);
659 }
660 tag.lines.setEnabled(enabled);
661 tag.lines.setAlpha(enabled ? 1 : .4f);
John Spurlocka0457c22014-09-26 13:22:08 -0400662
John Spurlock86005342014-05-23 11:58:00 -0400663 final ImageView button1 = (ImageView) row.findViewById(android.R.id.button1);
664 button1.setOnClickListener(new OnClickListener() {
665 @Override
666 public void onClick(View v) {
Julia Reynolds0842fe82015-10-01 14:34:22 -0400667 onClickTimeButton(row, tag, false /*down*/, rowId);
John Spurlock86005342014-05-23 11:58:00 -0400668 }
669 });
670
671 final ImageView button2 = (ImageView) row.findViewById(android.R.id.button2);
672 button2.setOnClickListener(new OnClickListener() {
673 @Override
674 public void onClick(View v) {
Julia Reynolds0842fe82015-10-01 14:34:22 -0400675 onClickTimeButton(row, tag, true /*up*/, rowId);
John Spurlock86005342014-05-23 11:58:00 -0400676 }
677 });
John Spurlockc90e6fe2014-10-28 11:21:42 -0400678 tag.lines.setOnClickListener(new OnClickListener() {
John Spurlock86005342014-05-23 11:58:00 -0400679 @Override
680 public void onClick(View v) {
Julia Reynolds617a7802016-04-29 14:32:46 -0400681 setChecked(tag.rb, true);
John Spurlock86005342014-05-23 11:58:00 -0400682 }
683 });
John Spurlock856edeb2014-06-01 20:36:47 -0400684
John Spurlock530052a2014-11-30 16:26:19 -0500685 final long time = ZenModeConfig.tryParseCountdownConditionId(conditionId);
Julia Reynolds0842fe82015-10-01 14:34:22 -0400686 if (rowId != COUNTDOWN_ALARM_CONDITION_INDEX && time > 0) {
John Spurlock530052a2014-11-30 16:26:19 -0500687 button1.setVisibility(VISIBLE);
688 button2.setVisibility(VISIBLE);
John Spurlock856edeb2014-06-01 20:36:47 -0400689 if (mBucketIndex > -1) {
690 button1.setEnabled(mBucketIndex > 0);
691 button2.setEnabled(mBucketIndex < MINUTE_BUCKETS.length - 1);
692 } else {
693 final long span = time - System.currentTimeMillis();
694 button1.setEnabled(span > MIN_BUCKET_MINUTES * MINUTES_MS);
John Spurlockc90e6fe2014-10-28 11:21:42 -0400695 final Condition maxCondition = ZenModeConfig.toTimeCondition(mContext,
Selim Cinek9c4a7072014-11-21 17:44:34 +0100696 MAX_BUCKET_MINUTES, ActivityManager.getCurrentUser());
John Spurlock856edeb2014-06-01 20:36:47 -0400697 button2.setEnabled(!Objects.equals(condition.summary, maxCondition.summary));
698 }
699
700 button1.setAlpha(button1.isEnabled() ? 1f : .5f);
701 button2.setAlpha(button2.isEnabled() ? 1f : .5f);
John Spurlock86005342014-05-23 11:58:00 -0400702 } else {
John Spurlock530052a2014-11-30 16:26:19 -0500703 button1.setVisibility(GONE);
704 button2.setVisibility(GONE);
John Spurlock86005342014-05-23 11:58:00 -0400705 }
John Spurlocka0457c22014-09-26 13:22:08 -0400706 // wire up interaction callbacks for newly-added condition rows
John Spurlock530052a2014-11-30 16:26:19 -0500707 if (first) {
John Spurlocka0457c22014-09-26 13:22:08 -0400708 Interaction.register(tag.rb, mInteractionCallback);
John Spurlockc90e6fe2014-10-28 11:21:42 -0400709 Interaction.register(tag.lines, mInteractionCallback);
John Spurlocka0457c22014-09-26 13:22:08 -0400710 Interaction.register(button1, mInteractionCallback);
711 Interaction.register(button2, mInteractionCallback);
712 }
John Spurlock530052a2014-11-30 16:26:19 -0500713 row.setVisibility(VISIBLE);
John Spurlocka0457c22014-09-26 13:22:08 -0400714 }
715
716 private void announceConditionSelection(ConditionTag tag) {
717 final int zen = getSelectedZen(Global.ZEN_MODE_OFF);
718 String modeText;
719 switch(zen) {
720 case Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS:
John Spurlockd9c75db2015-04-28 11:19:13 -0400721 modeText = mContext.getString(R.string.interruption_level_priority);
John Spurlocka0457c22014-09-26 13:22:08 -0400722 break;
723 case Global.ZEN_MODE_NO_INTERRUPTIONS:
John Spurlockd9c75db2015-04-28 11:19:13 -0400724 modeText = mContext.getString(R.string.interruption_level_none);
John Spurlocka0457c22014-09-26 13:22:08 -0400725 break;
John Spurlock4f1163c2015-04-02 17:41:21 -0400726 case Global.ZEN_MODE_ALARMS:
John Spurlockd9c75db2015-04-28 11:19:13 -0400727 modeText = mContext.getString(R.string.interruption_level_alarms);
John Spurlock4f1163c2015-04-02 17:41:21 -0400728 break;
729 default:
John Spurlocka0457c22014-09-26 13:22:08 -0400730 return;
731 }
732 announceForAccessibility(mContext.getString(R.string.zen_mode_and_condition, modeText,
John Spurlockc90e6fe2014-10-28 11:21:42 -0400733 tag.line1.getText()));
John Spurlock856edeb2014-06-01 20:36:47 -0400734 }
735
Julia Reynolds0842fe82015-10-01 14:34:22 -0400736 private void onClickTimeButton(View row, ConditionTag tag, boolean up, int rowId) {
Chris Wrenf6e9228b2016-01-26 18:04:35 -0500737 MetricsLogger.action(mContext, MetricsEvent.QS_DND_TIME, up);
John Spurlock856edeb2014-06-01 20:36:47 -0400738 Condition newCondition = null;
739 final int N = MINUTE_BUCKETS.length;
740 if (mBucketIndex == -1) {
741 // not on a known index, search for the next or prev bucket by time
John Spurlock4db0d982014-08-13 09:19:03 -0400742 final Uri conditionId = getConditionId(tag.condition);
743 final long time = ZenModeConfig.tryParseCountdownConditionId(conditionId);
John Spurlock856edeb2014-06-01 20:36:47 -0400744 final long now = System.currentTimeMillis();
745 for (int i = 0; i < N; i++) {
746 int j = up ? i : N - 1 - i;
747 final int bucketMinutes = MINUTE_BUCKETS[j];
748 final long bucketTime = now + bucketMinutes * MINUTES_MS;
749 if (up && bucketTime > time || !up && bucketTime < time) {
750 mBucketIndex = j;
John Spurlockc90e6fe2014-10-28 11:21:42 -0400751 newCondition = ZenModeConfig.toTimeCondition(mContext,
Julia Reynolds0842fe82015-10-01 14:34:22 -0400752 bucketTime, bucketMinutes, ActivityManager.getCurrentUser(),
John Spurlockbbde2672015-05-13 15:42:04 -0400753 false /*shortVersion*/);
John Spurlock856edeb2014-06-01 20:36:47 -0400754 break;
755 }
756 }
757 if (newCondition == null) {
758 mBucketIndex = DEFAULT_BUCKET_INDEX;
John Spurlockc90e6fe2014-10-28 11:21:42 -0400759 newCondition = ZenModeConfig.toTimeCondition(mContext,
Selim Cinek9c4a7072014-11-21 17:44:34 +0100760 MINUTE_BUCKETS[mBucketIndex], ActivityManager.getCurrentUser());
John Spurlock856edeb2014-06-01 20:36:47 -0400761 }
762 } else {
763 // on a known index, simply increment or decrement
764 mBucketIndex = Math.max(0, Math.min(N - 1, mBucketIndex + (up ? 1 : -1)));
John Spurlockc90e6fe2014-10-28 11:21:42 -0400765 newCondition = ZenModeConfig.toTimeCondition(mContext,
Selim Cinek9c4a7072014-11-21 17:44:34 +0100766 MINUTE_BUCKETS[mBucketIndex], ActivityManager.getCurrentUser());
John Spurlock856edeb2014-06-01 20:36:47 -0400767 }
John Spurlock4db0d982014-08-13 09:19:03 -0400768 mTimeCondition = newCondition;
Julia Reynolds0842fe82015-10-01 14:34:22 -0400769 bind(mTimeCondition, row, rowId);
Julia Reynolds617a7802016-04-29 14:32:46 -0400770 setChecked(tag.rb, true);
John Spurlock4db0d982014-08-13 09:19:03 -0400771 select(mTimeCondition);
John Spurlocka0457c22014-09-26 13:22:08 -0400772 announceConditionSelection(tag);
John Spurlock856edeb2014-06-01 20:36:47 -0400773 }
774
John Spurlock530052a2014-11-30 16:26:19 -0500775 private void select(final Condition condition) {
John Spurlock4db0d982014-08-13 09:19:03 -0400776 if (DEBUG) Log.d(mTag, "select " + condition);
John Spurlockb2278d62015-04-07 12:47:12 -0400777 if (mSessionZen == -1 || mSessionZen == Global.ZEN_MODE_OFF) {
778 if (DEBUG) Log.d(mTag, "Ignoring condition selection outside of manual zen");
779 return;
780 }
781 final Uri realConditionId = getRealConditionId(condition);
John Spurlock856edeb2014-06-01 20:36:47 -0400782 if (mController != null) {
John Spurlock530052a2014-11-30 16:26:19 -0500783 AsyncTask.execute(new Runnable() {
784 @Override
785 public void run() {
John Spurlockb2278d62015-04-07 12:47:12 -0400786 mController.setZen(mSessionZen, realConditionId, TAG + ".selectCondition");
John Spurlock530052a2014-11-30 16:26:19 -0500787 }
788 });
John Spurlock856edeb2014-06-01 20:36:47 -0400789 }
John Spurlock4db0d982014-08-13 09:19:03 -0400790 setExitCondition(condition);
John Spurlockb2278d62015-04-07 12:47:12 -0400791 if (realConditionId == null) {
John Spurlock8f8ecd62014-08-27 17:46:03 -0400792 mPrefs.setMinuteIndex(-1);
John Spurlock530052a2014-11-30 16:26:19 -0500793 } else if (isCountdown(condition) && mBucketIndex != -1) {
John Spurlock8f8ecd62014-08-27 17:46:03 -0400794 mPrefs.setMinuteIndex(mBucketIndex);
John Spurlock86005342014-05-23 11:58:00 -0400795 }
John Spurlock530052a2014-11-30 16:26:19 -0500796 setSessionExitCondition(copy(condition));
John Spurlock86005342014-05-23 11:58:00 -0400797 }
798
John Spurlock86005342014-05-23 11:58:00 -0400799 private void fireInteraction() {
800 if (mCallback != null) {
801 mCallback.onInteraction();
802 }
803 }
804
John Spurlockae641c92014-06-30 18:11:40 -0400805 private void fireExpanded() {
806 if (mCallback != null) {
807 mCallback.onExpanded(mExpanded);
808 }
809 }
810
John Spurlock86005342014-05-23 11:58:00 -0400811 private final ZenModeController.Callback mZenCallback = new ZenModeController.Callback() {
812 @Override
John Spurlockb2278d62015-04-07 12:47:12 -0400813 public void onManualRuleChanged(ZenRule rule) {
814 mHandler.obtainMessage(H.MANUAL_RULE_CHANGED, rule).sendToTarget();
John Spurlock856edeb2014-06-01 20:36:47 -0400815 }
John Spurlock86005342014-05-23 11:58:00 -0400816 };
817
818 private final class H extends Handler {
John Spurlockb2278d62015-04-07 12:47:12 -0400819 private static final int MANUAL_RULE_CHANGED = 2;
John Spurlockf55b7f22015-04-13 19:21:26 -0400820 private static final int UPDATE_WIDGETS = 3;
John Spurlock86005342014-05-23 11:58:00 -0400821
822 private H() {
823 super(Looper.getMainLooper());
824 }
825
826 @Override
827 public void handleMessage(Message msg) {
John Spurlockf55b7f22015-04-13 19:21:26 -0400828 switch (msg.what) {
John Spurlockf55b7f22015-04-13 19:21:26 -0400829 case MANUAL_RULE_CHANGED: handleUpdateManualRule((ZenRule) msg.obj); break;
830 case UPDATE_WIDGETS: updateWidgets(); break;
John Spurlock86005342014-05-23 11:58:00 -0400831 }
832 }
833 }
834
835 public interface Callback {
John Spurlockf55b7f22015-04-13 19:21:26 -0400836 void onPrioritySettings();
John Spurlock86005342014-05-23 11:58:00 -0400837 void onInteraction();
John Spurlockae641c92014-06-30 18:11:40 -0400838 void onExpanded(boolean expanded);
John Spurlock86005342014-05-23 11:58:00 -0400839 }
John Spurlock856edeb2014-06-01 20:36:47 -0400840
841 // used as the view tag on condition rows
842 private static class ConditionTag {
843 RadioButton rb;
John Spurlockc90e6fe2014-10-28 11:21:42 -0400844 View lines;
845 TextView line1;
846 TextView line2;
John Spurlock4db0d982014-08-13 09:19:03 -0400847 Condition condition;
John Spurlock856edeb2014-06-01 20:36:47 -0400848 }
849
John Spurlockf55b7f22015-04-13 19:21:26 -0400850 private final class ZenPrefs implements OnSharedPreferenceChangeListener {
John Spurlock8f8ecd62014-08-27 17:46:03 -0400851 private final int mNoneDangerousThreshold;
John Spurlock856edeb2014-06-01 20:36:47 -0400852
853 private int mMinuteIndex;
John Spurlock8f8ecd62014-08-27 17:46:03 -0400854 private int mNoneSelected;
John Spurlockd9c75db2015-04-28 11:19:13 -0400855 private boolean mConfirmedPriorityIntroduction;
856 private boolean mConfirmedSilenceIntroduction;
John Spurlock856edeb2014-06-01 20:36:47 -0400857
John Spurlockf55b7f22015-04-13 19:21:26 -0400858 private ZenPrefs() {
John Spurlock8f8ecd62014-08-27 17:46:03 -0400859 mNoneDangerousThreshold = mContext.getResources()
860 .getInteger(R.integer.zen_mode_alarm_warning_threshold);
John Spurlockf55b7f22015-04-13 19:21:26 -0400861 Prefs.registerListener(mContext, this);
John Spurlock856edeb2014-06-01 20:36:47 -0400862 updateMinuteIndex();
John Spurlock8f8ecd62014-08-27 17:46:03 -0400863 updateNoneSelected();
John Spurlockd9c75db2015-04-28 11:19:13 -0400864 updateConfirmedPriorityIntroduction();
865 updateConfirmedSilenceIntroduction();
John Spurlock8f8ecd62014-08-27 17:46:03 -0400866 }
867
868 public void trackNoneSelected() {
869 mNoneSelected = clampNoneSelected(mNoneSelected + 1);
870 if (DEBUG) Log.d(mTag, "Setting none selected: " + mNoneSelected + " threshold="
871 + mNoneDangerousThreshold);
John Spurlockf55b7f22015-04-13 19:21:26 -0400872 Prefs.putInt(mContext, Prefs.Key.DND_NONE_SELECTED, mNoneSelected);
John Spurlock856edeb2014-06-01 20:36:47 -0400873 }
874
875 public int getMinuteIndex() {
876 return mMinuteIndex;
877 }
878
879 public void setMinuteIndex(int minuteIndex) {
John Spurlock8f8ecd62014-08-27 17:46:03 -0400880 minuteIndex = clampIndex(minuteIndex);
John Spurlock856edeb2014-06-01 20:36:47 -0400881 if (minuteIndex == mMinuteIndex) return;
John Spurlock8f8ecd62014-08-27 17:46:03 -0400882 mMinuteIndex = clampIndex(minuteIndex);
John Spurlock856edeb2014-06-01 20:36:47 -0400883 if (DEBUG) Log.d(mTag, "Setting favorite minute index: " + mMinuteIndex);
John Spurlockf55b7f22015-04-13 19:21:26 -0400884 Prefs.putInt(mContext, Prefs.Key.DND_FAVORITE_BUCKET_INDEX, mMinuteIndex);
John Spurlock856edeb2014-06-01 20:36:47 -0400885 }
886
887 @Override
888 public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
889 updateMinuteIndex();
John Spurlock8f8ecd62014-08-27 17:46:03 -0400890 updateNoneSelected();
John Spurlockd9c75db2015-04-28 11:19:13 -0400891 updateConfirmedPriorityIntroduction();
892 updateConfirmedSilenceIntroduction();
John Spurlock856edeb2014-06-01 20:36:47 -0400893 }
894
895 private void updateMinuteIndex() {
John Spurlockf55b7f22015-04-13 19:21:26 -0400896 mMinuteIndex = clampIndex(Prefs.getInt(mContext,
897 Prefs.Key.DND_FAVORITE_BUCKET_INDEX, DEFAULT_BUCKET_INDEX));
John Spurlock856edeb2014-06-01 20:36:47 -0400898 if (DEBUG) Log.d(mTag, "Favorite minute index: " + mMinuteIndex);
899 }
900
John Spurlock8f8ecd62014-08-27 17:46:03 -0400901 private int clampIndex(int index) {
902 return MathUtils.constrain(index, -1, MINUTE_BUCKETS.length - 1);
903 }
904
905 private void updateNoneSelected() {
John Spurlockf55b7f22015-04-13 19:21:26 -0400906 mNoneSelected = clampNoneSelected(Prefs.getInt(mContext,
907 Prefs.Key.DND_NONE_SELECTED, 0));
John Spurlock8f8ecd62014-08-27 17:46:03 -0400908 if (DEBUG) Log.d(mTag, "None selected: " + mNoneSelected);
909 }
910
911 private int clampNoneSelected(int noneSelected) {
912 return MathUtils.constrain(noneSelected, 0, Integer.MAX_VALUE);
John Spurlock856edeb2014-06-01 20:36:47 -0400913 }
John Spurlockf55b7f22015-04-13 19:21:26 -0400914
John Spurlockd9c75db2015-04-28 11:19:13 -0400915 private void updateConfirmedPriorityIntroduction() {
John Spurlockf55b7f22015-04-13 19:21:26 -0400916 final boolean confirmed = Prefs.getBoolean(mContext,
917 Prefs.Key.DND_CONFIRMED_PRIORITY_INTRODUCTION, false);
John Spurlockd9c75db2015-04-28 11:19:13 -0400918 if (confirmed == mConfirmedPriorityIntroduction) return;
919 mConfirmedPriorityIntroduction = confirmed;
920 if (DEBUG) Log.d(mTag, "Confirmed priority introduction: "
921 + mConfirmedPriorityIntroduction);
922 }
923
924 private void updateConfirmedSilenceIntroduction() {
925 final boolean confirmed = Prefs.getBoolean(mContext,
926 Prefs.Key.DND_CONFIRMED_SILENCE_INTRODUCTION, false);
927 if (confirmed == mConfirmedSilenceIntroduction) return;
928 mConfirmedSilenceIntroduction = confirmed;
929 if (DEBUG) Log.d(mTag, "Confirmed silence introduction: "
930 + mConfirmedSilenceIntroduction);
John Spurlockf55b7f22015-04-13 19:21:26 -0400931 }
John Spurlock856edeb2014-06-01 20:36:47 -0400932 }
John Spurlockae641c92014-06-30 18:11:40 -0400933
Muyuan Li8303bd22016-03-23 20:08:26 -0700934 protected final SegmentedButtons.Callback mZenButtonsCallback = new SegmentedButtons.Callback() {
John Spurlockae641c92014-06-30 18:11:40 -0400935 @Override
Chris Wren4572cbc2015-06-29 11:27:18 -0400936 public void onSelected(final Object value, boolean fromClick) {
John Spurlockb2278d62015-04-07 12:47:12 -0400937 if (value != null && mZenButtons.isShown() && isAttachedToWindow()) {
John Spurlockd9c75db2015-04-28 11:19:13 -0400938 final int zen = (Integer) value;
Chris Wren4572cbc2015-06-29 11:27:18 -0400939 if (fromClick) {
Chris Wrenf6e9228b2016-01-26 18:04:35 -0500940 MetricsLogger.action(mContext, MetricsEvent.QS_DND_ZEN_SELECT, zen);
Chris Wren4572cbc2015-06-29 11:27:18 -0400941 }
John Spurlockd9c75db2015-04-28 11:19:13 -0400942 if (DEBUG) Log.d(mTag, "mZenButtonsCallback selected=" + zen);
John Spurlockb2278d62015-04-07 12:47:12 -0400943 final Uri realConditionId = getRealConditionId(mSessionExitCondition);
John Spurlock530052a2014-11-30 16:26:19 -0500944 AsyncTask.execute(new Runnable() {
945 @Override
946 public void run() {
John Spurlockd9c75db2015-04-28 11:19:13 -0400947 mController.setZen(zen, realConditionId, TAG + ".selectZen");
948 if (zen != Global.ZEN_MODE_OFF) {
949 Prefs.putInt(mContext, Prefs.Key.DND_FAVORITE_ZEN, zen);
950 }
John Spurlock530052a2014-11-30 16:26:19 -0500951 }
952 });
John Spurlockae641c92014-06-30 18:11:40 -0400953 }
954 }
John Spurlocka0457c22014-09-26 13:22:08 -0400955
956 @Override
957 public void onInteraction() {
958 fireInteraction();
959 }
960 };
961
962 private final Interaction.Callback mInteractionCallback = new Interaction.Callback() {
963 @Override
964 public void onInteraction() {
965 fireInteraction();
966 }
John Spurlockae641c92014-06-30 18:11:40 -0400967 };
John Spurlock530052a2014-11-30 16:26:19 -0500968
969 private final class TransitionHelper implements TransitionListener, Runnable {
970 private final ArraySet<View> mTransitioningViews = new ArraySet<View>();
971
972 private boolean mTransitioning;
John Spurlock530052a2014-11-30 16:26:19 -0500973 private boolean mPendingUpdateWidgets;
974
975 public void clear() {
976 mTransitioningViews.clear();
Julia Reynolds0842fe82015-10-01 14:34:22 -0400977 mPendingUpdateWidgets = false;
John Spurlock530052a2014-11-30 16:26:19 -0500978 }
979
980 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
981 pw.println(" TransitionHelper state:");
John Spurlock530052a2014-11-30 16:26:19 -0500982 pw.print(" mPendingUpdateWidgets="); pw.println(mPendingUpdateWidgets);
983 pw.print(" mTransitioning="); pw.println(mTransitioning);
984 pw.print(" mTransitioningViews="); pw.println(mTransitioningViews);
985 }
986
John Spurlock530052a2014-11-30 16:26:19 -0500987 public void pendingUpdateWidgets() {
988 mPendingUpdateWidgets = true;
989 }
990
991 public boolean isTransitioning() {
992 return !mTransitioningViews.isEmpty();
993 }
994
995 @Override
996 public void startTransition(LayoutTransition transition,
997 ViewGroup container, View view, int transitionType) {
998 mTransitioningViews.add(view);
999 updateTransitioning();
1000 }
1001
1002 @Override
1003 public void endTransition(LayoutTransition transition,
1004 ViewGroup container, View view, int transitionType) {
1005 mTransitioningViews.remove(view);
1006 updateTransitioning();
1007 }
1008
1009 @Override
1010 public void run() {
1011 if (DEBUG) Log.d(mTag, "TransitionHelper run"
Julia Reynolds0842fe82015-10-01 14:34:22 -04001012 + " mPendingUpdateWidgets=" + mPendingUpdateWidgets);
John Spurlock530052a2014-11-30 16:26:19 -05001013 if (mPendingUpdateWidgets) {
1014 updateWidgets();
1015 }
Julia Reynolds0842fe82015-10-01 14:34:22 -04001016 mPendingUpdateWidgets = false;
John Spurlock530052a2014-11-30 16:26:19 -05001017 }
1018
1019 private void updateTransitioning() {
1020 final boolean transitioning = isTransitioning();
1021 if (mTransitioning == transitioning) return;
1022 mTransitioning = transitioning;
1023 if (DEBUG) Log.d(mTag, "TransitionHelper mTransitioning=" + mTransitioning);
1024 if (!mTransitioning) {
Julia Reynolds0842fe82015-10-01 14:34:22 -04001025 if (mPendingUpdateWidgets) {
John Spurlock530052a2014-11-30 16:26:19 -05001026 mHandler.post(this);
1027 } else {
Julia Reynolds0842fe82015-10-01 14:34:22 -04001028 mPendingUpdateWidgets = false;
John Spurlock530052a2014-11-30 16:26:19 -05001029 }
1030 }
1031 }
1032 }
John Spurlock86005342014-05-23 11:58:00 -04001033}