Home | History | Annotate | Download | only in notification
      1 /*
      2  * Copyright (C) 2017 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.ActivityManager;
     20 import android.app.AlarmManager;
     21 import android.app.AlarmManager.AlarmClockInfo;
     22 import android.app.NotificationManager;
     23 import android.content.ContentResolver;
     24 import android.content.Context;
     25 import android.database.ContentObserver;
     26 import android.net.Uri;
     27 import android.os.Handler;
     28 import android.os.UserHandle;
     29 import android.provider.Settings;
     30 import android.service.notification.ScheduleCalendar;
     31 import android.service.notification.ZenModeConfig;
     32 import android.support.v7.preference.Preference;
     33 import android.support.v7.preference.PreferenceScreen;
     34 
     35 import com.android.internal.annotations.VisibleForTesting;
     36 import com.android.settings.core.PreferenceControllerMixin;
     37 import com.android.settings.overlay.FeatureFactory;
     38 import com.android.settingslib.core.AbstractPreferenceController;
     39 import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
     40 import com.android.settingslib.core.lifecycle.Lifecycle;
     41 import com.android.settingslib.core.lifecycle.LifecycleObserver;
     42 import com.android.settingslib.core.lifecycle.events.OnPause;
     43 import com.android.settingslib.core.lifecycle.events.OnResume;
     44 
     45 abstract public class AbstractZenModePreferenceController extends
     46         AbstractPreferenceController implements PreferenceControllerMixin, LifecycleObserver,
     47         OnResume, OnPause {
     48 
     49     @VisibleForTesting
     50     protected SettingObserver mSettingObserver;
     51 
     52     private final String KEY;
     53     final private NotificationManager mNotificationManager;
     54     protected static ZenModeConfigWrapper mZenModeConfigWrapper;
     55     protected MetricsFeatureProvider mMetricsFeatureProvider;
     56     protected final ZenModeBackend mBackend;
     57     protected PreferenceScreen mScreen;
     58 
     59     public AbstractZenModePreferenceController(Context context, String key,
     60             Lifecycle lifecycle) {
     61         super(context);
     62         mZenModeConfigWrapper = new ZenModeConfigWrapper(context);
     63         if (lifecycle != null) {
     64             lifecycle.addObserver(this);
     65         }
     66         KEY = key;
     67         mNotificationManager = (NotificationManager) context.getSystemService(
     68                 Context.NOTIFICATION_SERVICE);
     69 
     70         final FeatureFactory featureFactory = FeatureFactory.getFactory(mContext);
     71         mMetricsFeatureProvider = featureFactory.getMetricsFeatureProvider();
     72         mBackend = ZenModeBackend.getInstance(context);
     73     }
     74 
     75     @Override
     76     public String getPreferenceKey() {
     77         return KEY;
     78     }
     79 
     80     @Override
     81     public void displayPreference(PreferenceScreen screen) {
     82         super.displayPreference(screen);
     83         mScreen = screen;
     84         Preference pref = screen.findPreference(KEY);
     85         if (pref != null) {
     86             mSettingObserver = new SettingObserver(pref);
     87         }
     88     }
     89 
     90     @Override
     91     public void onResume() {
     92         if (mSettingObserver != null) {
     93             mSettingObserver.register(mContext.getContentResolver());
     94             mSettingObserver.onChange(false, null);
     95         }
     96     }
     97 
     98     @Override
     99     public void onPause() {
    100         if (mSettingObserver != null) {
    101             mSettingObserver.unregister(mContext.getContentResolver());
    102         }
    103     }
    104 
    105     protected NotificationManager.Policy getPolicy() {
    106         return mNotificationManager.getNotificationPolicy();
    107     }
    108 
    109     protected ZenModeConfig getZenModeConfig() {
    110         return mNotificationManager.getZenModeConfig();
    111     }
    112 
    113     protected int getZenMode() {
    114         return Settings.Global.getInt(mContext.getContentResolver(), Settings.Global.ZEN_MODE,
    115                 mBackend.mZenMode);
    116     }
    117 
    118     protected int getZenDuration() {
    119         return Settings.Global.getInt(mContext.getContentResolver(), Settings.Global.ZEN_DURATION,
    120                 0);
    121     }
    122 
    123     class SettingObserver extends ContentObserver {
    124         private final Uri ZEN_MODE_URI = Settings.Global.getUriFor(Settings.Global.ZEN_MODE);
    125         private final Uri ZEN_MODE_CONFIG_ETAG_URI = Settings.Global.getUriFor(
    126                 Settings.Global.ZEN_MODE_CONFIG_ETAG);
    127         private final Uri ZEN_MODE_DURATION_URI = Settings.Global.getUriFor(
    128                 Settings.Global.ZEN_DURATION);
    129 
    130         private final Preference mPreference;
    131 
    132         public SettingObserver(Preference preference) {
    133             super(new Handler());
    134             mPreference = preference;
    135         }
    136 
    137         public void register(ContentResolver cr) {
    138             cr.registerContentObserver(ZEN_MODE_URI, false, this, UserHandle.USER_ALL);
    139             cr.registerContentObserver(ZEN_MODE_CONFIG_ETAG_URI, false, this, UserHandle.USER_ALL);
    140             cr.registerContentObserver(ZEN_MODE_DURATION_URI, false, this, UserHandle.USER_ALL);
    141         }
    142 
    143         public void unregister(ContentResolver cr) {
    144             cr.unregisterContentObserver(this);
    145         }
    146 
    147         @Override
    148         public void onChange(boolean selfChange, Uri uri) {
    149             super.onChange(selfChange, uri);
    150             if (uri == null || ZEN_MODE_URI.equals(uri) || ZEN_MODE_CONFIG_ETAG_URI.equals(uri)
    151                     || ZEN_MODE_DURATION_URI.equals(uri)) {
    152                 mBackend.updatePolicy();
    153                 mBackend.updateZenMode();
    154                 if (mScreen != null) {
    155                     displayPreference(mScreen);
    156                 }
    157                 updateState(mPreference);
    158             }
    159         }
    160     }
    161 
    162     /**
    163      * Wrapper for testing compatibility
    164      */
    165     @VisibleForTesting
    166     static class ZenModeConfigWrapper {
    167         private final Context mContext;
    168 
    169         public ZenModeConfigWrapper(Context context) {
    170             mContext = context;
    171         }
    172 
    173         protected String getOwnerCaption(String owner) {
    174             return ZenModeConfig.getOwnerCaption(mContext, owner);
    175         }
    176 
    177         protected boolean isTimeRule(Uri id) {
    178             return ZenModeConfig.isValidEventConditionId(id) ||
    179                     ZenModeConfig.isValidScheduleConditionId(id);
    180         }
    181 
    182         protected CharSequence getFormattedTime(long time, int userHandle) {
    183             return ZenModeConfig.getFormattedTime(mContext, time, isToday(time), userHandle);
    184         }
    185 
    186         private boolean isToday(long time) {
    187             return ZenModeConfig.isToday(time);
    188         }
    189 
    190         protected long parseManualRuleTime(Uri id) {
    191             return ZenModeConfig.tryParseCountdownConditionId(id);
    192         }
    193 
    194         protected long parseAutomaticRuleEndTime(Uri id) {
    195             if (ZenModeConfig.isValidEventConditionId(id)) {
    196                 // cannot look up end times for events
    197                 return Long.MAX_VALUE;
    198             }
    199 
    200             if (ZenModeConfig.isValidScheduleConditionId(id)) {
    201                 ScheduleCalendar schedule = ZenModeConfig.toScheduleCalendar(id);
    202                 long endTimeMs = schedule.getNextChangeTime(System.currentTimeMillis());
    203 
    204                 // check if automatic rule will end on next alarm
    205                 if (schedule.exitAtAlarm()) {
    206                     long nextAlarm = getNextAlarm(mContext);
    207                     schedule.maybeSetNextAlarm(System.currentTimeMillis(), nextAlarm);
    208                     if (schedule.shouldExitForAlarm(endTimeMs)) {
    209                         return nextAlarm;
    210                     }
    211                 }
    212 
    213                 return endTimeMs;
    214             }
    215 
    216             return -1;
    217         }
    218     }
    219 
    220     private static long getNextAlarm(Context context) {
    221         final AlarmManager alarms = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
    222         final AlarmClockInfo info = alarms.getNextAlarmClock(ActivityManager.getCurrentUser());
    223         return info != null ? info.getTriggerTime() : 0;
    224     }
    225 }
    226