• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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