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