ConditionProviders.java revision e86de4c0670550a29edae77ebb9f5c8ba5631231
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.server.notification; 18 19import android.content.Context; 20import android.net.Uri; 21import android.os.Handler; 22import android.os.IBinder; 23import android.os.IInterface; 24import android.os.RemoteException; 25import android.provider.Settings; 26import android.provider.Settings.Global; 27import android.service.notification.Condition; 28import android.service.notification.ConditionProviderService; 29import android.service.notification.IConditionListener; 30import android.service.notification.IConditionProvider; 31import android.util.ArrayMap; 32import android.util.Slog; 33 34import com.android.internal.R; 35 36import libcore.util.Objects; 37 38import java.io.PrintWriter; 39import java.util.Arrays; 40 41public class ConditionProviders extends ManagedServices { 42 43 private final ZenModeHelper mZenModeHelper; 44 private final ArrayMap<IBinder, IConditionListener> mListeners 45 = new ArrayMap<IBinder, IConditionListener>(); 46 private final ArrayMap<Uri, ManagedServiceInfo> mConditions 47 = new ArrayMap<Uri, ManagedServiceInfo>(); 48 49 private Uri mCurrentConditionId; 50 51 public ConditionProviders(Context context, Handler handler, 52 UserProfiles userProfiles, ZenModeHelper zenModeHelper) { 53 super(context, handler, new Object(), userProfiles); 54 mZenModeHelper = zenModeHelper; 55 mZenModeHelper.addCallback(new ZenModeHelperCallback()); 56 } 57 58 @Override 59 protected Config getConfig() { 60 Config c = new Config(); 61 c.caption = "condition provider"; 62 c.serviceInterface = ConditionProviderService.SERVICE_INTERFACE; 63 c.secureSettingName = Settings.Secure.ENABLED_CONDITION_PROVIDERS; 64 c.bindPermission = android.Manifest.permission.BIND_CONDITION_PROVIDER_SERVICE; 65 c.settingsAction = Settings.ACTION_CONDITION_PROVIDER_SETTINGS; 66 c.clientLabel = R.string.condition_provider_service_binding_label; 67 return c; 68 } 69 70 @Override 71 public void dump(PrintWriter pw) { 72 super.dump(pw); 73 synchronized(mMutex) { 74 pw.print(" mCurrentConditionId="); pw.println(mCurrentConditionId); 75 pw.print(" mListeners("); pw.print(mListeners.size()); pw.println("):"); 76 for (int i = 0; i < mListeners.size(); i++) { 77 pw.print(" "); pw.println(mListeners.keyAt(i)); 78 } 79 pw.print(" mConditions("); pw.print(mConditions.size()); pw.println("):"); 80 for (int i = 0; i < mConditions.size(); i++) { 81 pw.print(" "); pw.print(mConditions.keyAt(i)); 82 final ManagedServiceInfo info = mConditions.valueAt(i); 83 pw.print(" -> "); pw.print(info.component); 84 if (!mServices.contains(info)) { 85 pw.print(" (orphan)"); 86 } 87 pw.println(); 88 } 89 } 90 } 91 92 @Override 93 protected IInterface asInterface(IBinder binder) { 94 return IConditionProvider.Stub.asInterface(binder); 95 } 96 97 @Override 98 protected void onServiceAdded(IInterface service) { 99 Slog.d(TAG, "onServiceAdded " + service); 100 final IConditionProvider provider = (IConditionProvider) service; 101 try { 102 provider.onConnected(); 103 } catch (RemoteException e) { 104 // we tried 105 } 106 } 107 108 @Override 109 protected void onServiceRemovedLocked(ManagedServiceInfo removed) { 110 if (removed == null) return; 111 if (mCurrentConditionId != null) { 112 if (removed.equals(mConditions.get(mCurrentConditionId))) { 113 mCurrentConditionId = null; 114 mZenModeHelper.setZenMode(Global.ZEN_MODE_OFF); 115 } 116 } 117 for (int i = mConditions.size() - 1; i >= 0; i--) { 118 if (removed.equals(mConditions.valueAt(i))) { 119 mConditions.removeAt(i); 120 } 121 } 122 } 123 124 public ManagedServiceInfo checkServiceToken(IConditionProvider provider) { 125 synchronized(mMutex) { 126 return checkServiceTokenLocked(provider); 127 } 128 } 129 130 public void requestZenModeConditions(IConditionListener callback, boolean requested) { 131 synchronized(mMutex) { 132 if (DEBUG) Slog.d(TAG, "requestZenModeConditions callback=" + callback 133 + " requested=" + requested); 134 if (callback == null) return; 135 if (requested) { 136 mListeners.put(callback.asBinder(), callback); 137 requestConditionsLocked(Condition.FLAG_RELEVANT_NOW); 138 } else { 139 mListeners.remove(callback.asBinder()); 140 if (mListeners.isEmpty()) { 141 requestConditionsLocked(0); 142 } 143 } 144 } 145 } 146 147 public void notifyConditions(String pkg, ManagedServiceInfo info, Condition[] conditions) { 148 synchronized(mMutex) { 149 if (DEBUG) Slog.d(TAG, "notifyConditions pkg=" + pkg + " info=" + info + " conditions=" 150 + (conditions == null ? null : Arrays.asList(conditions))); 151 if (conditions == null || conditions.length == 0) return; 152 final int N = conditions.length; 153 boolean valid = true; 154 for (int i = 0; i < N; i++) { 155 final Uri id = conditions[i].id; 156 if (!Condition.isValidId(id, pkg)) { 157 Slog.w(TAG, "Ignoring conditions from " + pkg + " for invalid id: " + id); 158 valid = false; 159 } 160 } 161 if (!valid) return; 162 163 for (int i = 0; i < N; i++) { 164 mConditions.put(conditions[i].id, info); 165 } 166 for (IConditionListener listener : mListeners.values()) { 167 try { 168 listener.onConditionsReceived(conditions); 169 } catch (RemoteException e) { 170 Slog.w(TAG, "Error sending conditions to listener " + listener, e); 171 } 172 } 173 if (mCurrentConditionId != null) { 174 for (int i = 0; i < N; i++) { 175 final Condition c = conditions[i]; 176 if (!c.id.equals(mCurrentConditionId)) continue; 177 if (c.state == Condition.STATE_TRUE || c.state == Condition.STATE_ERROR) { 178 triggerExitLocked(c.state == Condition.STATE_ERROR); 179 return; 180 } 181 } 182 } 183 } 184 } 185 186 private void triggerExitLocked(boolean error) { 187 if (error) { 188 Slog.w(TAG, "Zen mode exit condition failed"); 189 } else if (DEBUG) { 190 Slog.d(TAG, "Zen mode exit condition triggered"); 191 } 192 mZenModeHelper.setZenMode(Settings.Global.ZEN_MODE_OFF); 193 unsubscribeLocked(mCurrentConditionId); 194 mCurrentConditionId = null; 195 } 196 197 public void setZenModeCondition(Uri conditionId) { 198 synchronized(mMutex) { 199 if (DEBUG) Slog.d(TAG, "setZenModeCondition " + conditionId); 200 if (Objects.equal(mCurrentConditionId, conditionId)) return; 201 202 if (mCurrentConditionId != null) { 203 unsubscribeLocked(mCurrentConditionId); 204 } 205 if (conditionId != null) { 206 final ManagedServiceInfo info = mConditions.get(conditionId); 207 final IConditionProvider provider = provider(info); 208 if (provider == null) return; 209 try { 210 provider.onSubscribe(conditionId); 211 } catch (RemoteException e) { 212 Slog.w(TAG, "Error subscribing to " + conditionId 213 + " from " + info.component, e); 214 } 215 } 216 mCurrentConditionId = conditionId; 217 } 218 } 219 220 private void unsubscribeLocked(Uri conditionId) { 221 final ManagedServiceInfo info = mConditions.get(mCurrentConditionId); 222 final IConditionProvider provider = provider(info); 223 if (provider == null) return; 224 try { 225 provider.onUnsubscribe(conditionId); 226 } catch (RemoteException e) { 227 Slog.w(TAG, "Error unsubscribing to " + conditionId + " from " + info.component, e); 228 } 229 } 230 231 private static IConditionProvider provider(ManagedServiceInfo info) { 232 return info == null ? null : (IConditionProvider) info.service; 233 } 234 235 private void requestConditionsLocked(int flags) { 236 for (ManagedServiceInfo info : mServices) { 237 final IConditionProvider provider = provider(info); 238 if (provider == null) continue; 239 try { 240 provider.onRequestConditions(flags); 241 } catch (RemoteException e) { 242 Slog.w(TAG, "Error requesting conditions from " + info.component, e); 243 } 244 } 245 } 246 247 private class ZenModeHelperCallback extends ZenModeHelper.Callback { 248 @Override 249 void onZenModeChanged() { 250 final int mode = mZenModeHelper.getZenMode(); 251 if (mode == Global.ZEN_MODE_OFF) { 252 synchronized (mMutex) { 253 if (mCurrentConditionId != null) { 254 if (DEBUG) Slog.d(TAG, "Zen mode off, forcing unsubscribe from " 255 + mCurrentConditionId); 256 unsubscribeLocked(mCurrentConditionId); 257 mCurrentConditionId = null; 258 } 259 } 260 } 261 } 262 } 263} 264