1 /* 2 * Copyright (C) 2015 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 17 package com.android.settings.notification; 18 19 import android.app.AlertDialog; 20 import android.app.AutomaticZenRule; 21 import android.app.Dialog; 22 import android.app.FragmentManager; 23 import android.app.TimePickerDialog; 24 import android.content.Context; 25 import android.content.DialogInterface; 26 import android.content.DialogInterface.OnDismissListener; 27 import android.os.Bundle; 28 import android.provider.Settings; 29 import android.service.notification.ZenModeConfig; 30 import android.service.notification.ZenModeConfig.ScheduleInfo; 31 import android.support.v14.preference.SwitchPreference; 32 import android.support.v7.preference.Preference; 33 import android.support.v7.preference.Preference.OnPreferenceClickListener; 34 import android.support.v7.preference.PreferenceScreen; 35 import android.text.format.DateFormat; 36 import android.util.Log; 37 import android.widget.TimePicker; 38 39 import com.android.internal.logging.nano.MetricsProto.MetricsEvent; 40 import com.android.settings.R; 41 import com.android.settings.core.instrumentation.InstrumentedDialogFragment; 42 import com.android.settingslib.core.AbstractPreferenceController; 43 44 import java.text.SimpleDateFormat; 45 import java.util.ArrayList; 46 import java.util.Arrays; 47 import java.util.Calendar; 48 import java.util.List; 49 50 public class ZenModeScheduleRuleSettings extends ZenModeRuleSettingsBase { 51 private static final String KEY_DAYS = "days"; 52 private static final String KEY_START_TIME = "start_time"; 53 private static final String KEY_END_TIME = "end_time"; 54 private static final String KEY_EXIT_AT_ALARM = "exit_at_alarm"; 55 56 public static final String ACTION = Settings.ACTION_ZEN_MODE_SCHEDULE_RULE_SETTINGS; 57 58 // per-instance to ensure we're always using the current locale 59 private final SimpleDateFormat mDayFormat = new SimpleDateFormat("EEE"); 60 61 private Preference mDays; 62 private TimePickerPreference mStart; 63 private TimePickerPreference mEnd; 64 private SwitchPreference mExitAtAlarm; 65 66 private ScheduleInfo mSchedule; 67 68 @Override setRule(AutomaticZenRule rule)69 protected boolean setRule(AutomaticZenRule rule) { 70 mSchedule = rule != null ? ZenModeConfig.tryParseScheduleConditionId(rule.getConditionId()) 71 : null; 72 return mSchedule != null; 73 } 74 75 @Override getPreferenceScreenResId()76 protected int getPreferenceScreenResId() { 77 return R.xml.zen_mode_schedule_rule_settings; 78 } 79 80 @Override onCreateInternal()81 protected void onCreateInternal() { 82 final PreferenceScreen root = getPreferenceScreen(); 83 84 mDays = root.findPreference(KEY_DAYS); 85 mDays.setOnPreferenceClickListener(new OnPreferenceClickListener() { 86 @Override 87 public boolean onPreferenceClick(Preference preference) { 88 showDaysDialog(); 89 return true; 90 } 91 }); 92 93 final FragmentManager mgr = getFragmentManager(); 94 95 mStart = new TimePickerPreference(getPrefContext(), mgr); 96 mStart.setKey(KEY_START_TIME); 97 mStart.setTitle(R.string.zen_mode_start_time); 98 mStart.setCallback(new TimePickerPreference.Callback() { 99 @Override 100 public boolean onSetTime(final int hour, final int minute) { 101 if (mDisableListeners) return true; 102 if (!ZenModeConfig.isValidHour(hour)) return false; 103 if (!ZenModeConfig.isValidMinute(minute)) return false; 104 if (hour == mSchedule.startHour && minute == mSchedule.startMinute) { 105 return true; 106 } 107 if (DEBUG) Log.d(TAG, "onPrefChange start h=" + hour + " m=" + minute); 108 mSchedule.startHour = hour; 109 mSchedule.startMinute = minute; 110 updateRule(ZenModeConfig.toScheduleConditionId(mSchedule)); 111 return true; 112 } 113 }); 114 root.addPreference(mStart); 115 mStart.setDependency(mDays.getKey()); 116 117 mEnd = new TimePickerPreference(getPrefContext(), mgr); 118 mEnd.setKey(KEY_END_TIME); 119 mEnd.setTitle(R.string.zen_mode_end_time); 120 mEnd.setCallback(new TimePickerPreference.Callback() { 121 @Override 122 public boolean onSetTime(final int hour, final int minute) { 123 if (mDisableListeners) return true; 124 if (!ZenModeConfig.isValidHour(hour)) return false; 125 if (!ZenModeConfig.isValidMinute(minute)) return false; 126 if (hour == mSchedule.endHour && minute == mSchedule.endMinute) { 127 return true; 128 } 129 if (DEBUG) Log.d(TAG, "onPrefChange end h=" + hour + " m=" + minute); 130 mSchedule.endHour = hour; 131 mSchedule.endMinute = minute; 132 updateRule(ZenModeConfig.toScheduleConditionId(mSchedule)); 133 return true; 134 } 135 }); 136 root.addPreference(mEnd); 137 mEnd.setDependency(mDays.getKey()); 138 139 mExitAtAlarm = (SwitchPreference) root.findPreference(KEY_EXIT_AT_ALARM); 140 mExitAtAlarm.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { 141 @Override 142 public boolean onPreferenceChange(Preference preference, Object o) { 143 mSchedule.exitAtAlarm = (Boolean) o; 144 updateRule(ZenModeConfig.toScheduleConditionId(mSchedule)); 145 return true; 146 } 147 }); 148 } 149 updateDays()150 private void updateDays() { 151 // Compute an ordered, delimited list of day names based on the persisted user config. 152 final int[] days = mSchedule.days; 153 if (days != null && days.length > 0) { 154 final StringBuilder sb = new StringBuilder(); 155 final Calendar c = Calendar.getInstance(); 156 int[] daysOfWeek = ZenModeScheduleDaysSelection.getDaysOfWeekForLocale(c); 157 for (int i = 0; i < daysOfWeek.length; i++) { 158 final int day = daysOfWeek[i]; 159 for (int j = 0; j < days.length; j++) { 160 if (day == days[j]) { 161 c.set(Calendar.DAY_OF_WEEK, day); 162 if (sb.length() > 0) { 163 sb.append(mContext.getString(R.string.summary_divider_text)); 164 } 165 sb.append(mDayFormat.format(c.getTime())); 166 break; 167 } 168 } 169 } 170 if (sb.length() > 0) { 171 mDays.setSummary(sb); 172 mDays.notifyDependencyChange(false); 173 return; 174 } 175 } 176 mDays.setSummary(R.string.zen_mode_schedule_rule_days_none); 177 mDays.notifyDependencyChange(true); 178 } 179 updateEndSummary()180 private void updateEndSummary() { 181 final int startMin = 60 * mSchedule.startHour + mSchedule.startMinute; 182 final int endMin = 60 * mSchedule.endHour + mSchedule.endMinute; 183 final boolean nextDay = startMin >= endMin; 184 final int summaryFormat = nextDay ? R.string.zen_mode_end_time_next_day_summary_format : 0; 185 mEnd.setSummaryFormat(summaryFormat); 186 } 187 188 @Override updateControlsInternal()189 protected void updateControlsInternal() { 190 updateDays(); 191 mStart.setTime(mSchedule.startHour, mSchedule.startMinute); 192 mEnd.setTime(mSchedule.endHour, mSchedule.endMinute); 193 mExitAtAlarm.setChecked(mSchedule.exitAtAlarm); 194 updateEndSummary(); 195 } 196 197 198 @Override createPreferenceControllers(Context context)199 protected List<AbstractPreferenceController> createPreferenceControllers(Context context) { 200 List<AbstractPreferenceController> controllers = new ArrayList<>(); 201 mHeader = new ZenAutomaticRuleHeaderPreferenceController(context, this, 202 getLifecycle()); 203 mSwitch = new ZenAutomaticRuleSwitchPreferenceController(context, this, getLifecycle()); 204 205 controllers.add(mHeader); 206 controllers.add(mSwitch); 207 return controllers; 208 } 209 210 @Override getMetricsCategory()211 public int getMetricsCategory() { 212 return MetricsEvent.NOTIFICATION_ZEN_MODE_SCHEDULE_RULE; 213 } 214 showDaysDialog()215 private void showDaysDialog() { 216 new AlertDialog.Builder(mContext) 217 .setTitle(R.string.zen_mode_schedule_rule_days) 218 .setView(new ZenModeScheduleDaysSelection(mContext, mSchedule.days) { 219 @Override 220 protected void onChanged(final int[] days) { 221 if (mDisableListeners) return; 222 if (Arrays.equals(days, mSchedule.days)) return; 223 if (DEBUG) Log.d(TAG, "days.onChanged days=" + Arrays.asList(days)); 224 mSchedule.days = days; 225 updateRule(ZenModeConfig.toScheduleConditionId(mSchedule)); 226 } 227 }) 228 .setOnDismissListener(new OnDismissListener() { 229 @Override 230 public void onDismiss(DialogInterface dialog) { 231 updateDays(); 232 } 233 }) 234 .setPositiveButton(R.string.done_button, null) 235 .show(); 236 } 237 238 private static class TimePickerPreference extends Preference { 239 private final Context mContext; 240 241 private int mSummaryFormat; 242 private int mHourOfDay; 243 private int mMinute; 244 private Callback mCallback; 245 TimePickerPreference(Context context, final FragmentManager mgr)246 public TimePickerPreference(Context context, final FragmentManager mgr) { 247 super(context); 248 mContext = context; 249 setPersistent(false); 250 setOnPreferenceClickListener(new OnPreferenceClickListener(){ 251 @Override 252 public boolean onPreferenceClick(Preference preference) { 253 final TimePickerFragment frag = new TimePickerFragment(); 254 frag.pref = TimePickerPreference.this; 255 frag.show(mgr, TimePickerPreference.class.getName()); 256 return true; 257 } 258 }); 259 } 260 setCallback(Callback callback)261 public void setCallback(Callback callback) { 262 mCallback = callback; 263 } 264 setSummaryFormat(int resId)265 public void setSummaryFormat(int resId) { 266 mSummaryFormat = resId; 267 updateSummary(); 268 } 269 setTime(int hourOfDay, int minute)270 public void setTime(int hourOfDay, int minute) { 271 if (mCallback != null && !mCallback.onSetTime(hourOfDay, minute)) return; 272 mHourOfDay = hourOfDay; 273 mMinute = minute; 274 updateSummary(); 275 } 276 updateSummary()277 private void updateSummary() { 278 final Calendar c = Calendar.getInstance(); 279 c.set(Calendar.HOUR_OF_DAY, mHourOfDay); 280 c.set(Calendar.MINUTE, mMinute); 281 String time = DateFormat.getTimeFormat(mContext).format(c.getTime()); 282 if (mSummaryFormat != 0) { 283 time = mContext.getResources().getString(mSummaryFormat, time); 284 } 285 setSummary(time); 286 } 287 288 public static class TimePickerFragment extends InstrumentedDialogFragment implements 289 TimePickerDialog.OnTimeSetListener { 290 public TimePickerPreference pref; 291 292 @Override getMetricsCategory()293 public int getMetricsCategory() { 294 return MetricsEvent.DIALOG_ZEN_TIMEPICKER; 295 } 296 297 @Override onCreateDialog(Bundle savedInstanceState)298 public Dialog onCreateDialog(Bundle savedInstanceState) { 299 final boolean usePref = pref != null && pref.mHourOfDay >= 0 && pref.mMinute >= 0; 300 final Calendar c = Calendar.getInstance(); 301 final int hour = usePref ? pref.mHourOfDay : c.get(Calendar.HOUR_OF_DAY); 302 final int minute = usePref ? pref.mMinute : c.get(Calendar.MINUTE); 303 return new TimePickerDialog(getActivity(), this, hour, minute, 304 DateFormat.is24HourFormat(getActivity())); 305 } 306 onTimeSet(TimePicker view, int hourOfDay, int minute)307 public void onTimeSet(TimePicker view, int hourOfDay, int minute) { 308 if (pref != null) { 309 pref.setTime(hourOfDay, minute); 310 } 311 } 312 } 313 314 public interface Callback { onSetTime(int hour, int minute)315 boolean onSetTime(int hour, int minute); 316 } 317 } 318 } 319