ConditionProviderService.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 android.service.notification;
18
19import android.annotation.SdkConstant;
20import android.app.INotificationManager;
21import android.app.Service;
22import android.content.Context;
23import android.content.Intent;
24import android.net.Uri;
25import android.os.Handler;
26import android.os.IBinder;
27import android.os.Message;
28import android.os.ServiceManager;
29import android.util.Log;
30
31/**
32 * A service that provides conditions about boolean state.
33 * <p>To extend this class, you must declare the service in your manifest file with
34 * the {@link android.Manifest.permission#BIND_CONDITION_PROVIDER_SERVICE} permission
35 * and include an intent filter with the {@link #SERVICE_INTERFACE} action. For example:</p>
36 * <pre>
37 * &lt;service android:name=".MyConditionProvider"
38 *          android:label="&#64;string/service_name"
39 *          android:permission="android.permission.BIND_CONDITION_PROVIDER_SERVICE">
40 *     &lt;intent-filter>
41 *         &lt;action android:name="android.service.notification.ConditionProviderService" />
42 *     &lt;/intent-filter>
43 * &lt;/service></pre>
44 *
45 * @hide
46 */
47public abstract class ConditionProviderService extends Service {
48    private final String TAG = ConditionProviderService.class.getSimpleName()
49            + "[" + getClass().getSimpleName() + "]";
50
51    private final H mHandler = new H();
52
53    private Provider mProvider;
54    private INotificationManager mNoMan;
55
56    /**
57     * The {@link Intent} that must be declared as handled by the service.
58     */
59    @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
60    public static final String SERVICE_INTERFACE
61            = "android.service.notification.ConditionProviderService";
62
63    abstract public void onConnected();
64    abstract public void onRequestConditions(int relevance);
65    abstract public void onSubscribe(Uri conditionId);
66    abstract public void onUnsubscribe(Uri conditionId);
67
68    private final INotificationManager getNotificationInterface() {
69        if (mNoMan == null) {
70            mNoMan = INotificationManager.Stub.asInterface(
71                    ServiceManager.getService(Context.NOTIFICATION_SERVICE));
72        }
73        return mNoMan;
74    }
75
76    public final void notifyCondition(Condition condition) {
77        if (condition == null) return;
78        notifyConditions(new Condition[]{ condition });
79    }
80
81    public final void notifyConditions(Condition... conditions) {
82        if (!isBound() || conditions == null) return;
83        try {
84            getNotificationInterface().notifyConditions(getPackageName(), mProvider, conditions);
85        } catch (android.os.RemoteException ex) {
86            Log.v(TAG, "Unable to contact notification manager", ex);
87        }
88    }
89
90    @Override
91    public IBinder onBind(Intent intent) {
92        if (mProvider == null) {
93            mProvider = new Provider();
94        }
95        return mProvider;
96    }
97
98    private boolean isBound() {
99        if (mProvider == null) {
100            Log.w(TAG, "Condition provider service not yet bound.");
101            return false;
102        }
103        return true;
104    }
105
106    private final class Provider extends IConditionProvider.Stub {
107        @Override
108        public void onConnected() {
109            mHandler.obtainMessage(H.ON_CONNECTED).sendToTarget();
110        }
111
112        @Override
113        public void onRequestConditions(int relevance) {
114            mHandler.obtainMessage(H.ON_REQUEST_CONDITIONS, relevance, 0).sendToTarget();
115        }
116
117        @Override
118        public void onSubscribe(Uri conditionId) {
119            mHandler.obtainMessage(H.ON_SUBSCRIBE, conditionId).sendToTarget();
120        }
121
122        @Override
123        public void onUnsubscribe(Uri conditionId) {
124            mHandler.obtainMessage(H.ON_UNSUBSCRIBE, conditionId).sendToTarget();
125        }
126    }
127
128    private final class H extends Handler {
129        private static final int ON_CONNECTED = 1;
130        private static final int ON_REQUEST_CONDITIONS = 2;
131        private static final int ON_SUBSCRIBE = 3;
132        private static final int ON_UNSUBSCRIBE = 4;
133
134        @Override
135        public void handleMessage(Message msg) {
136            String name = null;
137            try {
138                switch(msg.what) {
139                    case ON_CONNECTED:
140                        name = "onConnected";
141                        onConnected();
142                        break;
143                    case ON_REQUEST_CONDITIONS:
144                        name = "onRequestConditions";
145                        onRequestConditions(msg.arg1);
146                        break;
147                    case ON_SUBSCRIBE:
148                        name = "onSubscribe";
149                        onSubscribe((Uri)msg.obj);
150                        break;
151                    case ON_UNSUBSCRIBE:
152                        name = "onUnsubscribe";
153                        onUnsubscribe((Uri)msg.obj);
154                        break;
155                }
156            } catch (Throwable t) {
157                Log.w(TAG, "Error running " + name, t);
158            }
159        }
160    }
161}
162