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.AlarmManager; 20import android.app.INotificationManager; 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.RemoteException; 32import android.os.ServiceManager; 33import android.os.UserHandle; 34import android.provider.Settings.Global; 35import android.provider.Settings.Secure; 36import android.service.notification.Condition; 37import android.service.notification.IConditionListener; 38import android.service.notification.ZenModeConfig; 39import android.util.Log; 40import android.util.Slog; 41 42import com.android.systemui.qs.GlobalSetting; 43 44import java.util.ArrayList; 45import java.util.LinkedHashMap; 46 47/** Platform implementation of the zen mode controller. **/ 48public 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 final IntentFilter filter = new IntentFilter(AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED); 161 filter.addAction(NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED); 162 mContext.registerReceiverAsUser(mReceiver, new UserHandle(mUserId), filter, null, null); 163 mRegistered = true; 164 mSetupObserver.register(); 165 } 166 167 @Override 168 public ComponentName getEffectsSuppressor() { 169 return NotificationManager.from(mContext).getEffectsSuppressor(); 170 } 171 172 private void fireNextAlarmChanged() { 173 for (Callback cb : mCallbacks) { 174 cb.onNextAlarmChanged(); 175 } 176 } 177 178 private void fireEffectsSuppressorChanged() { 179 for (Callback cb : mCallbacks) { 180 cb.onEffectsSupressorChanged(); 181 } 182 } 183 184 private void fireZenChanged(int zen) { 185 for (Callback cb : mCallbacks) { 186 cb.onZenChanged(zen); 187 } 188 } 189 190 private void fireZenAvailableChanged(boolean available) { 191 for (Callback cb : mCallbacks) { 192 cb.onZenAvailableChanged(available); 193 } 194 } 195 196 private void fireConditionsChanged(Condition[] conditions) { 197 for (Callback cb : mCallbacks) { 198 cb.onConditionsChanged(conditions); 199 } 200 } 201 202 private void fireExitConditionChanged() { 203 final Condition exitCondition = getExitCondition(); 204 if (DEBUG) Slog.d(TAG, "exitCondition changed: " + exitCondition); 205 for (Callback cb : mCallbacks) { 206 cb.onExitConditionChanged(exitCondition); 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 final IConditionListener mListener = new IConditionListener.Stub() { 221 @Override 222 public void onConditionsReceived(Condition[] conditions) { 223 if (DEBUG) Slog.d(TAG, "onConditionsReceived " 224 + (conditions == null ? 0 : conditions.length) + " mRequesting=" + mRequesting); 225 if (!mRequesting) return; 226 updateConditions(conditions); 227 } 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