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.SYSTEM);
     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         mServiceWatcher.runOnBinder(new ServiceWatcher.BinderRunner() {
    120             @Override
    121             public void run(IBinder binder) {
    122                 final IGeofenceProvider provider = IGeofenceProvider.Stub.asInterface(binder);
    123                 try {
    124                     provider.setGeofenceHardware(mGeofenceHardware);
    125                 } catch (RemoteException e) {
    126                     Log.e(TAG, "Remote Exception: setGeofenceHardwareInProviderLocked: " + e);
    127                 }
    128             }
    129         });
    130     }
    131 
    132     private void setGpsGeofenceLocked() {
    133         try {
    134             if (mGpsGeofenceHardware != null) {
    135                 mGeofenceHardware.setGpsGeofenceHardware(mGpsGeofenceHardware);
    136             }
    137         } catch (RemoteException e) {
    138             Log.e(TAG, "Error while connecting to GeofenceHardwareService");
    139         }
    140     }
    141 
    142     private void setFusedGeofenceLocked() {
    143         try {
    144             mGeofenceHardware.setFusedGeofenceHardware(mFusedGeofenceHardware);
    145         } catch(RemoteException e) {
    146             Log.e(TAG, "Error while connecting to GeofenceHardwareService");
    147         }
    148     }
    149 
    150     // This needs to be reworked, when more services get added,
    151     // Might need a state machine or add a framework utility class,
    152     private Handler mHandler = new Handler() {
    153 
    154         @Override
    155         public void handleMessage(Message msg) {
    156             switch (msg.what) {
    157                 case GEOFENCE_PROVIDER_CONNECTED:
    158                     synchronized (mLock) {
    159                         if (mGeofenceHardware != null) {
    160                             setGeofenceHardwareInProviderLocked();
    161                         }
    162                         // else: the geofence provider will be notified when the connection to
    163                         // GeofenceHardwareService is established.
    164                     }
    165                     break;
    166                 case GEOFENCE_HARDWARE_CONNECTED:
    167                     synchronized (mLock) {
    168                         // Theoretically this won't happen because once the GeofenceHardwareService
    169                         // is connected to, we won't lose connection to it because it's a system
    170                         // service. But this check does make the code more robust.
    171                         if (mGeofenceHardware != null) {
    172                             setGpsGeofenceLocked();
    173                             setFusedGeofenceLocked();
    174                             setGeofenceHardwareInProviderLocked();
    175                         }
    176                     }
    177                     break;
    178                 case GEOFENCE_HARDWARE_DISCONNECTED:
    179                     synchronized (mLock) {
    180                         if (mGeofenceHardware == null) {
    181                             setGeofenceHardwareInProviderLocked();
    182                         }
    183                     }
    184                     break;
    185             }
    186         }
    187     };
    188 }
    189