ConditionProviders.java revision e77bb36d48b6b8b5c3bb6a1195aca469bb237919
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.service.notification.Condition;
27import android.service.notification.ConditionProviderService;
28import android.service.notification.IConditionListener;
29import android.service.notification.IConditionProvider;
30import android.util.ArrayMap;
31import android.util.Slog;
32
33import com.android.internal.R;
34
35import libcore.util.Objects;
36
37import java.io.PrintWriter;
38import java.util.Arrays;
39
40public class ConditionProviders extends ManagedServices {
41
42    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
50    public ConditionProviders(Context context, Handler handler,
51            UserProfiles userProfiles, ZenModeHelper zenModeHelper) {
52        super(context, handler, new Object(), userProfiles);
53        mZenModeHelper = zenModeHelper;
54    }
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
69    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
91    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);
98        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        }
237    }
238}
239