ConditionProviders.java revision 1c923a386ee4d8c31cc289f8628b8fc46bf08e86
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 for (int i = mConditions.size() - 1; i >= 0; i--) { 112 if (removed.equals(mConditions.valueAt(i))) { 113 mConditions.removeAt(i); 114 } 115 } 116 } 117 118 public ManagedServiceInfo checkServiceToken(IConditionProvider provider) { 119 synchronized(mMutex) { 120 return checkServiceTokenLocked(provider); 121 } 122 } 123 124 public void requestZenModeConditions(IConditionListener callback, boolean requested) { 125 synchronized(mMutex) { 126 if (DEBUG) Slog.d(TAG, "requestZenModeConditions callback=" + callback 127 + " requested=" + requested); 128 if (callback == null) return; 129 if (requested) { 130 mListeners.put(callback.asBinder(), callback); 131 requestConditionsLocked(Condition.FLAG_RELEVANT_NOW); 132 } else { 133 mListeners.remove(callback.asBinder()); 134 if (mListeners.isEmpty()) { 135 requestConditionsLocked(0); 136 } 137 } 138 } 139 } 140 141 public void notifyConditions(String pkg, ManagedServiceInfo info, Condition[] conditions) { 142 synchronized(mMutex) { 143 if (DEBUG) Slog.d(TAG, "notifyConditions pkg=" + pkg + " info=" + info + " conditions=" 144 + (conditions == null ? null : Arrays.asList(conditions))); 145 if (conditions == null || conditions.length == 0) return; 146 final int N = conditions.length; 147 boolean valid = true; 148 for (int i = 0; i < N; i++) { 149 final Uri id = conditions[i].id; 150 if (!Condition.isValidId(id, pkg)) { 151 Slog.w(TAG, "Ignoring conditions from " + pkg + " for invalid id: " + id); 152 valid = false; 153 } 154 } 155 if (!valid) return; 156 157 for (int i = 0; i < N; i++) { 158 mConditions.put(conditions[i].id, info); 159 } 160 for (IConditionListener listener : mListeners.values()) { 161 try { 162 listener.onConditionsReceived(conditions); 163 } catch (RemoteException e) { 164 Slog.w(TAG, "Error sending conditions to listener " + listener, e); 165 } 166 } 167 if (mCurrentConditionId != null) { 168 for (int i = 0; i < N; i++) { 169 final Condition c = conditions[i]; 170 if (!c.id.equals(mCurrentConditionId)) continue; 171 if (c.state == Condition.STATE_TRUE || c.state == Condition.STATE_ERROR) { 172 triggerExitLocked(c.state == Condition.STATE_ERROR); 173 return; 174 } 175 } 176 } 177 } 178 } 179 180 private void triggerExitLocked(boolean error) { 181 if (error) { 182 Slog.w(TAG, "Zen mode exit condition failed"); 183 } else if (DEBUG) { 184 Slog.d(TAG, "Zen mode exit condition triggered"); 185 } 186 mZenModeHelper.setZenMode(Settings.Global.ZEN_MODE_OFF); 187 unsubscribeLocked(mCurrentConditionId); 188 mCurrentConditionId = null; 189 } 190 191 public void setZenModeCondition(Uri conditionId) { 192 synchronized(mMutex) { 193 if (DEBUG) Slog.d(TAG, "setZenModeCondition " + conditionId); 194 if (Objects.equal(mCurrentConditionId, conditionId)) return; 195 196 if (mCurrentConditionId != null) { 197 unsubscribeLocked(mCurrentConditionId); 198 } 199 if (conditionId != null) { 200 final ManagedServiceInfo info = mConditions.get(conditionId); 201 final IConditionProvider provider = provider(info); 202 if (provider == null) return; 203 try { 204 provider.onSubscribe(conditionId); 205 } catch (RemoteException e) { 206 Slog.w(TAG, "Error subscribing to " + conditionId 207 + " from " + info.component, e); 208 } 209 } 210 mCurrentConditionId = conditionId; 211 } 212 } 213 214 private void unsubscribeLocked(Uri conditionId) { 215 final ManagedServiceInfo info = mConditions.get(mCurrentConditionId); 216 final IConditionProvider provider = provider(info); 217 if (provider == null) return; 218 try { 219 provider.onUnsubscribe(conditionId); 220 } catch (RemoteException e) { 221 Slog.w(TAG, "Error unsubscribing to " + conditionId + " from " + info.component, e); 222 } 223 } 224 225 private static IConditionProvider provider(ManagedServiceInfo info) { 226 return info == null ? null : (IConditionProvider) info.service; 227 } 228 229 private void requestConditionsLocked(int flags) { 230 for (ManagedServiceInfo info : mServices) { 231 final IConditionProvider provider = provider(info); 232 if (provider == null) continue; 233 try { 234 provider.onRequestConditions(flags); 235 } catch (RemoteException e) { 236 Slog.w(TAG, "Error requesting conditions from " + info.component, e); 237 } 238 } 239 } 240 241 private class ZenModeHelperCallback extends ZenModeHelper.Callback { 242 @Override 243 void onZenModeChanged() { 244 final int mode = mZenModeHelper.getZenMode(); 245 if (mode == Global.ZEN_MODE_OFF) { 246 synchronized (mMutex) { 247 if (mCurrentConditionId != null) { 248 if (DEBUG) Slog.d(TAG, "Zen mode off, forcing unsubscribe from " 249 + mCurrentConditionId); 250 unsubscribeLocked(mCurrentConditionId); 251 mCurrentConditionId = null; 252 } 253 } 254 } 255 } 256 } 257} 258