1 /* 2 * Copyright (C) 2014 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.systemui.statusbar.policy; 18 19 import android.app.ActivityManager; 20 import android.app.AlarmManager; 21 import android.app.NotificationManager; 22 import android.content.BroadcastReceiver; 23 import android.content.ComponentName; 24 import android.content.ContentResolver; 25 import android.content.Context; 26 import android.content.Intent; 27 import android.content.IntentFilter; 28 import android.database.ContentObserver; 29 import android.net.Uri; 30 import android.os.Handler; 31 import android.os.UserHandle; 32 import android.os.UserManager; 33 import android.provider.Settings.Global; 34 import android.provider.Settings.Secure; 35 import android.service.notification.Condition; 36 import android.service.notification.ZenModeConfig; 37 import android.service.notification.ZenModeConfig.ZenRule; 38 import android.util.Log; 39 import android.util.Slog; 40 41 import com.android.internal.annotations.VisibleForTesting; 42 import com.android.systemui.qs.GlobalSetting; 43 import com.android.systemui.settings.CurrentUserTracker; 44 import com.android.systemui.util.Utils; 45 46 import java.util.ArrayList; 47 import java.util.LinkedHashMap; 48 import java.util.Objects; 49 50 /** Platform implementation of the zen mode controller. **/ 51 public class ZenModeControllerImpl extends CurrentUserTracker implements ZenModeController { 52 private static final String TAG = "ZenModeController"; 53 private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); 54 55 private final ArrayList<Callback> mCallbacks = new ArrayList<Callback>(); 56 private final Context mContext; 57 private final GlobalSetting mModeSetting; 58 private final GlobalSetting mConfigSetting; 59 private final NotificationManager mNoMan; 60 private final LinkedHashMap<Uri, Condition> mConditions = new LinkedHashMap<Uri, Condition>(); 61 private final AlarmManager mAlarmManager; 62 private final SetupObserver mSetupObserver; 63 private final UserManager mUserManager; 64 65 private int mUserId; 66 private boolean mRegistered; 67 private ZenModeConfig mConfig; 68 private int mZenMode; 69 70 public ZenModeControllerImpl(Context context, Handler handler) { 71 super(context); 72 mContext = context; 73 mModeSetting = new GlobalSetting(mContext, handler, Global.ZEN_MODE) { 74 @Override 75 protected void handleValueChanged(int value) { 76 updateZenMode(value); 77 fireZenChanged(value); 78 } 79 }; 80 mConfigSetting = new GlobalSetting(mContext, handler, Global.ZEN_MODE_CONFIG_ETAG) { 81 @Override 82 protected void handleValueChanged(int value) { 83 updateZenModeConfig(); 84 } 85 }; 86 mNoMan = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); 87 mConfig = mNoMan.getZenModeConfig(); 88 mModeSetting.setListening(true); 89 updateZenMode(mModeSetting.getValue()); 90 mConfigSetting.setListening(true); 91 updateZenModeConfig(); 92 mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); 93 mSetupObserver = new SetupObserver(handler); 94 mSetupObserver.register(); 95 mUserManager = context.getSystemService(UserManager.class); 96 startTracking(); 97 } 98 99 @Override 100 public boolean isVolumeRestricted() { 101 return mUserManager.hasUserRestriction(UserManager.DISALLOW_ADJUST_VOLUME, 102 new UserHandle(mUserId)); 103 } 104 105 @Override 106 public boolean areNotificationsHiddenInShade() { 107 if (mZenMode != Global.ZEN_MODE_OFF) { 108 return (mConfig.suppressedVisualEffects & NotificationManager.Policy 109 .SUPPRESSED_EFFECT_NOTIFICATION_LIST) != 0; 110 } 111 return false; 112 } 113 114 @Override 115 public void addCallback(Callback callback) { 116 if (callback == null) { 117 Slog.e(TAG, "Attempted to add a null callback."); 118 return; 119 } 120 mCallbacks.add(callback); 121 } 122 123 @Override 124 public void removeCallback(Callback callback) { 125 mCallbacks.remove(callback); 126 } 127 128 @Override 129 public int getZen() { 130 return mZenMode; 131 } 132 133 @Override 134 public void setZen(int zen, Uri conditionId, String reason) { 135 mNoMan.setZenMode(zen, conditionId, reason); 136 } 137 138 @Override 139 public boolean isZenAvailable() { 140 return mSetupObserver.isDeviceProvisioned() && mSetupObserver.isUserSetup(); 141 } 142 143 @Override 144 public ZenRule getManualRule() { 145 return mConfig == null ? null : mConfig.manualRule; 146 } 147 148 @Override 149 public ZenModeConfig getConfig() { 150 return mConfig; 151 } 152 153 @Override 154 public long getNextAlarm() { 155 final AlarmManager.AlarmClockInfo info = mAlarmManager.getNextAlarmClock(mUserId); 156 return info != null ? info.getTriggerTime() : 0; 157 } 158 159 @Override 160 public void onUserSwitched(int userId) { 161 mUserId = userId; 162 if (mRegistered) { 163 mContext.unregisterReceiver(mReceiver); 164 } 165 final IntentFilter filter = new IntentFilter(AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED); 166 filter.addAction(NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED); 167 mContext.registerReceiverAsUser(mReceiver, new UserHandle(mUserId), filter, null, null); 168 mRegistered = true; 169 mSetupObserver.register(); 170 } 171 172 @Override 173 public ComponentName getEffectsSuppressor() { 174 return NotificationManager.from(mContext).getEffectsSuppressor(); 175 } 176 177 @Override 178 public boolean isCountdownConditionSupported() { 179 return NotificationManager.from(mContext) 180 .isSystemConditionProviderEnabled(ZenModeConfig.COUNTDOWN_PATH); 181 } 182 183 @Override 184 public int getCurrentUser() { 185 return ActivityManager.getCurrentUser(); 186 } 187 188 private void fireNextAlarmChanged() { 189 Utils.safeForeach(mCallbacks, c -> c.onNextAlarmChanged()); 190 } 191 192 private void fireEffectsSuppressorChanged() { 193 Utils.safeForeach(mCallbacks, c -> c.onEffectsSupressorChanged()); 194 } 195 196 private void fireZenChanged(int zen) { 197 Utils.safeForeach(mCallbacks, c -> c.onZenChanged(zen)); 198 } 199 200 private void fireZenAvailableChanged(boolean available) { 201 Utils.safeForeach(mCallbacks, c -> c.onZenAvailableChanged(available)); 202 } 203 204 private void fireManualRuleChanged(ZenRule rule) { 205 Utils.safeForeach(mCallbacks, c -> c.onManualRuleChanged(rule)); 206 } 207 208 @VisibleForTesting 209 protected void fireConfigChanged(ZenModeConfig config) { 210 Utils.safeForeach(mCallbacks, c -> c.onConfigChanged(config)); 211 } 212 213 @VisibleForTesting 214 protected void updateZenMode(int mode) { 215 mZenMode = mode; 216 } 217 218 @VisibleForTesting 219 protected void updateZenModeConfig() { 220 final ZenModeConfig config = mNoMan.getZenModeConfig(); 221 if (Objects.equals(config, mConfig)) return; 222 final ZenRule oldRule = mConfig != null ? mConfig.manualRule : null; 223 mConfig = config; 224 fireConfigChanged(config); 225 final ZenRule newRule = config != null ? config.manualRule : null; 226 if (Objects.equals(oldRule, newRule)) return; 227 fireManualRuleChanged(newRule); 228 } 229 230 private final BroadcastReceiver mReceiver = new BroadcastReceiver() { 231 @Override 232 public void onReceive(Context context, Intent intent) { 233 if (AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED.equals(intent.getAction())) { 234 fireNextAlarmChanged(); 235 } 236 if (NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED.equals(intent.getAction())) { 237 fireEffectsSuppressorChanged(); 238 } 239 } 240 }; 241 242 private final class SetupObserver extends ContentObserver { 243 private final ContentResolver mResolver; 244 245 private boolean mRegistered; 246 247 public SetupObserver(Handler handler) { 248 super(handler); 249 mResolver = mContext.getContentResolver(); 250 } 251 252 public boolean isUserSetup() { 253 return Secure.getIntForUser(mResolver, Secure.USER_SETUP_COMPLETE, 0, mUserId) != 0; 254 } 255 256 public boolean isDeviceProvisioned() { 257 return Global.getInt(mResolver, Global.DEVICE_PROVISIONED, 0) != 0; 258 } 259 260 public void register() { 261 if (mRegistered) { 262 mResolver.unregisterContentObserver(this); 263 } 264 mResolver.registerContentObserver( 265 Global.getUriFor(Global.DEVICE_PROVISIONED), false, this); 266 mResolver.registerContentObserver( 267 Secure.getUriFor(Secure.USER_SETUP_COMPLETE), false, this, mUserId); 268 fireZenAvailableChanged(isZenAvailable()); 269 } 270 271 @Override 272 public void onChange(boolean selfChange, Uri uri) { 273 if (Global.getUriFor(Global.DEVICE_PROVISIONED).equals(uri) 274 || Secure.getUriFor(Secure.USER_SETUP_COMPLETE).equals(uri)) { 275 fireZenAvailableChanged(isZenAvailable()); 276 } 277 } 278 } 279 } 280