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