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