18ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh/*
28ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh * Copyright (C) 2013 The Android Open Source Project
38ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh *
48ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh * Licensed under the Apache License, Version 2.0 (the "License");
58ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh * you may not use this file except in compliance with the License.
68ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh * You may obtain a copy of the License at
78ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh *
88ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh *      http://www.apache.org/licenses/LICENSE-2.0
98ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh *
108ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh * Unless required by applicable law or agreed to in writing, software
118ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh * distributed under the License is distributed on an "AS IS" BASIS,
128ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
138ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh * See the License for the specific language governing permissions and
148ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh * limitations under the License.
158ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh */
168ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganeshpackage com.android.server.location;
178ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh
188ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganeshimport android.content.ComponentName;
198ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganeshimport android.content.Intent;
208ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganeshimport android.content.ServiceConnection;
218ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganeshimport android.hardware.location.GeofenceHardwareService;
228ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganeshimport android.hardware.location.IGeofenceHardware;
238ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganeshimport android.location.IGeofenceProvider;
248ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganeshimport android.location.IGpsGeofenceHardware;
250682809ad08db284d7110aab44108d5e9c310e6bdestradaaimport android.location.IFusedGeofenceHardware;
268ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganeshimport android.content.Context;
278ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganeshimport android.os.Handler;
288ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganeshimport android.os.IBinder;
298ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganeshimport android.os.Message;
308ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganeshimport android.os.RemoteException;
318ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganeshimport android.os.UserHandle;
328ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganeshimport android.util.Log;
338ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganeshimport com.android.server.ServiceWatcher;
348ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh
358ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh/**
368ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh * @hide
378ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh */
388ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganeshpublic final class GeofenceProxy {
398ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    private static final String TAG = "GeofenceProxy";
408ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    private static final String SERVICE_ACTION =
418ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh            "com.android.location.service.GeofenceProvider";
42d535ead295abf3b74afb6450c83bd197f69c5a26Zhentao Sun    private final ServiceWatcher mServiceWatcher;
43d535ead295abf3b74afb6450c83bd197f69c5a26Zhentao Sun    private final Context mContext;
44d535ead295abf3b74afb6450c83bd197f69c5a26Zhentao Sun    private final IGpsGeofenceHardware mGpsGeofenceHardware;
45d535ead295abf3b74afb6450c83bd197f69c5a26Zhentao Sun    private final IFusedGeofenceHardware mFusedGeofenceHardware;
46d535ead295abf3b74afb6450c83bd197f69c5a26Zhentao Sun
47d535ead295abf3b74afb6450c83bd197f69c5a26Zhentao Sun    private final Object mLock = new Object();
48d535ead295abf3b74afb6450c83bd197f69c5a26Zhentao Sun
49d535ead295abf3b74afb6450c83bd197f69c5a26Zhentao Sun    // Access to mGeofenceHardware needs to be synchronized by mLock.
508ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    private IGeofenceHardware mGeofenceHardware;
518ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh
528ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    private static final int GEOFENCE_PROVIDER_CONNECTED = 1;
538ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    private static final int GEOFENCE_HARDWARE_CONNECTED = 2;
548ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    private static final int GEOFENCE_HARDWARE_DISCONNECTED = 3;
558ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    private static final int GEOFENCE_GPS_HARDWARE_CONNECTED = 4;
568ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    private static final int GEOFENCE_GPS_HARDWARE_DISCONNECTED = 5;
578ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh
588ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    private Runnable mRunnable = new Runnable() {
598ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        @Override
608ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        public void run() {
618ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh            mHandler.sendEmptyMessage(GEOFENCE_PROVIDER_CONNECTED);
628ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        }
638ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    };
648ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh
658ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    public static GeofenceProxy createAndBind(Context context,
66c5fc9988f11acc58229fb6ae80d346277318ada4Zhentao Sun            int overlaySwitchResId, int defaultServicePackageNameResId,
670682809ad08db284d7110aab44108d5e9c310e6bdestradaa            int initialPackageNamesResId, Handler handler, IGpsGeofenceHardware gpsGeofence,
680682809ad08db284d7110aab44108d5e9c310e6bdestradaa            IFusedGeofenceHardware fusedGeofenceHardware) {
69c5fc9988f11acc58229fb6ae80d346277318ada4Zhentao Sun        GeofenceProxy proxy = new GeofenceProxy(context, overlaySwitchResId,
700682809ad08db284d7110aab44108d5e9c310e6bdestradaa            defaultServicePackageNameResId, initialPackageNamesResId, handler, gpsGeofence,
710682809ad08db284d7110aab44108d5e9c310e6bdestradaa            fusedGeofenceHardware);
728ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        if (proxy.bindGeofenceProvider()) {
738ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh            return proxy;
748ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        } else {
758ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh            return null;
768ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        }
778ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    }
788ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh
79c5fc9988f11acc58229fb6ae80d346277318ada4Zhentao Sun    private GeofenceProxy(Context context,
80c5fc9988f11acc58229fb6ae80d346277318ada4Zhentao Sun            int overlaySwitchResId, int defaultServicePackageNameResId,
810682809ad08db284d7110aab44108d5e9c310e6bdestradaa            int initialPackageNamesResId, Handler handler, IGpsGeofenceHardware gpsGeofence,
820682809ad08db284d7110aab44108d5e9c310e6bdestradaa            IFusedGeofenceHardware fusedGeofenceHardware) {
838ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        mContext = context;
84c5fc9988f11acc58229fb6ae80d346277318ada4Zhentao Sun        mServiceWatcher = new ServiceWatcher(context, TAG, SERVICE_ACTION, overlaySwitchResId,
85c5fc9988f11acc58229fb6ae80d346277318ada4Zhentao Sun            defaultServicePackageNameResId, initialPackageNamesResId, mRunnable, handler);
868ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        mGpsGeofenceHardware = gpsGeofence;
870682809ad08db284d7110aab44108d5e9c310e6bdestradaa        mFusedGeofenceHardware = fusedGeofenceHardware;
888ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        bindHardwareGeofence();
898ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    }
908ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh
918ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    private boolean bindGeofenceProvider() {
928ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        return mServiceWatcher.start();
938ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    }
948ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh
958ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    private void bindHardwareGeofence() {
968ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        mContext.bindServiceAsUser(new Intent(mContext, GeofenceHardwareService.class),
978ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                mServiceConnection, Context.BIND_AUTO_CREATE, UserHandle.OWNER);
988ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    }
998ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh
1008ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    private ServiceConnection mServiceConnection = new ServiceConnection() {
1018ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        @Override
1028ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        public void onServiceConnected(ComponentName name, IBinder service) {
103d535ead295abf3b74afb6450c83bd197f69c5a26Zhentao Sun            synchronized (mLock) {
104d535ead295abf3b74afb6450c83bd197f69c5a26Zhentao Sun                mGeofenceHardware = IGeofenceHardware.Stub.asInterface(service);
105d535ead295abf3b74afb6450c83bd197f69c5a26Zhentao Sun                mHandler.sendEmptyMessage(GEOFENCE_HARDWARE_CONNECTED);
106d535ead295abf3b74afb6450c83bd197f69c5a26Zhentao Sun            }
1078ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        }
1088ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh
1098ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        @Override
1108ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        public void onServiceDisconnected(ComponentName name) {
111d535ead295abf3b74afb6450c83bd197f69c5a26Zhentao Sun            synchronized (mLock) {
112d535ead295abf3b74afb6450c83bd197f69c5a26Zhentao Sun                mGeofenceHardware = null;
113d535ead295abf3b74afb6450c83bd197f69c5a26Zhentao Sun                mHandler.sendEmptyMessage(GEOFENCE_HARDWARE_DISCONNECTED);
114d535ead295abf3b74afb6450c83bd197f69c5a26Zhentao Sun            }
1158ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        }
1168ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    };
1178ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh
118d535ead295abf3b74afb6450c83bd197f69c5a26Zhentao Sun    private void setGeofenceHardwareInProviderLocked() {
1198ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        try {
120d535ead295abf3b74afb6450c83bd197f69c5a26Zhentao Sun            IGeofenceProvider provider = IGeofenceProvider.Stub.asInterface(
121d535ead295abf3b74afb6450c83bd197f69c5a26Zhentao Sun                      mServiceWatcher.getBinder());
122d535ead295abf3b74afb6450c83bd197f69c5a26Zhentao Sun            if (provider != null) {
123d535ead295abf3b74afb6450c83bd197f69c5a26Zhentao Sun                provider.setGeofenceHardware(mGeofenceHardware);
124d535ead295abf3b74afb6450c83bd197f69c5a26Zhentao Sun            }
1258ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        } catch (RemoteException e) {
126d535ead295abf3b74afb6450c83bd197f69c5a26Zhentao Sun            Log.e(TAG, "Remote Exception: setGeofenceHardwareInProviderLocked: " + e);
1278ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        }
1288ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    }
1298ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh
130d535ead295abf3b74afb6450c83bd197f69c5a26Zhentao Sun    private void setGpsGeofenceLocked() {
1318ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        try {
1325241a4cb55b4015549242ac7d8aa5c99e5f157e5Wei Liu            if (mGpsGeofenceHardware != null) {
1335241a4cb55b4015549242ac7d8aa5c99e5f157e5Wei Liu                mGeofenceHardware.setGpsGeofenceHardware(mGpsGeofenceHardware);
1345241a4cb55b4015549242ac7d8aa5c99e5f157e5Wei Liu            }
1358ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        } catch (RemoteException e) {
1368ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh            Log.e(TAG, "Error while connecting to GeofenceHardwareService");
1378ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        }
1388ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    }
1398ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh
140d535ead295abf3b74afb6450c83bd197f69c5a26Zhentao Sun    private void setFusedGeofenceLocked() {
1410682809ad08db284d7110aab44108d5e9c310e6bdestradaa        try {
1420682809ad08db284d7110aab44108d5e9c310e6bdestradaa            mGeofenceHardware.setFusedGeofenceHardware(mFusedGeofenceHardware);
1430682809ad08db284d7110aab44108d5e9c310e6bdestradaa        } catch(RemoteException e) {
1440682809ad08db284d7110aab44108d5e9c310e6bdestradaa            Log.e(TAG, "Error while connecting to GeofenceHardwareService");
1450682809ad08db284d7110aab44108d5e9c310e6bdestradaa        }
1460682809ad08db284d7110aab44108d5e9c310e6bdestradaa    }
1478ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh
1488ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    // This needs to be reworked, when more services get added,
1498ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    // Might need a state machine or add a framework utility class,
1508ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    private Handler mHandler = new Handler() {
1518ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh
1528ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        @Override
1538ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        public void handleMessage(Message msg) {
1548ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh            switch (msg.what) {
1558ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                case GEOFENCE_PROVIDER_CONNECTED:
156d535ead295abf3b74afb6450c83bd197f69c5a26Zhentao Sun                    synchronized (mLock) {
157d535ead295abf3b74afb6450c83bd197f69c5a26Zhentao Sun                        if (mGeofenceHardware != null) {
158d535ead295abf3b74afb6450c83bd197f69c5a26Zhentao Sun                            setGeofenceHardwareInProviderLocked();
159d535ead295abf3b74afb6450c83bd197f69c5a26Zhentao Sun                        }
160d535ead295abf3b74afb6450c83bd197f69c5a26Zhentao Sun                        // else: the geofence provider will be notified when the connection to
161d535ead295abf3b74afb6450c83bd197f69c5a26Zhentao Sun                        // GeofenceHardwareService is established.
1628ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                    }
1638ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                    break;
1648ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                case GEOFENCE_HARDWARE_CONNECTED:
165d535ead295abf3b74afb6450c83bd197f69c5a26Zhentao Sun                    synchronized (mLock) {
166d535ead295abf3b74afb6450c83bd197f69c5a26Zhentao Sun                        // Theoretically this won't happen because once the GeofenceHardwareService
167d535ead295abf3b74afb6450c83bd197f69c5a26Zhentao Sun                        // is connected to, we won't lose connection to it because it's a system
168d535ead295abf3b74afb6450c83bd197f69c5a26Zhentao Sun                        // service. But this check does make the code more robust.
169d535ead295abf3b74afb6450c83bd197f69c5a26Zhentao Sun                        if (mGeofenceHardware != null) {
170d535ead295abf3b74afb6450c83bd197f69c5a26Zhentao Sun                            setGpsGeofenceLocked();
171d535ead295abf3b74afb6450c83bd197f69c5a26Zhentao Sun                            setFusedGeofenceLocked();
172d535ead295abf3b74afb6450c83bd197f69c5a26Zhentao Sun                            setGeofenceHardwareInProviderLocked();
173d535ead295abf3b74afb6450c83bd197f69c5a26Zhentao Sun                        }
1748ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                    }
1758ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                    break;
1768ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                case GEOFENCE_HARDWARE_DISCONNECTED:
177d535ead295abf3b74afb6450c83bd197f69c5a26Zhentao Sun                    synchronized (mLock) {
178d535ead295abf3b74afb6450c83bd197f69c5a26Zhentao Sun                        if (mGeofenceHardware == null) {
179d535ead295abf3b74afb6450c83bd197f69c5a26Zhentao Sun                            setGeofenceHardwareInProviderLocked();
180d535ead295abf3b74afb6450c83bd197f69c5a26Zhentao Sun                        }
181d535ead295abf3b74afb6450c83bd197f69c5a26Zhentao Sun                    }
1828ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                    break;
1838ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh            }
1848ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        }
1858ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    };
1868ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh}
187