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.location;
18
19import com.android.server.ServiceWatcher;
20
21import android.content.Context;
22import android.hardware.location.ActivityRecognitionHardware;
23import android.hardware.location.IActivityRecognitionHardwareClient;
24import android.hardware.location.IActivityRecognitionHardwareWatcher;
25import android.os.Handler;
26import android.os.IBinder;
27import android.os.RemoteException;
28import android.util.Log;
29
30/**
31 * Proxy class to bind GmsCore to the ActivityRecognitionHardware.
32 *
33 * @hide
34 */
35public class ActivityRecognitionProxy {
36    private static final String TAG = "ActivityRecognitionProxy";
37
38    private final ServiceWatcher mServiceWatcher;
39    private final boolean mIsSupported;
40    private final ActivityRecognitionHardware mInstance;
41
42    private ActivityRecognitionProxy(
43            Context context,
44            Handler handler,
45            boolean activityRecognitionHardwareIsSupported,
46            ActivityRecognitionHardware activityRecognitionHardware,
47            int overlaySwitchResId,
48            int defaultServicePackageNameResId,
49            int initialPackageNameResId) {
50        mIsSupported = activityRecognitionHardwareIsSupported;
51        mInstance = activityRecognitionHardware;
52
53        Runnable newServiceWork = new Runnable() {
54            @Override
55            public void run() {
56                bindProvider();
57            }
58        };
59
60        // prepare the connection to the provider
61        mServiceWatcher = new ServiceWatcher(
62                context,
63                TAG,
64                "com.android.location.service.ActivityRecognitionProvider",
65                overlaySwitchResId,
66                defaultServicePackageNameResId,
67                initialPackageNameResId,
68                newServiceWork,
69                handler);
70    }
71
72    /**
73     * Creates an instance of the proxy and binds it to the appropriate FusedProvider.
74     *
75     * @return An instance of the proxy if it could be bound, null otherwise.
76     */
77    public static ActivityRecognitionProxy createAndBind(
78            Context context,
79            Handler handler,
80            boolean activityRecognitionHardwareIsSupported,
81            ActivityRecognitionHardware activityRecognitionHardware,
82            int overlaySwitchResId,
83            int defaultServicePackageNameResId,
84            int initialPackageNameResId) {
85        ActivityRecognitionProxy activityRecognitionProxy = new ActivityRecognitionProxy(
86                context,
87                handler,
88                activityRecognitionHardwareIsSupported,
89                activityRecognitionHardware,
90                overlaySwitchResId,
91                defaultServicePackageNameResId,
92                initialPackageNameResId);
93
94        // try to bind the provider
95        if (!activityRecognitionProxy.mServiceWatcher.start()) {
96            Log.e(TAG, "ServiceWatcher could not start.");
97            return null;
98        }
99        return activityRecognitionProxy;
100    }
101
102    /**
103     * Helper function to bind the FusedLocationHardware to the appropriate FusedProvider instance.
104     */
105    private void bindProvider() {
106        IBinder binder = mServiceWatcher.getBinder();
107        if (binder == null) {
108            Log.e(TAG, "Null binder found on connection.");
109            return;
110        }
111        String descriptor;
112        try {
113            descriptor = binder.getInterfaceDescriptor();
114        } catch (RemoteException e) {
115            Log.e(TAG, "Unable to get interface descriptor.", e);
116            return;
117        }
118
119        if (IActivityRecognitionHardwareWatcher.class.getCanonicalName().equals(descriptor)) {
120            IActivityRecognitionHardwareWatcher watcher =
121                    IActivityRecognitionHardwareWatcher.Stub.asInterface(binder);
122            if (watcher == null) {
123                Log.e(TAG, "No watcher found on connection.");
124                return;
125            }
126            if (mInstance == null) {
127                // to keep backwards compatibility do not update the watcher when there is no
128                // instance available, or it will cause an NPE
129                Log.d(TAG, "AR HW instance not available, binding will be a no-op.");
130                return;
131            }
132            try {
133                watcher.onInstanceChanged(mInstance);
134            } catch (RemoteException e) {
135                Log.e(TAG, "Error delivering hardware interface to watcher.", e);
136            }
137        } else if (IActivityRecognitionHardwareClient.class.getCanonicalName().equals(descriptor)) {
138            IActivityRecognitionHardwareClient client =
139                    IActivityRecognitionHardwareClient.Stub.asInterface(binder);
140            if (client == null) {
141                Log.e(TAG, "No client found on connection.");
142                return;
143            }
144            try {
145                client.onAvailabilityChanged(mIsSupported, mInstance);
146            } catch (RemoteException e) {
147                Log.e(TAG, "Error delivering hardware interface to client.", e);
148            }
149        } else {
150            Log.e(TAG, "Invalid descriptor found on connection: " + descriptor);
151        }
152    }
153}
154