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.zen; 18 19 import android.app.AutomaticZenRule; 20 import android.app.Dialog; 21 import android.app.TimePickerDialog; 22 import android.app.settings.SettingsEnums; 23 import android.content.Context; 24 import android.content.DialogInterface; 25 import android.content.DialogInterface.OnDismissListener; 26 import android.os.Bundle; 27 import android.provider.Settings; 28 import android.service.notification.ZenModeConfig; 29 import android.service.notification.ZenModeConfig.ScheduleInfo; 30 import android.text.format.DateFormat; 31 import android.util.Log; 32 import android.widget.TimePicker; 33 34 import androidx.appcompat.app.AlertDialog; 35 import androidx.fragment.app.FragmentManager; 36 import androidx.preference.Preference; 37 import androidx.preference.Preference.OnPreferenceClickListener; 38 import androidx.preference.PreferenceScreen; 39 import androidx.preference.SwitchPreference; 40 41 import com.android.settings.R; 42 import com.android.settings.core.instrumentation.InstrumentedDialogFragment; 43 import com.android.settingslib.core.AbstractPreferenceController; 44 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 private final ZenRuleScheduleHelper mScheduleHelper = new ZenRuleScheduleHelper(); 59 60 private Preference mDays; 61 private TimePickerPreference mStart; 62 private TimePickerPreference mEnd; 63 private SwitchPreference mExitAtAlarm; 64 private AlertDialog mDayDialog; 65 private ScheduleInfo mSchedule; 66 67 @Override setRule(AutomaticZenRule rule)68 protected boolean setRule(AutomaticZenRule rule) { 69 mSchedule = rule != null ? ZenModeConfig.tryParseScheduleConditionId(rule.getConditionId()) 70 : null; 71 return mSchedule != null; 72 } 73 74 @Override getPreferenceScreenResId()75 protected int getPreferenceScreenResId() { 76 return R.xml.zen_mode_schedule_rule_settings; 77 } 78 79 @Override onCreateInternal()80 protected void onCreateInternal() { 81 final PreferenceScreen root = getPreferenceScreen(); 82 83 mDays = root.findPreference(KEY_DAYS); 84 mDays.setOnPreferenceClickListener(new OnPreferenceClickListener() { 85 @Override 86 public boolean onPreferenceClick(Preference preference) { 87 showDaysDialog(); 88 return true; 89 } 90 }); 91 92 final FragmentManager mgr = getFragmentManager(); 93 94 mStart = new TimePickerPreference(getPrefContext(), mgr); 95 mStart.setKey(KEY_START_TIME); 96 mStart.setTitle(R.string.zen_mode_start_time); 97 mStart.setCallback(new TimePickerPreference.Callback() { 98 @Override 99 public boolean onSetTime(final int hour, final int minute) { 100 if (mDisableListeners) return true; 101 if (!ZenModeConfig.isValidHour(hour)) return false; 102 if (!ZenModeConfig.isValidMinute(minute)) return false; 103 if (hour == mSchedule.startHour && minute == mSchedule.startMinute) { 104 return true; 105 } 106 if (DEBUG) Log.d(TAG, "onPrefChange start h=" + hour + " m=" + minute); 107 mSchedule.startHour = hour; 108 mSchedule.startMinute = minute; 109 updateRule(ZenModeConfig.toScheduleConditionId(mSchedule)); 110 return true; 111 } 112 }); 113 root.addPreference(mStart); 114 mStart.setDependency(mDays.getKey()); 115 116 mEnd = new TimePickerPreference(getPrefContext(), mgr); 117 mEnd.setKey(KEY_END_TIME); 118 mEnd.setTitle(R.string.zen_mode_end_time); 119 mEnd.setCallback(new TimePickerPreference.Callback() { 120 @Override 121 public boolean onSetTime(final int hour, final int minute) { 122 if (mDisableListeners) return true; 123 if (!ZenModeConfig.isValidHour(hour)) return false; 124 if (!ZenModeConfig.isValidMinute(minute)) return false; 125 if (hour == mSchedule.endHour && minute == mSchedule.endMinute) { 126 return true; 127 } 128 if (DEBUG) Log.d(TAG, "onPrefChange end h=" + hour + " m=" + minute); 129 mSchedule.endHour = hour; 130 mSchedule.endMinute = minute; 131 updateRule(ZenModeConfig.toScheduleConditionId(mSchedule)); 132 return true; 133 } 134 }); 135 root.addPreference(mEnd); 136 mEnd.setDependency(mDays.getKey()); 137 138 mExitAtAlarm = (SwitchPreference) root.findPreference(KEY_EXIT_AT_ALARM); 139 mExitAtAlarm.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { 140 @Override 141 public boolean onPreferenceChange(Preference preference, Object o) { 142 mSchedule.exitAtAlarm = (Boolean) o; 143 updateRule(ZenModeConfig.toScheduleConditionId(mSchedule)); 144 return true; 145 } 146 }); 147 } 148 updateDays()149 private void updateDays() { 150 String desc = mScheduleHelper.getDaysDescription(mContext, mSchedule); 151 if (desc != null) { 152 mDays.setSummary(desc); 153 mDays.notifyDependencyChange(false); 154 return; 155 } 156 mDays.setSummary(R.string.zen_mode_schedule_rule_days_none); 157 mDays.notifyDependencyChange(true); 158 } 159 updateEndSummary()160 private void updateEndSummary() { 161 final int startMin = 60 * mSchedule.startHour + mSchedule.startMinute; 162 final int endMin = 60 * mSchedule.endHour + mSchedule.endMinute; 163 final boolean nextDay = startMin >= endMin; 164 final int summaryFormat = nextDay ? R.string.zen_mode_end_time_next_day_summary_format : 0; 165 mEnd.setSummaryFormat(summaryFormat); 166 } 167 @Override updateControlsInternal()168 protected void updateControlsInternal() { 169 updateDays(); 170 mStart.setTime(mSchedule.startHour, mSchedule.startMinute); 171 mEnd.setTime(mSchedule.endHour, mSchedule.endMinute); 172 mExitAtAlarm.setChecked(mSchedule.exitAtAlarm); 173 updateEndSummary(); 174 } 175 176 @Override createPreferenceControllers(Context context)177 protected List<AbstractPreferenceController> createPreferenceControllers(Context context) { 178 List<AbstractPreferenceController> controllers = new ArrayList<>(); 179 mHeader = new ZenAutomaticRuleHeaderPreferenceController(context, this, 180 getSettingsLifecycle()); 181 mActionButtons = new ZenRuleButtonsPreferenceController(context, this, 182 getSettingsLifecycle()); 183 mSwitch = new ZenAutomaticRuleSwitchPreferenceController(context, this, 184 getSettingsLifecycle()); 185 controllers.add(mHeader); 186 controllers.add(mActionButtons); 187 controllers.add(mSwitch); 188 return controllers; 189 } 190 191 @Override getMetricsCategory()192 public int getMetricsCategory() { 193 return SettingsEnums.NOTIFICATION_ZEN_MODE_SCHEDULE_RULE; 194 } 195 196 @Override onDestroy()197 public void onDestroy() { 198 super.onDestroy(); 199 if (mDayDialog != null && mDayDialog.isShowing()) { 200 mDayDialog.dismiss(); 201 mDayDialog = null; 202 } 203 } 204 showDaysDialog()205 private void showDaysDialog() { 206 mDayDialog = 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.toString(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 TimePickerPreference(Context context, final FragmentManager mgr)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 setCallback(Callback callback)251 public void setCallback(Callback callback) { 252 mCallback = callback; 253 } 254 setSummaryFormat(int resId)255 public void setSummaryFormat(int resId) { 256 mSummaryFormat = resId; 257 updateSummary(); 258 } 259 setTime(int hourOfDay, int minute)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 updateSummary()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 InstrumentedDialogFragment implements 279 TimePickerDialog.OnTimeSetListener { 280 public TimePickerPreference pref; 281 282 @Override getMetricsCategory()283 public int getMetricsCategory() { 284 return SettingsEnums.DIALOG_ZEN_TIMEPICKER; 285 } 286 287 @Override onCreateDialog(Bundle savedInstanceState)288 public Dialog onCreateDialog(Bundle savedInstanceState) { 289 final boolean usePref = pref != null && pref.mHourOfDay >= 0 && pref.mMinute >= 0; 290 final Calendar c = Calendar.getInstance(); 291 final int hour = usePref ? pref.mHourOfDay : c.get(Calendar.HOUR_OF_DAY); 292 final int minute = usePref ? pref.mMinute : c.get(Calendar.MINUTE); 293 return new TimePickerDialog(getActivity(), this, hour, minute, 294 DateFormat.is24HourFormat(getActivity())); 295 } 296 onTimeSet(TimePicker view, int hourOfDay, int minute)297 public void onTimeSet(TimePicker view, int hourOfDay, int minute) { 298 if (pref != null) { 299 pref.setTime(hourOfDay, minute); 300 } 301 } 302 } 303 304 public interface Callback { onSetTime(int hour, int minute)305 boolean onSetTime(int hour, int minute); 306 } 307 } 308 } 309