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