17340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlock/*
27340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlock * Copyright (C) 2014 The Android Open Source Project
37340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlock *
47340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlock * Licensed under the Apache License, Version 2.0 (the "License");
57340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlock * you may not use this file except in compliance with the License.
67340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlock * You may obtain a copy of the License at
77340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlock *
87340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlock *      http://www.apache.org/licenses/LICENSE-2.0
97340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlock *
107340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlock * Unless required by applicable law or agreed to in writing, software
117340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlock * distributed under the License is distributed on an "AS IS" BASIS,
127340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlock * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
137340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlock * See the License for the specific language governing permissions and
147340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlock * limitations under the License.
157340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlock */
167340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlock
177340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlockpackage android.service.notification;
187340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlock
197340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlockimport android.annotation.SdkConstant;
20bf4e41747d138bf89c6c3fa5076a38334d3b45e1John Spurlockimport android.annotation.SystemApi;
217340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlockimport android.app.INotificationManager;
227340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlockimport android.app.Service;
237340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlockimport android.content.Context;
247340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlockimport android.content.Intent;
257340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlockimport android.net.Uri;
26e86de4c0670550a29edae77ebb9f5c8ba5631231John Spurlockimport android.os.Handler;
277340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlockimport android.os.IBinder;
28e86de4c0670550a29edae77ebb9f5c8ba5631231John Spurlockimport android.os.Message;
297340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlockimport android.os.ServiceManager;
307340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlockimport android.util.Log;
317340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlock
327340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlock/**
337340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlock * A service that provides conditions about boolean state.
347340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlock * <p>To extend this class, you must declare the service in your manifest file with
357340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlock * the {@link android.Manifest.permission#BIND_CONDITION_PROVIDER_SERVICE} permission
367340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlock * and include an intent filter with the {@link #SERVICE_INTERFACE} action. For example:</p>
377340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlock * <pre>
387340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlock * &lt;service android:name=".MyConditionProvider"
397340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlock *          android:label="&#64;string/service_name"
407340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlock *          android:permission="android.permission.BIND_CONDITION_PROVIDER_SERVICE">
417340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlock *     &lt;intent-filter>
427340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlock *         &lt;action android:name="android.service.notification.ConditionProviderService" />
437340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlock *     &lt;/intent-filter>
447340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlock * &lt;/service></pre>
457340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlock *
467340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlock * @hide
477340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlock */
48bf4e41747d138bf89c6c3fa5076a38334d3b45e1John Spurlock@SystemApi
497340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlockpublic abstract class ConditionProviderService extends Service {
507340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlock    private final String TAG = ConditionProviderService.class.getSimpleName()
517340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlock            + "[" + getClass().getSimpleName() + "]";
527340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlock
53e86de4c0670550a29edae77ebb9f5c8ba5631231John Spurlock    private final H mHandler = new H();
54e86de4c0670550a29edae77ebb9f5c8ba5631231John Spurlock
557340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlock    private Provider mProvider;
567340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlock    private INotificationManager mNoMan;
577340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlock
587340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlock    /**
597340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlock     * The {@link Intent} that must be declared as handled by the service.
607340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlock     */
617340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlock    @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
627340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlock    public static final String SERVICE_INTERFACE
637340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlock            = "android.service.notification.ConditionProviderService";
647340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlock
65e77bb36d48b6b8b5c3bb6a1195aca469bb237919John Spurlock    abstract public void onConnected();
66e77bb36d48b6b8b5c3bb6a1195aca469bb237919John Spurlock    abstract public void onRequestConditions(int relevance);
67e77bb36d48b6b8b5c3bb6a1195aca469bb237919John Spurlock    abstract public void onSubscribe(Uri conditionId);
68e77bb36d48b6b8b5c3bb6a1195aca469bb237919John Spurlock    abstract public void onUnsubscribe(Uri conditionId);
697340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlock
707340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlock    private final INotificationManager getNotificationInterface() {
717340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlock        if (mNoMan == null) {
727340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlock            mNoMan = INotificationManager.Stub.asInterface(
737340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlock                    ServiceManager.getService(Context.NOTIFICATION_SERVICE));
747340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlock        }
757340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlock        return mNoMan;
767340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlock    }
777340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlock
781c923a386ee4d8c31cc289f8628b8fc46bf08e86John Spurlock    public final void notifyCondition(Condition condition) {
791c923a386ee4d8c31cc289f8628b8fc46bf08e86John Spurlock        if (condition == null) return;
801c923a386ee4d8c31cc289f8628b8fc46bf08e86John Spurlock        notifyConditions(new Condition[]{ condition });
811c923a386ee4d8c31cc289f8628b8fc46bf08e86John Spurlock    }
821c923a386ee4d8c31cc289f8628b8fc46bf08e86John Spurlock
831c923a386ee4d8c31cc289f8628b8fc46bf08e86John Spurlock    public final void notifyConditions(Condition... conditions) {
841c923a386ee4d8c31cc289f8628b8fc46bf08e86John Spurlock        if (!isBound() || conditions == null) return;
857340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlock        try {
86e77bb36d48b6b8b5c3bb6a1195aca469bb237919John Spurlock            getNotificationInterface().notifyConditions(getPackageName(), mProvider, conditions);
877340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlock        } catch (android.os.RemoteException ex) {
887340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlock            Log.v(TAG, "Unable to contact notification manager", ex);
897340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlock        }
907340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlock    }
917340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlock
927340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlock    @Override
937340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlock    public IBinder onBind(Intent intent) {
947340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlock        if (mProvider == null) {
957340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlock            mProvider = new Provider();
967340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlock        }
977340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlock        return mProvider;
987340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlock    }
997340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlock
1007340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlock    private boolean isBound() {
1017340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlock        if (mProvider == null) {
1027340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlock            Log.w(TAG, "Condition provider service not yet bound.");
1037340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlock            return false;
1047340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlock        }
1057340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlock        return true;
1067340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlock    }
1077340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlock
1087340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlock    private final class Provider extends IConditionProvider.Stub {
1097340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlock        @Override
110e77bb36d48b6b8b5c3bb6a1195aca469bb237919John Spurlock        public void onConnected() {
111e86de4c0670550a29edae77ebb9f5c8ba5631231John Spurlock            mHandler.obtainMessage(H.ON_CONNECTED).sendToTarget();
1127340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlock        }
1137340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlock
1147340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlock        @Override
115e77bb36d48b6b8b5c3bb6a1195aca469bb237919John Spurlock        public void onRequestConditions(int relevance) {
116e86de4c0670550a29edae77ebb9f5c8ba5631231John Spurlock            mHandler.obtainMessage(H.ON_REQUEST_CONDITIONS, relevance, 0).sendToTarget();
1177340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlock        }
1187340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlock
1197340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlock        @Override
120e77bb36d48b6b8b5c3bb6a1195aca469bb237919John Spurlock        public void onSubscribe(Uri conditionId) {
121e86de4c0670550a29edae77ebb9f5c8ba5631231John Spurlock            mHandler.obtainMessage(H.ON_SUBSCRIBE, conditionId).sendToTarget();
1227340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlock        }
1237340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlock
1247340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlock        @Override
125e77bb36d48b6b8b5c3bb6a1195aca469bb237919John Spurlock        public void onUnsubscribe(Uri conditionId) {
126e86de4c0670550a29edae77ebb9f5c8ba5631231John Spurlock            mHandler.obtainMessage(H.ON_UNSUBSCRIBE, conditionId).sendToTarget();
127e86de4c0670550a29edae77ebb9f5c8ba5631231John Spurlock        }
128e86de4c0670550a29edae77ebb9f5c8ba5631231John Spurlock    }
129e86de4c0670550a29edae77ebb9f5c8ba5631231John Spurlock
130e86de4c0670550a29edae77ebb9f5c8ba5631231John Spurlock    private final class H extends Handler {
131e86de4c0670550a29edae77ebb9f5c8ba5631231John Spurlock        private static final int ON_CONNECTED = 1;
132e86de4c0670550a29edae77ebb9f5c8ba5631231John Spurlock        private static final int ON_REQUEST_CONDITIONS = 2;
133e86de4c0670550a29edae77ebb9f5c8ba5631231John Spurlock        private static final int ON_SUBSCRIBE = 3;
134e86de4c0670550a29edae77ebb9f5c8ba5631231John Spurlock        private static final int ON_UNSUBSCRIBE = 4;
135e86de4c0670550a29edae77ebb9f5c8ba5631231John Spurlock
136e86de4c0670550a29edae77ebb9f5c8ba5631231John Spurlock        @Override
137e86de4c0670550a29edae77ebb9f5c8ba5631231John Spurlock        public void handleMessage(Message msg) {
138e86de4c0670550a29edae77ebb9f5c8ba5631231John Spurlock            String name = null;
1397340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlock            try {
140e86de4c0670550a29edae77ebb9f5c8ba5631231John Spurlock                switch(msg.what) {
141e86de4c0670550a29edae77ebb9f5c8ba5631231John Spurlock                    case ON_CONNECTED:
142e86de4c0670550a29edae77ebb9f5c8ba5631231John Spurlock                        name = "onConnected";
143e86de4c0670550a29edae77ebb9f5c8ba5631231John Spurlock                        onConnected();
144e86de4c0670550a29edae77ebb9f5c8ba5631231John Spurlock                        break;
145e86de4c0670550a29edae77ebb9f5c8ba5631231John Spurlock                    case ON_REQUEST_CONDITIONS:
146e86de4c0670550a29edae77ebb9f5c8ba5631231John Spurlock                        name = "onRequestConditions";
147e86de4c0670550a29edae77ebb9f5c8ba5631231John Spurlock                        onRequestConditions(msg.arg1);
148e86de4c0670550a29edae77ebb9f5c8ba5631231John Spurlock                        break;
149e86de4c0670550a29edae77ebb9f5c8ba5631231John Spurlock                    case ON_SUBSCRIBE:
150e86de4c0670550a29edae77ebb9f5c8ba5631231John Spurlock                        name = "onSubscribe";
151e86de4c0670550a29edae77ebb9f5c8ba5631231John Spurlock                        onSubscribe((Uri)msg.obj);
152e86de4c0670550a29edae77ebb9f5c8ba5631231John Spurlock                        break;
153e86de4c0670550a29edae77ebb9f5c8ba5631231John Spurlock                    case ON_UNSUBSCRIBE:
154e86de4c0670550a29edae77ebb9f5c8ba5631231John Spurlock                        name = "onUnsubscribe";
155e86de4c0670550a29edae77ebb9f5c8ba5631231John Spurlock                        onUnsubscribe((Uri)msg.obj);
156e86de4c0670550a29edae77ebb9f5c8ba5631231John Spurlock                        break;
157e86de4c0670550a29edae77ebb9f5c8ba5631231John Spurlock                }
1587340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlock            } catch (Throwable t) {
159e86de4c0670550a29edae77ebb9f5c8ba5631231John Spurlock                Log.w(TAG, "Error running " + name, t);
1607340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlock            }
1617340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlock        }
1627340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlock    }
1637340fc8665ae3f9f1978f42aa0e5e1da85036158John Spurlock}
164