GeofenceProxy.java revision 9158825f9c41869689d6b1786d7c7aa8bdd524ce
1/*
2 * Copyright (C) 2013 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 */
16package com.android.server.location;
17
18import android.content.ComponentName;
19import android.content.Intent;
20import android.content.ServiceConnection;
21import android.hardware.location.GeofenceHardwareService;
22import android.hardware.location.IGeofenceHardware;
23import android.location.IGeofenceProvider;
24import android.location.IGpsGeofenceHardware;
25import android.location.IFusedGeofenceHardware;
26import android.content.Context;
27import android.os.Handler;
28import android.os.IBinder;
29import android.os.Message;
30import android.os.RemoteException;
31import android.os.UserHandle;
32import android.util.Log;
33import com.android.server.ServiceWatcher;
34
35import java.util.List;
36
37/**
38 * @hide
39 */
40public final class GeofenceProxy {
41    private static final String TAG = "GeofenceProxy";
42    private static final String SERVICE_ACTION =
43            "com.android.location.service.GeofenceProvider";
44    private final ServiceWatcher mServiceWatcher;
45    private final Context mContext;
46    private final IGpsGeofenceHardware mGpsGeofenceHardware;
47    private final IFusedGeofenceHardware mFusedGeofenceHardware;
48
49    private final Object mLock = new Object();
50
51    // Access to mGeofenceHardware needs to be synchronized by mLock.
52    private IGeofenceHardware mGeofenceHardware;
53
54    private static final int GEOFENCE_PROVIDER_CONNECTED = 1;
55    private static final int GEOFENCE_HARDWARE_CONNECTED = 2;
56    private static final int GEOFENCE_HARDWARE_DISCONNECTED = 3;
57    private static final int GEOFENCE_GPS_HARDWARE_CONNECTED = 4;
58    private static final int GEOFENCE_GPS_HARDWARE_DISCONNECTED = 5;
59
60    private Runnable mRunnable = new Runnable() {
61        @Override
62        public void run() {
63            mHandler.sendEmptyMessage(GEOFENCE_PROVIDER_CONNECTED);
64        }
65    };
66
67    public static GeofenceProxy createAndBind(Context context,
68            int overlaySwitchResId, int defaultServicePackageNameResId,
69            int initialPackageNamesResId, Handler handler, IGpsGeofenceHardware gpsGeofence,
70            IFusedGeofenceHardware fusedGeofenceHardware) {
71        GeofenceProxy proxy = new GeofenceProxy(context, overlaySwitchResId,
72            defaultServicePackageNameResId, initialPackageNamesResId, handler, gpsGeofence,
73            fusedGeofenceHardware);
74        if (proxy.bindGeofenceProvider()) {
75            return proxy;
76        } else {
77            return null;
78        }
79    }
80
81    private GeofenceProxy(Context context,
82            int overlaySwitchResId, int defaultServicePackageNameResId,
83            int initialPackageNamesResId, Handler handler, IGpsGeofenceHardware gpsGeofence,
84            IFusedGeofenceHardware fusedGeofenceHardware) {
85        mContext = context;
86        mServiceWatcher = new ServiceWatcher(context, TAG, SERVICE_ACTION, overlaySwitchResId,
87            defaultServicePackageNameResId, initialPackageNamesResId, mRunnable, handler);
88        mGpsGeofenceHardware = gpsGeofence;
89        mFusedGeofenceHardware = fusedGeofenceHardware;
90        bindHardwareGeofence();
91    }
92
93    private boolean bindGeofenceProvider() {
94        return mServiceWatcher.start();
95    }
96
97    private void bindHardwareGeofence() {
98        mContext.bindServiceAsUser(new Intent(mContext, GeofenceHardwareService.class),
99                mServiceConnection, Context.BIND_AUTO_CREATE, UserHandle.OWNER);
100    }
101
102    private ServiceConnection mServiceConnection = new ServiceConnection() {
103        @Override
104        public void onServiceConnected(ComponentName name, IBinder service) {
105            synchronized (mLock) {
106                mGeofenceHardware = IGeofenceHardware.Stub.asInterface(service);
107                mHandler.sendEmptyMessage(GEOFENCE_HARDWARE_CONNECTED);
108            }
109        }
110
111        @Override
112        public void onServiceDisconnected(ComponentName name) {
113            synchronized (mLock) {
114                mGeofenceHardware = null;
115                mHandler.sendEmptyMessage(GEOFENCE_HARDWARE_DISCONNECTED);
116            }
117        }
118    };
119
120    private void setGeofenceHardwareInProviderLocked() {
121        try {
122            IGeofenceProvider provider = IGeofenceProvider.Stub.asInterface(
123                      mServiceWatcher.getBinder());
124            if (provider != null) {
125                provider.setGeofenceHardware(mGeofenceHardware);
126            }
127        } catch (RemoteException e) {
128            Log.e(TAG, "Remote Exception: setGeofenceHardwareInProviderLocked: " + e);
129        }
130    }
131
132    private void setGpsGeofenceLocked() {
133        try {
134            mGeofenceHardware.setGpsGeofenceHardware(mGpsGeofenceHardware);
135        } catch (RemoteException e) {
136            Log.e(TAG, "Error while connecting to GeofenceHardwareService");
137        }
138    }
139
140    private void setFusedGeofenceLocked() {
141        try {
142            mGeofenceHardware.setFusedGeofenceHardware(mFusedGeofenceHardware);
143        } catch(RemoteException e) {
144            Log.e(TAG, "Error while connecting to GeofenceHardwareService");
145        }
146    }
147
148    // This needs to be reworked, when more services get added,
149    // Might need a state machine or add a framework utility class,
150    private Handler mHandler = new Handler() {
151
152        @Override
153        public void handleMessage(Message msg) {
154            switch (msg.what) {
155                case GEOFENCE_PROVIDER_CONNECTED:
156                    synchronized (mLock) {
157                        if (mGeofenceHardware != null) {
158                            setGeofenceHardwareInProviderLocked();
159                        }
160                        // else: the geofence provider will be notified when the connection to
161                        // GeofenceHardwareService is established.
162                    }
163                    break;
164                case GEOFENCE_HARDWARE_CONNECTED:
165                    synchronized (mLock) {
166                        // Theoretically this won't happen because once the GeofenceHardwareService
167                        // is connected to, we won't lose connection to it because it's a system
168                        // service. But this check does make the code more robust.
169                        if (mGeofenceHardware != null) {
170                            setGpsGeofenceLocked();
171                            setFusedGeofenceLocked();
172                            setGeofenceHardwareInProviderLocked();
173                        }
174                    }
175                    break;
176                case GEOFENCE_HARDWARE_DISCONNECTED:
177                    synchronized (mLock) {
178                        if (mGeofenceHardware == null) {
179                            setGeofenceHardwareInProviderLocked();
180                        }
181                    }
182                    break;
183            }
184        }
185    };
186}
187