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;
258ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganeshimport android.content.Context;
268ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganeshimport android.os.Handler;
278ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganeshimport android.os.IBinder;
288ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganeshimport android.os.Message;
298ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganeshimport android.os.RemoteException;
308ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganeshimport android.os.UserHandle;
318ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganeshimport android.util.Log;
328ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganeshimport com.android.server.ServiceWatcher;
338ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh
348ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganeshimport java.util.List;
358ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh
368ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh/**
378ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh * @hide
388ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh */
398ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganeshpublic final class GeofenceProxy {
408ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    private static final String TAG = "GeofenceProxy";
418ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    private static final String SERVICE_ACTION =
428ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh            "com.android.location.service.GeofenceProvider";
438ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    private ServiceWatcher mServiceWatcher;
448ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    private Context mContext;
458ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    private IGeofenceHardware mGeofenceHardware;
468ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    private IGpsGeofenceHardware mGpsGeofenceHardware;
478ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh
488ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    private static final int GEOFENCE_PROVIDER_CONNECTED = 1;
498ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    private static final int GEOFENCE_HARDWARE_CONNECTED = 2;
508ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    private static final int GEOFENCE_HARDWARE_DISCONNECTED = 3;
518ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    private static final int GEOFENCE_GPS_HARDWARE_CONNECTED = 4;
528ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    private static final int GEOFENCE_GPS_HARDWARE_DISCONNECTED = 5;
538ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh
548ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    private Runnable mRunnable = new Runnable() {
558ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        @Override
568ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        public void run() {
578ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh            mHandler.sendEmptyMessage(GEOFENCE_PROVIDER_CONNECTED);
588ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        }
598ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    };
608ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh
618ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    public static GeofenceProxy createAndBind(Context context,
62c5fc9988f11acc58229fb6ae80d346277318ada4Zhentao Sun            int overlaySwitchResId, int defaultServicePackageNameResId,
63c5fc9988f11acc58229fb6ae80d346277318ada4Zhentao Sun            int initialPackageNamesResId, Handler handler, IGpsGeofenceHardware gpsGeofence) {
64c5fc9988f11acc58229fb6ae80d346277318ada4Zhentao Sun        GeofenceProxy proxy = new GeofenceProxy(context, overlaySwitchResId,
65c5fc9988f11acc58229fb6ae80d346277318ada4Zhentao Sun            defaultServicePackageNameResId, initialPackageNamesResId, handler, gpsGeofence);
668ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        if (proxy.bindGeofenceProvider()) {
678ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh            return proxy;
688ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        } else {
698ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh            return null;
708ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        }
718ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    }
728ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh
73c5fc9988f11acc58229fb6ae80d346277318ada4Zhentao Sun    private GeofenceProxy(Context context,
74c5fc9988f11acc58229fb6ae80d346277318ada4Zhentao Sun            int overlaySwitchResId, int defaultServicePackageNameResId,
75c5fc9988f11acc58229fb6ae80d346277318ada4Zhentao Sun            int initialPackageNamesResId, Handler handler, IGpsGeofenceHardware gpsGeofence) {
768ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        mContext = context;
77c5fc9988f11acc58229fb6ae80d346277318ada4Zhentao Sun        mServiceWatcher = new ServiceWatcher(context, TAG, SERVICE_ACTION, overlaySwitchResId,
78c5fc9988f11acc58229fb6ae80d346277318ada4Zhentao Sun            defaultServicePackageNameResId, initialPackageNamesResId, mRunnable, handler);
798ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        mGpsGeofenceHardware = gpsGeofence;
808ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        bindHardwareGeofence();
818ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    }
828ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh
838ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    private boolean bindGeofenceProvider() {
848ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        return mServiceWatcher.start();
858ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    }
868ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh
878ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    private IGeofenceProvider getGeofenceProviderService() {
888ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        return IGeofenceProvider.Stub.asInterface(mServiceWatcher.getBinder());
898ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    }
908ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh
918ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    private void bindHardwareGeofence() {
928ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        mContext.bindServiceAsUser(new Intent(mContext, GeofenceHardwareService.class),
938ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                mServiceConnection, Context.BIND_AUTO_CREATE, UserHandle.OWNER);
948ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    }
958ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh
968ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    private ServiceConnection mServiceConnection = new ServiceConnection() {
978ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        @Override
988ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        public void onServiceConnected(ComponentName name, IBinder service) {
998ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh            mGeofenceHardware = IGeofenceHardware.Stub.asInterface(service);
1008ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh            mHandler.sendEmptyMessage(GEOFENCE_HARDWARE_CONNECTED);
1018ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        }
1028ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh
1038ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        @Override
1048ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        public void onServiceDisconnected(ComponentName name) {
1058ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh            mGeofenceHardware = null;
1068ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh            mHandler.sendEmptyMessage(GEOFENCE_HARDWARE_DISCONNECTED);
1078ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        }
1088ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    };
1098ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh
1108ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    private void setGeofenceHardwareInProvider() {
1118ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        try {
1128ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh            getGeofenceProviderService().setGeofenceHardware(mGeofenceHardware);
1138ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        } catch (RemoteException e) {
1148ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh            Log.e(TAG, "Remote Exception: setGeofenceHardwareInProvider: " + e);
1158ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        }
1168ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    }
1178ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh
1188ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    private void setGpsGeofence() {
1198ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        try {
1208ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh            mGeofenceHardware.setGpsGeofenceHardware(mGpsGeofenceHardware);
1218ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        } catch (RemoteException e) {
1228ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh            Log.e(TAG, "Error while connecting to GeofenceHardwareService");
1238ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        }
1248ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    }
1258ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh
1268ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh
1278ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    // This needs to be reworked, when more services get added,
1288ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    // Might need a state machine or add a framework utility class,
1298ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    private Handler mHandler = new Handler() {
1308ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        private boolean mGeofenceHardwareConnected = false;
1318ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        private boolean mGeofenceProviderConnected = false;
1328ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh
1338ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh
1348ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        @Override
1358ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        public void handleMessage(Message msg) {
1368ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh            switch (msg.what) {
1378ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                case GEOFENCE_PROVIDER_CONNECTED:
1388ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                    mGeofenceProviderConnected = true;
1398ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                    if (mGeofenceHardwareConnected) {
1408ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                        setGeofenceHardwareInProvider();
1418ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                    }
1428ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                    break;
1438ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                case GEOFENCE_HARDWARE_CONNECTED:
1448ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                    setGpsGeofence();
1458ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                    mGeofenceHardwareConnected = true;
1468ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                    if (mGeofenceProviderConnected) {
1478ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                        setGeofenceHardwareInProvider();
1488ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                    }
1498ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                    break;
1508ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                case GEOFENCE_HARDWARE_DISCONNECTED:
1518ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                    mGeofenceHardwareConnected = false;
1528ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                    setGeofenceHardwareInProvider();
1538ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                    break;
1548ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh            }
1558ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        }
1568ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    };
1578ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh}
158