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