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