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 17package com.android.systemui.statusbar.policy; 18 19import android.app.ActivityManager; 20import android.app.AlarmManager; 21import android.app.NotificationManager; 22import android.content.BroadcastReceiver; 23import android.content.ComponentName; 24import android.content.ContentResolver; 25import android.content.Context; 26import android.content.Intent; 27import android.content.IntentFilter; 28import android.database.ContentObserver; 29import android.net.Uri; 30import android.os.Handler; 31import android.os.UserHandle; 32import android.os.UserManager; 33import android.provider.Settings.Global; 34import android.provider.Settings.Secure; 35import android.service.notification.Condition; 36import android.service.notification.IConditionListener; 37import android.service.notification.ZenModeConfig; 38import android.service.notification.ZenModeConfig.ZenRule; 39import android.util.Log; 40import android.util.Slog; 41 42import com.android.systemui.qs.GlobalSetting; 43 44import java.util.ArrayList; 45import java.util.LinkedHashMap; 46import java.util.Objects; 47 48/** Platform implementation of the zen mode controller. **/ 49public 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 void requestConditions(boolean request) { 125 mRequesting = request; 126 mNoMan.requestZenModeConditions(mListener, request ? Condition.FLAG_RELEVANT_NOW : 0); 127 if (!mRequesting) { 128 mConditions.clear(); 129 } 130 } 131 132 @Override 133 public ZenRule getManualRule() { 134 return mConfig == null ? null : mConfig.manualRule; 135 } 136 137 @Override 138 public ZenModeConfig getConfig() { 139 return mConfig; 140 } 141 142 @Override 143 public long getNextAlarm() { 144 final AlarmManager.AlarmClockInfo info = mAlarmManager.getNextAlarmClock(mUserId); 145 return info != null ? info.getTriggerTime() : 0; 146 } 147 148 @Override 149 public void setUserId(int userId) { 150 mUserId = userId; 151 if (mRegistered) { 152 mContext.unregisterReceiver(mReceiver); 153 } 154 final IntentFilter filter = new IntentFilter(AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED); 155 filter.addAction(NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED); 156 mContext.registerReceiverAsUser(mReceiver, new UserHandle(mUserId), filter, null, null); 157 mRegistered = true; 158 mSetupObserver.register(); 159 } 160 161 @Override 162 public ComponentName getEffectsSuppressor() { 163 return NotificationManager.from(mContext).getEffectsSuppressor(); 164 } 165 166 @Override 167 public boolean isCountdownConditionSupported() { 168 return NotificationManager.from(mContext) 169 .isSystemConditionProviderEnabled(ZenModeConfig.COUNTDOWN_PATH); 170 } 171 172 @Override 173 public int getCurrentUser() { 174 return ActivityManager.getCurrentUser(); 175 } 176 177 private void fireNextAlarmChanged() { 178 for (Callback cb : mCallbacks) { 179 cb.onNextAlarmChanged(); 180 } 181 } 182 183 private void fireEffectsSuppressorChanged() { 184 for (Callback cb : mCallbacks) { 185 cb.onEffectsSupressorChanged(); 186 } 187 } 188 189 private void fireZenChanged(int zen) { 190 for (Callback cb : mCallbacks) { 191 cb.onZenChanged(zen); 192 } 193 } 194 195 private void fireZenAvailableChanged(boolean available) { 196 for (Callback cb : mCallbacks) { 197 cb.onZenAvailableChanged(available); 198 } 199 } 200 201 private void fireConditionsChanged(Condition[] conditions) { 202 for (Callback cb : mCallbacks) { 203 cb.onConditionsChanged(conditions); 204 } 205 } 206 207 private void fireManualRuleChanged(ZenRule rule) { 208 for (Callback cb : mCallbacks) { 209 cb.onManualRuleChanged(rule); 210 } 211 } 212 213 private void fireConfigChanged(ZenModeConfig config) { 214 for (Callback cb : mCallbacks) { 215 cb.onConfigChanged(config); 216 } 217 } 218 219 private void updateConditions(Condition[] conditions) { 220 if (conditions == null || conditions.length == 0) return; 221 for (Condition c : conditions) { 222 if ((c.flags & Condition.FLAG_RELEVANT_NOW) == 0) continue; 223 mConditions.put(c.id, c); 224 } 225 fireConditionsChanged( 226 mConditions.values().toArray(new Condition[mConditions.values().size()])); 227 } 228 229 private void updateZenModeConfig() { 230 final ZenModeConfig config = mNoMan.getZenModeConfig(); 231 if (Objects.equals(config, mConfig)) return; 232 final ZenRule oldRule = mConfig != null ? mConfig.manualRule : null; 233 mConfig = config; 234 fireConfigChanged(config); 235 final ZenRule newRule = config != null ? config.manualRule : null; 236 if (Objects.equals(oldRule, newRule)) return; 237 fireManualRuleChanged(newRule); 238 } 239 240 private final IConditionListener mListener = new IConditionListener.Stub() { 241 @Override 242 public void onConditionsReceived(Condition[] conditions) { 243 if (DEBUG) Slog.d(TAG, "onConditionsReceived " 244 + (conditions == null ? 0 : conditions.length) + " mRequesting=" + mRequesting); 245 if (!mRequesting) return; 246 updateConditions(conditions); 247 } 248 }; 249 250 private final BroadcastReceiver mReceiver = new BroadcastReceiver() { 251 @Override 252 public void onReceive(Context context, Intent intent) { 253 if (AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED.equals(intent.getAction())) { 254 fireNextAlarmChanged(); 255 } 256 if (NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED.equals(intent.getAction())) { 257 fireEffectsSuppressorChanged(); 258 } 259 } 260 }; 261 262 private final class SetupObserver extends ContentObserver { 263 private final ContentResolver mResolver; 264 265 private boolean mRegistered; 266 267 public SetupObserver(Handler handler) { 268 super(handler); 269 mResolver = mContext.getContentResolver(); 270 } 271 272 public boolean isUserSetup() { 273 return Secure.getIntForUser(mResolver, Secure.USER_SETUP_COMPLETE, 0, mUserId) != 0; 274 } 275 276 public boolean isDeviceProvisioned() { 277 return Global.getInt(mResolver, Global.DEVICE_PROVISIONED, 0) != 0; 278 } 279 280 public void register() { 281 if (mRegistered) { 282 mResolver.unregisterContentObserver(this); 283 } 284 mResolver.registerContentObserver( 285 Global.getUriFor(Global.DEVICE_PROVISIONED), false, this); 286 mResolver.registerContentObserver( 287 Secure.getUriFor(Secure.USER_SETUP_COMPLETE), false, this, mUserId); 288 fireZenAvailableChanged(isZenAvailable()); 289 } 290 291 @Override 292 public void onChange(boolean selfChange, Uri uri) { 293 if (Global.getUriFor(Global.DEVICE_PROVISIONED).equals(uri) 294 || Secure.getUriFor(Secure.USER_SETUP_COMPLETE).equals(uri)) { 295 fireZenAvailableChanged(isZenAvailable()); 296 } 297 } 298 } 299} 300