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