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