Home | History | Annotate | Download | only in notification
      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
     67     protected boolean setRule(AutomaticZenRule rule) {
     68         mSchedule = rule != null ? ZenModeConfig.tryParseScheduleConditionId(rule.getConditionId())
     69                 : null;
     70         return mSchedule != null;
     71     }
     72 
     73     @Override
     74     protected String getZenModeDependency() {
     75         return mDays.getKey();
     76     }
     77 
     78     @Override
     79     protected int getEnabledToastText() {
     80         return R.string.zen_schedule_rule_enabled_toast;
     81     }
     82 
     83     @Override
     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 
    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 
    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
    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
    202     public int getMetricsCategory() {
    203         return MetricsEvent.NOTIFICATION_ZEN_MODE_SCHEDULE_RULE;
    204     }
    205 
    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 
    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 
    252         public void setCallback(Callback callback) {
    253             mCallback = callback;
    254         }
    255 
    256         public void setSummaryFormat(int resId) {
    257             mSummaryFormat = resId;
    258             updateSummary();
    259         }
    260 
    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 
    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
    284             public int getMetricsCategory() {
    285                 return MetricsEvent.DIALOG_ZEN_TIMEPICKER;
    286             }
    287 
    288             @Override
    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 
    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 {
    306             boolean onSetTime(int hour, int minute);
    307         }
    308     }
    309 
    310 }
    311