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 Ganesh
178ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganeshpackage android.hardware.location;
188ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh
198ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganeshimport android.content.Context;
208ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganeshimport android.content.pm.PackageManager;
218ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganeshimport android.location.IGpsGeofenceHardware;
228ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganeshimport android.location.Location;
238ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganeshimport android.location.LocationManager;
24da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganeshimport android.os.Binder;
258ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganeshimport android.os.Bundle;
268ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganeshimport android.os.Handler;
27da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganeshimport android.os.IBinder;
288ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganeshimport android.os.Message;
298ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganeshimport android.os.PowerManager;
308ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganeshimport android.os.RemoteException;
318ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganeshimport android.os.ServiceManager;
328ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganeshimport android.os.SystemClock;
338ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganeshimport android.util.Log;
348ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganeshimport android.util.SparseArray;
358ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh
368ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganeshimport java.util.ArrayList;
378ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganeshimport java.util.HashMap;
388ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh
398ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh/**
408ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh * This class manages the geofences which are handled by hardware.
418ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh *
428ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh * @hide
438ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh */
448ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganeshpublic final class GeofenceHardwareImpl {
458ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    private static final String TAG = "GeofenceHardwareImpl";
468ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
478ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh
488ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    private final Context mContext;
498ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    private static GeofenceHardwareImpl sInstance;
508ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    private PowerManager.WakeLock mWakeLock;
51f8f085c51b5f8b180ad964d0385b34f8fa97cd32Zhentao Sun    private final SparseArray<IGeofenceHardwareCallback> mGeofences =
528ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh            new SparseArray<IGeofenceHardwareCallback>();
53f8f085c51b5f8b180ad964d0385b34f8fa97cd32Zhentao Sun    private final ArrayList<IGeofenceHardwareMonitorCallback>[] mCallbacks =
548ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh            new ArrayList[GeofenceHardware.NUM_MONITORS];
55f8f085c51b5f8b180ad964d0385b34f8fa97cd32Zhentao Sun    private final ArrayList<Reaper> mReapers = new ArrayList<Reaper>();
568ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh
578ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    private IGpsGeofenceHardware mGpsService;
588ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh
598ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    private int[] mSupportedMonitorTypes = new int[GeofenceHardware.NUM_MONITORS];
608ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh
618ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    // mGeofenceHandler message types
628ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    private static final int GEOFENCE_TRANSITION_CALLBACK = 1;
638ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    private static final int ADD_GEOFENCE_CALLBACK = 2;
648ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    private static final int REMOVE_GEOFENCE_CALLBACK = 3;
658ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    private static final int PAUSE_GEOFENCE_CALLBACK = 4;
668ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    private static final int RESUME_GEOFENCE_CALLBACK = 5;
67f8f085c51b5f8b180ad964d0385b34f8fa97cd32Zhentao Sun    private static final int GEOFENCE_CALLBACK_BINDER_DIED = 6;
688ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh
698ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    // mCallbacksHandler message types
708ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    private static final int GPS_GEOFENCE_STATUS = 1;
718ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    private static final int CALLBACK_ADD = 2;
728ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    private static final int CALLBACK_REMOVE = 3;
73da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh    private static final int MONITOR_CALLBACK_BINDER_DIED = 4;
74da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh
75da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh    // mReaperHandler message types
76da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh    private static final int REAPER_GEOFENCE_ADDED = 1;
77da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh    private static final int REAPER_MONITOR_CALLBACK_ADDED = 2;
78da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh    private static final int REAPER_REMOVED = 3;
798ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh
808ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    // The following constants need to match GpsLocationFlags enum in gps.h
818ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    private static final int LOCATION_INVALID = 0;
828ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    private static final int LOCATION_HAS_LAT_LONG = 1;
838ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    private static final int LOCATION_HAS_ALTITUDE = 2;
848ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    private static final int LOCATION_HAS_SPEED = 4;
858ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    private static final int LOCATION_HAS_BEARING = 8;
868ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    private static final int LOCATION_HAS_ACCURACY = 16;
878ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh
888ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    // Resolution level constants used for permission checks.
898ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    // These constants must be in increasing order of finer resolution.
908ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    private static final int RESOLUTION_LEVEL_NONE = 1;
918ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    private static final int RESOLUTION_LEVEL_COARSE = 2;
928ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    private static final int RESOLUTION_LEVEL_FINE = 3;
938ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh
948ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    // GPS Geofence errors. Should match gps.h constants.
958ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    private static final int GPS_GEOFENCE_OPERATION_SUCCESS = 0;
968ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    private static final int GPS_GEOFENCE_ERROR_TOO_MANY_GEOFENCES = 100;
978ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    private static final int GPS_GEOFENCE_ERROR_ID_EXISTS  = -101;
988ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    private static final int GPS_GEOFENCE_ERROR_ID_UNKNOWN = -102;
998ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    private static final int GPS_GEOFENCE_ERROR_INVALID_TRANSITION = -103;
1008ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    private static final int GPS_GEOFENCE_ERROR_GENERIC = -149;
1018ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh
1028ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh
1038ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh
1048ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    public synchronized static GeofenceHardwareImpl getInstance(Context context) {
1058ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        if (sInstance == null) {
1068ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh            sInstance = new GeofenceHardwareImpl(context);
1078ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        }
1088ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        return sInstance;
1098ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    }
1108ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh
1118ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    private GeofenceHardwareImpl(Context context) {
1128ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        mContext = context;
1138ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        // Init everything to unsupported.
1148ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        setMonitorAvailability(GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE,
1158ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                GeofenceHardware.MONITOR_UNSUPPORTED);
1168ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh
1178ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    }
1188ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh
1198ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    private void acquireWakeLock() {
1208ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        if (mWakeLock == null) {
1218ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh            PowerManager powerManager =
1228ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                    (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
1238ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh            mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
1248ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        }
1258ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        mWakeLock.acquire();
1268ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    }
1278ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh
1288ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    private void releaseWakeLock() {
1298ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        if (mWakeLock.isHeld()) mWakeLock.release();
1308ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    }
1318ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh
1328ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    private void updateGpsHardwareAvailability() {
1338ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        //Check which monitors are available.
1348ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        boolean gpsSupported;
1358ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        try {
1368ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh            gpsSupported = mGpsService.isHardwareGeofenceSupported();
1378ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        } catch (RemoteException e) {
1388ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh            Log.e(TAG, "Remote Exception calling LocationManagerService");
1398ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh            gpsSupported = false;
1408ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        }
1418ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh
1428ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        if (gpsSupported) {
1438ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh            // Its assumed currently available at startup.
1448ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh            // native layer will update later.
1458ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh            setMonitorAvailability(GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE,
1468ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                    GeofenceHardware.MONITOR_CURRENTLY_AVAILABLE);
1478ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        }
1488ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    }
1498ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh
1508ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    public void setGpsHardwareGeofence(IGpsGeofenceHardware service) {
1518ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        if (mGpsService == null) {
1528ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh            mGpsService = service;
1538ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh            updateGpsHardwareAvailability();
1548ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        } else if (service == null) {
1558ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh            mGpsService = null;
1568ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh            Log.w(TAG, "GPS Geofence Hardware service seems to have crashed");
1578ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        } else {
1588ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh            Log.e(TAG, "Error: GpsService being set again.");
1598ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        }
1608ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    }
1618ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh
162da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh    public int[] getMonitoringTypes() {
1638ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        synchronized (mSupportedMonitorTypes) {
164da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh            if (mSupportedMonitorTypes[GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE] !=
165da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh                        GeofenceHardware.MONITOR_UNSUPPORTED) {
166da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh                return new int[] {GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE};
167da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh            }
168da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh            return new int[0];
169da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh        }
170da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh    }
171da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh
172da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh    public int getStatusOfMonitoringType(int monitoringType) {
173da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh        synchronized (mSupportedMonitorTypes) {
174da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh            if (monitoringType >= mSupportedMonitorTypes.length || monitoringType < 0) {
175da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh                throw new IllegalArgumentException("Unknown monitoring type");
176da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh            }
177da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh            return mSupportedMonitorTypes[monitoringType];
1788ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        }
1798ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    }
1808ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh
181da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh    public boolean addCircularFence(int geofenceId,  int monitoringType, double latitude,
182da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh            double longitude, double radius, int lastTransition,int monitorTransitions,
183da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh            int notificationResponsivenes, int unknownTimer, IGeofenceHardwareCallback callback) {
1848ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        // This API is not thread safe. Operations on the same geofence need to be serialized
1858ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        // by upper layers
1868ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        if (DEBUG) {
187f8f085c51b5f8b180ad964d0385b34f8fa97cd32Zhentao Sun            Log.d(TAG, "addCircularFence: GeofenceId: " + geofenceId + " Latitude: " + latitude +
188f8f085c51b5f8b180ad964d0385b34f8fa97cd32Zhentao Sun                    " Longitude: " + longitude + " Radius: " + radius + " LastTransition: "
189f8f085c51b5f8b180ad964d0385b34f8fa97cd32Zhentao Sun                    + lastTransition + " MonitorTransition: " + monitorTransitions +
190f8f085c51b5f8b180ad964d0385b34f8fa97cd32Zhentao Sun                    " NotificationResponsiveness: " + notificationResponsivenes +
191f8f085c51b5f8b180ad964d0385b34f8fa97cd32Zhentao Sun                    " UnKnown Timer: " + unknownTimer + " MonitoringType: " + monitoringType);
1928ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh
1938ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        }
1948ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        boolean result;
195f8f085c51b5f8b180ad964d0385b34f8fa97cd32Zhentao Sun
196f8f085c51b5f8b180ad964d0385b34f8fa97cd32Zhentao Sun        // The callback must be added before addCircularHardwareGeofence is called otherwise the
197f8f085c51b5f8b180ad964d0385b34f8fa97cd32Zhentao Sun        // callback might not be called after the geofence is added in the geofence hardware.
198f8f085c51b5f8b180ad964d0385b34f8fa97cd32Zhentao Sun        // This also means that the callback must be removed if the addCircularHardwareGeofence
199f8f085c51b5f8b180ad964d0385b34f8fa97cd32Zhentao Sun        // operations is not called or fails.
200f8f085c51b5f8b180ad964d0385b34f8fa97cd32Zhentao Sun        synchronized (mGeofences) {
201f8f085c51b5f8b180ad964d0385b34f8fa97cd32Zhentao Sun            mGeofences.put(geofenceId, callback);
202f8f085c51b5f8b180ad964d0385b34f8fa97cd32Zhentao Sun        }
2038ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh
2048ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        switch (monitoringType) {
2058ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh            case GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE:
2068ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                if (mGpsService == null) return false;
2078ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                try {
2088ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                    result = mGpsService.addCircularHardwareGeofence(geofenceId, latitude,
2098ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                            longitude, radius, lastTransition, monitorTransitions,
2108ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                            notificationResponsivenes, unknownTimer);
2118ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                } catch (RemoteException e) {
2128ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                    Log.e(TAG, "AddGeofence: Remote Exception calling LocationManagerService");
2138ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                    result = false;
2148ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                }
2158ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                break;
2168ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh            default:
2178ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                result = false;
2188ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        }
219da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh        if (result) {
220f8f085c51b5f8b180ad964d0385b34f8fa97cd32Zhentao Sun            Message m = mReaperHandler.obtainMessage(REAPER_GEOFENCE_ADDED, callback);
221da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh            m.arg1 = monitoringType;
222da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh            mReaperHandler.sendMessage(m);
223da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh        } else {
224f8f085c51b5f8b180ad964d0385b34f8fa97cd32Zhentao Sun            synchronized (mGeofences) {
225f8f085c51b5f8b180ad964d0385b34f8fa97cd32Zhentao Sun                mGeofences.remove(geofenceId);
226f8f085c51b5f8b180ad964d0385b34f8fa97cd32Zhentao Sun            }
2278ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        }
2288ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh
2298ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        if (DEBUG) Log.d(TAG, "addCircularFence: Result is: " + result);
2308ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        return result;
2318ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    }
2328ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh
2338ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    public boolean removeGeofence(int geofenceId, int monitoringType) {
2348ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        // This API is not thread safe. Operations on the same geofence need to be serialized
2358ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        // by upper layers
2368ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        if (DEBUG) Log.d(TAG, "Remove Geofence: GeofenceId: " + geofenceId);
2378ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        boolean result = false;
238f8f085c51b5f8b180ad964d0385b34f8fa97cd32Zhentao Sun
239f8f085c51b5f8b180ad964d0385b34f8fa97cd32Zhentao Sun        synchronized (mGeofences) {
240f8f085c51b5f8b180ad964d0385b34f8fa97cd32Zhentao Sun            if (mGeofences.get(geofenceId) == null) {
241f8f085c51b5f8b180ad964d0385b34f8fa97cd32Zhentao Sun                throw new IllegalArgumentException("Geofence " + geofenceId + " not registered.");
242f8f085c51b5f8b180ad964d0385b34f8fa97cd32Zhentao Sun            }
243f8f085c51b5f8b180ad964d0385b34f8fa97cd32Zhentao Sun        }
2448ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        switch (monitoringType) {
2458ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh            case GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE:
2468ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                if (mGpsService == null) return false;
2478ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                try {
2488ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                    result = mGpsService.removeHardwareGeofence(geofenceId);
2498ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                } catch (RemoteException e) {
2508ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                    Log.e(TAG, "RemoveGeofence: Remote Exception calling LocationManagerService");
2518ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                    result = false;
2528ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                }
2538ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                break;
2548ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh            default:
2558ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                result = false;
2568ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        }
2578ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        if (DEBUG) Log.d(TAG, "removeGeofence: Result is: " + result);
2588ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        return result;
2598ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    }
2608ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh
2618ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    public boolean pauseGeofence(int geofenceId, int monitoringType) {
2628ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        // This API is not thread safe. Operations on the same geofence need to be serialized
2638ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        // by upper layers
2648ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        if (DEBUG) Log.d(TAG, "Pause Geofence: GeofenceId: " + geofenceId);
2658ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        boolean result;
266f8f085c51b5f8b180ad964d0385b34f8fa97cd32Zhentao Sun        synchronized (mGeofences) {
267f8f085c51b5f8b180ad964d0385b34f8fa97cd32Zhentao Sun            if (mGeofences.get(geofenceId) == null) {
268f8f085c51b5f8b180ad964d0385b34f8fa97cd32Zhentao Sun                throw new IllegalArgumentException("Geofence " + geofenceId + " not registered.");
269f8f085c51b5f8b180ad964d0385b34f8fa97cd32Zhentao Sun            }
270f8f085c51b5f8b180ad964d0385b34f8fa97cd32Zhentao Sun        }
2718ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        switch (monitoringType) {
2728ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh            case GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE:
2738ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                if (mGpsService == null) return false;
2748ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                try {
2758ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                    result = mGpsService.pauseHardwareGeofence(geofenceId);
2768ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                } catch (RemoteException e) {
2778ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                    Log.e(TAG, "PauseGeofence: Remote Exception calling LocationManagerService");
2788ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                    result = false;
2798ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                }
2808ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                break;
2818ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh            default:
2828ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                result = false;
2838ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        }
2848ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        if (DEBUG) Log.d(TAG, "pauseGeofence: Result is: " + result);
2858ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        return result;
2868ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    }
2878ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh
2888ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh
289da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh    public boolean resumeGeofence(int geofenceId,  int monitoringType, int monitorTransition) {
2908ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        // This API is not thread safe. Operations on the same geofence need to be serialized
2918ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        // by upper layers
2928ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        if (DEBUG) Log.d(TAG, "Resume Geofence: GeofenceId: " + geofenceId);
2938ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        boolean result;
294f8f085c51b5f8b180ad964d0385b34f8fa97cd32Zhentao Sun        synchronized (mGeofences) {
295f8f085c51b5f8b180ad964d0385b34f8fa97cd32Zhentao Sun            if (mGeofences.get(geofenceId) == null) {
296f8f085c51b5f8b180ad964d0385b34f8fa97cd32Zhentao Sun                throw new IllegalArgumentException("Geofence " + geofenceId + " not registered.");
297f8f085c51b5f8b180ad964d0385b34f8fa97cd32Zhentao Sun            }
298f8f085c51b5f8b180ad964d0385b34f8fa97cd32Zhentao Sun        }
2998ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        switch (monitoringType) {
3008ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh            case GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE:
3018ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                if (mGpsService == null) return false;
3028ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                try {
3038ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                    result = mGpsService.resumeHardwareGeofence(geofenceId, monitorTransition);
3048ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                } catch (RemoteException e) {
3058ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                    Log.e(TAG, "ResumeGeofence: Remote Exception calling LocationManagerService");
3068ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                    result = false;
3078ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                }
3088ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                break;
3098ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh            default:
3108ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                result = false;
3118ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        }
3128ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        if (DEBUG) Log.d(TAG, "resumeGeofence: Result is: " + result);
3138ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        return result;
3148ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    }
3158ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh
3168ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    public boolean registerForMonitorStateChangeCallback(int monitoringType,
317da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh            IGeofenceHardwareMonitorCallback callback) {
318da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh        Message reaperMessage =
319da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh                mReaperHandler.obtainMessage(REAPER_MONITOR_CALLBACK_ADDED, callback);
320da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh        reaperMessage.arg1 = monitoringType;
321da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh        mReaperHandler.sendMessage(reaperMessage);
322da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh
3238ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        Message m = mCallbacksHandler.obtainMessage(CALLBACK_ADD, callback);
3248ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        m.arg1 = monitoringType;
3258ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        mCallbacksHandler.sendMessage(m);
3268ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        return true;
3278ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    }
3288ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh
3298ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    public boolean unregisterForMonitorStateChangeCallback(int monitoringType,
330da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh            IGeofenceHardwareMonitorCallback callback) {
3318ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        Message m = mCallbacksHandler.obtainMessage(CALLBACK_REMOVE, callback);
3328ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        m.arg1 = monitoringType;
3338ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        mCallbacksHandler.sendMessage(m);
3348ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        return true;
3358ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    }
3368ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh
3378ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    private Location getLocation(int flags, double latitude,
3388ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh            double longitude, double altitude, float speed, float bearing, float accuracy,
3398ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh            long timestamp) {
3408ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        if (DEBUG) Log.d(TAG, "GetLocation: " + flags + ":" + latitude);
3418ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        Location location = new Location(LocationManager.GPS_PROVIDER);
3428ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        if ((flags & LOCATION_HAS_LAT_LONG) == LOCATION_HAS_LAT_LONG) {
3438ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh            location.setLatitude(latitude);
3448ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh            location.setLongitude(longitude);
3458ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh            location.setTime(timestamp);
3468ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh            // It would be nice to push the elapsed real-time timestamp
3478ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh            // further down the stack, but this is still useful
3488ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh            location.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());
3498ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        }
3508ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        if ((flags & LOCATION_HAS_ALTITUDE) == LOCATION_HAS_ALTITUDE) {
3518ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh            location.setAltitude(altitude);
3528ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        } else {
3538ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh            location.removeAltitude();
3548ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        }
3558ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        if ((flags & LOCATION_HAS_SPEED) == LOCATION_HAS_SPEED) {
3568ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh            location.setSpeed(speed);
3578ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        } else {
3588ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh            location.removeSpeed();
3598ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        }
3608ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        if ((flags & LOCATION_HAS_BEARING) == LOCATION_HAS_BEARING) {
3618ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh            location.setBearing(bearing);
3628ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        } else {
3638ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh            location.removeBearing();
3648ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        }
3658ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        if ((flags & LOCATION_HAS_ACCURACY) == LOCATION_HAS_ACCURACY) {
3668ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh            location.setAccuracy(accuracy);
3678ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        } else {
3688ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh            location.removeAccuracy();
3698ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        }
3708ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        return location;
3718ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    }
3728ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh
3738ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    /**
3748ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh     * called from GpsLocationProvider to report geofence transition
3758ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh     */
3768ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    public void reportGpsGeofenceTransition(int geofenceId, int flags, double latitude,
3778ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh            double longitude, double altitude, float speed, float bearing, float accuracy,
3788ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh            long timestamp, int transition, long transitionTimestamp) {
3798ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        if (DEBUG) Log.d(TAG, "GeofenceTransition: Flags: " + flags + " Lat: " + latitude +
3808ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh            " Long: " + longitude + " Altitude: " + altitude + " Speed: " + speed + " Bearing: " +
3818ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh            bearing + " Accuracy: " + accuracy + " Timestamp: " + timestamp + " Transition: " +
3828ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh            transition + " TransitionTimestamp: " + transitionTimestamp);
3838ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        Location location = getLocation(flags, latitude, longitude, altitude, speed, bearing,
3848ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                accuracy, timestamp);
3858ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        GeofenceTransition t = new GeofenceTransition(geofenceId, transition, timestamp, location);
3868ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        acquireWakeLock();
3878ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        Message m = mGeofenceHandler.obtainMessage(GEOFENCE_TRANSITION_CALLBACK, t);
3888ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        mGeofenceHandler.sendMessage(m);
3898ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    }
3908ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh
3918ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    /**
3928ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh     * called from GpsLocationProvider to report GPS status change.
3938ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh     */
3948ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    public void reportGpsGeofenceStatus(int status, int flags, double latitude,
3958ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh            double longitude, double altitude, float speed, float bearing, float accuracy,
3968ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh            long timestamp) {
3978ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        Location location = getLocation(flags, latitude, longitude, altitude, speed, bearing,
3988ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                accuracy, timestamp);
3998ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        boolean available = false;
4008ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        if (status == GeofenceHardware.GPS_GEOFENCE_AVAILABLE) available = true;
4018ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh
402b8061be81c7a7cf87f4edc7ea48a8fd464363a61Zhentao Sun        int val = (available ? GeofenceHardware.MONITOR_CURRENTLY_AVAILABLE :
403b8061be81c7a7cf87f4edc7ea48a8fd464363a61Zhentao Sun                GeofenceHardware.MONITOR_CURRENTLY_UNAVAILABLE);
4048ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        setMonitorAvailability(GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE, val);
4058ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh
4068ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        acquireWakeLock();
4078ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        Message m = mCallbacksHandler.obtainMessage(GPS_GEOFENCE_STATUS, location);
4088ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        m.arg1 = val;
4098ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        mCallbacksHandler.sendMessage(m);
4108ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    }
4118ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh
4128ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    /**
4138ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh     * called from GpsLocationProvider add geofence callback.
4148ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh     */
4158ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    public void reportGpsGeofenceAddStatus(int geofenceId, int status) {
4168ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        if (DEBUG) Log.d(TAG, "Add Callback: GPS : Id: " + geofenceId + " Status: " + status);
4178ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        acquireWakeLock();
4188ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        Message m = mGeofenceHandler.obtainMessage(ADD_GEOFENCE_CALLBACK);
4198ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        m.arg1 = geofenceId;
4208ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        m.arg2 = getGeofenceStatus(status);
4218ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        mGeofenceHandler.sendMessage(m);
4228ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    }
4238ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh
4248ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    /**
4258ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh     * called from GpsLocationProvider remove geofence callback.
4268ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh     */
4278ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    public void reportGpsGeofenceRemoveStatus(int geofenceId, int status) {
4288ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        if (DEBUG) Log.d(TAG, "Remove Callback: GPS : Id: " + geofenceId + " Status: " + status);
4298ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        acquireWakeLock();
4308ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        Message m = mGeofenceHandler.obtainMessage(REMOVE_GEOFENCE_CALLBACK);
4318ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        m.arg1 = geofenceId;
4328ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        m.arg2 = getGeofenceStatus(status);
4338ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        mGeofenceHandler.sendMessage(m);
4348ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    }
4358ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh
4368ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    /**
4378ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh     * called from GpsLocationProvider pause geofence callback.
4388ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh     */
4398ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    public void reportGpsGeofencePauseStatus(int geofenceId, int status) {
4408ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        if (DEBUG) Log.d(TAG, "Pause Callback: GPS : Id: " + geofenceId + " Status: " + status);
4418ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        acquireWakeLock();
4428ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        Message m = mGeofenceHandler.obtainMessage(PAUSE_GEOFENCE_CALLBACK);
4438ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        m.arg1 = geofenceId;
4448ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        m.arg2 = getGeofenceStatus(status);
4458ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        mGeofenceHandler.sendMessage(m);
4468ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    }
4478ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh
4488ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    /**
4498ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh     * called from GpsLocationProvider resume geofence callback.
4508ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh     */
4518ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    public void reportGpsGeofenceResumeStatus(int geofenceId, int status) {
4528ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        if (DEBUG) Log.d(TAG, "Resume Callback: GPS : Id: " + geofenceId + " Status: " + status);
4538ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        acquireWakeLock();
4548ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        Message m = mGeofenceHandler.obtainMessage(RESUME_GEOFENCE_CALLBACK);
4558ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        m.arg1 = geofenceId;
4568ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        m.arg2 = getGeofenceStatus(status);
4578ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        mGeofenceHandler.sendMessage(m);
4588ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    }
4598ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh
4608ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    // All operations on mGeofences
4618ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    private Handler mGeofenceHandler = new Handler() {
4628ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        @Override
4638ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        public void handleMessage(Message msg) {
4648ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh            int geofenceId;
4658ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh            int status;
4668ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh            IGeofenceHardwareCallback callback;
4678ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh            switch (msg.what) {
4688ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                case ADD_GEOFENCE_CALLBACK:
4698ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                    geofenceId = msg.arg1;
470f8f085c51b5f8b180ad964d0385b34f8fa97cd32Zhentao Sun                    synchronized (mGeofences) {
471f8f085c51b5f8b180ad964d0385b34f8fa97cd32Zhentao Sun                        callback = mGeofences.get(geofenceId);
472f8f085c51b5f8b180ad964d0385b34f8fa97cd32Zhentao Sun                    }
4738ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh
474cfa496f7cdc52711e9ad7521224f67d1aaee002cZhentao Sun                    if (callback != null) {
475cfa496f7cdc52711e9ad7521224f67d1aaee002cZhentao Sun                        try {
476cfa496f7cdc52711e9ad7521224f67d1aaee002cZhentao Sun                            callback.onGeofenceAdd(geofenceId, msg.arg2);
477cfa496f7cdc52711e9ad7521224f67d1aaee002cZhentao Sun                        } catch (RemoteException e) {Log.i(TAG, "Remote Exception:" + e);}
478cfa496f7cdc52711e9ad7521224f67d1aaee002cZhentao Sun                    }
4798ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                    releaseWakeLock();
4808ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                    break;
4818ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                case REMOVE_GEOFENCE_CALLBACK:
4828ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                    geofenceId = msg.arg1;
483f8f085c51b5f8b180ad964d0385b34f8fa97cd32Zhentao Sun                    synchronized (mGeofences) {
484f8f085c51b5f8b180ad964d0385b34f8fa97cd32Zhentao Sun                        callback = mGeofences.get(geofenceId);
485f8f085c51b5f8b180ad964d0385b34f8fa97cd32Zhentao Sun                    }
4868ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh
487cfa496f7cdc52711e9ad7521224f67d1aaee002cZhentao Sun                    if (callback != null) {
488cfa496f7cdc52711e9ad7521224f67d1aaee002cZhentao Sun                        try {
489cfa496f7cdc52711e9ad7521224f67d1aaee002cZhentao Sun                            callback.onGeofenceRemove(geofenceId, msg.arg2);
490cfa496f7cdc52711e9ad7521224f67d1aaee002cZhentao Sun                        } catch (RemoteException e) {}
491cfa496f7cdc52711e9ad7521224f67d1aaee002cZhentao Sun                        synchronized (mGeofences) {
492cfa496f7cdc52711e9ad7521224f67d1aaee002cZhentao Sun                            mGeofences.remove(geofenceId);
493cfa496f7cdc52711e9ad7521224f67d1aaee002cZhentao Sun                        }
494f8f085c51b5f8b180ad964d0385b34f8fa97cd32Zhentao Sun                    }
4958ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                    releaseWakeLock();
4968ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                    break;
4978ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh
4988ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                case PAUSE_GEOFENCE_CALLBACK:
4998ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                    geofenceId = msg.arg1;
500f8f085c51b5f8b180ad964d0385b34f8fa97cd32Zhentao Sun                    synchronized (mGeofences) {
501f8f085c51b5f8b180ad964d0385b34f8fa97cd32Zhentao Sun                        callback = mGeofences.get(geofenceId);
502f8f085c51b5f8b180ad964d0385b34f8fa97cd32Zhentao Sun                    }
5038ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh
504cfa496f7cdc52711e9ad7521224f67d1aaee002cZhentao Sun                    if (callback != null) {
505cfa496f7cdc52711e9ad7521224f67d1aaee002cZhentao Sun                        try {
506cfa496f7cdc52711e9ad7521224f67d1aaee002cZhentao Sun                            callback.onGeofencePause(geofenceId, msg.arg2);
507cfa496f7cdc52711e9ad7521224f67d1aaee002cZhentao Sun                        } catch (RemoteException e) {}
508cfa496f7cdc52711e9ad7521224f67d1aaee002cZhentao Sun                    }
5098ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                    releaseWakeLock();
5108ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                    break;
5118ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh
5128ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                case RESUME_GEOFENCE_CALLBACK:
5138ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                    geofenceId = msg.arg1;
514f8f085c51b5f8b180ad964d0385b34f8fa97cd32Zhentao Sun                    synchronized (mGeofences) {
515f8f085c51b5f8b180ad964d0385b34f8fa97cd32Zhentao Sun                        callback = mGeofences.get(geofenceId);
516f8f085c51b5f8b180ad964d0385b34f8fa97cd32Zhentao Sun                    }
5178ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh
518cfa496f7cdc52711e9ad7521224f67d1aaee002cZhentao Sun                    if (callback != null) {
519cfa496f7cdc52711e9ad7521224f67d1aaee002cZhentao Sun                        try {
520cfa496f7cdc52711e9ad7521224f67d1aaee002cZhentao Sun                            callback.onGeofenceResume(geofenceId, msg.arg2);
521cfa496f7cdc52711e9ad7521224f67d1aaee002cZhentao Sun                        } catch (RemoteException e) {}
522cfa496f7cdc52711e9ad7521224f67d1aaee002cZhentao Sun                    }
5238ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                    releaseWakeLock();
5248ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                    break;
5258ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh
5268ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                case GEOFENCE_TRANSITION_CALLBACK:
5278ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                    GeofenceTransition geofenceTransition = (GeofenceTransition)(msg.obj);
528f8f085c51b5f8b180ad964d0385b34f8fa97cd32Zhentao Sun                    synchronized (mGeofences) {
529f8f085c51b5f8b180ad964d0385b34f8fa97cd32Zhentao Sun                        callback = mGeofences.get(geofenceTransition.mGeofenceId);
530f8f085c51b5f8b180ad964d0385b34f8fa97cd32Zhentao Sun                    }
5318ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh
5328ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                    if (DEBUG) Log.d(TAG, "GeofenceTransistionCallback: GPS : GeofenceId: " +
5338ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                            geofenceTransition.mGeofenceId +
534f8f085c51b5f8b180ad964d0385b34f8fa97cd32Zhentao Sun                            " Transition: " + geofenceTransition.mTransition +
535f8f085c51b5f8b180ad964d0385b34f8fa97cd32Zhentao Sun                            " Location: " + geofenceTransition.mLocation + ":" + mGeofences);
5368ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh
537cfa496f7cdc52711e9ad7521224f67d1aaee002cZhentao Sun                    if (callback != null) {
538cfa496f7cdc52711e9ad7521224f67d1aaee002cZhentao Sun                        try {
539cfa496f7cdc52711e9ad7521224f67d1aaee002cZhentao Sun                            callback.onGeofenceTransition(
540cfa496f7cdc52711e9ad7521224f67d1aaee002cZhentao Sun                                    geofenceTransition.mGeofenceId, geofenceTransition.mTransition,
541cfa496f7cdc52711e9ad7521224f67d1aaee002cZhentao Sun                                    geofenceTransition.mLocation, geofenceTransition.mTimestamp,
542cfa496f7cdc52711e9ad7521224f67d1aaee002cZhentao Sun                                    GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE);
543cfa496f7cdc52711e9ad7521224f67d1aaee002cZhentao Sun                        } catch (RemoteException e) {}
544cfa496f7cdc52711e9ad7521224f67d1aaee002cZhentao Sun                    }
5458ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                    releaseWakeLock();
5468ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                    break;
547da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh                case GEOFENCE_CALLBACK_BINDER_DIED:
548da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh                   // Find all geofences associated with this callback and remove them.
549da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh                   callback = (IGeofenceHardwareCallback) (msg.obj);
550da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh                   if (DEBUG) Log.d(TAG, "Geofence callback reaped:" + callback);
551da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh                   int monitoringType = msg.arg1;
552f8f085c51b5f8b180ad964d0385b34f8fa97cd32Zhentao Sun                   synchronized (mGeofences) {
553f8f085c51b5f8b180ad964d0385b34f8fa97cd32Zhentao Sun                       for (int i = 0; i < mGeofences.size(); i++) {
554f8f085c51b5f8b180ad964d0385b34f8fa97cd32Zhentao Sun                            if (mGeofences.valueAt(i).equals(callback)) {
555f8f085c51b5f8b180ad964d0385b34f8fa97cd32Zhentao Sun                                geofenceId = mGeofences.keyAt(i);
556f8f085c51b5f8b180ad964d0385b34f8fa97cd32Zhentao Sun                                removeGeofence(mGeofences.keyAt(i), monitoringType);
557f8f085c51b5f8b180ad964d0385b34f8fa97cd32Zhentao Sun                                mGeofences.remove(geofenceId);
558f8f085c51b5f8b180ad964d0385b34f8fa97cd32Zhentao Sun                            }
559f8f085c51b5f8b180ad964d0385b34f8fa97cd32Zhentao Sun                       }
560da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh                   }
5618ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh            }
5628ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        }
5638ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    };
5648ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh
5658ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    // All operations on mCallbacks
5668ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    private Handler mCallbacksHandler = new Handler() {
5678ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        @Override
5688ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        public void handleMessage(Message msg) {
5698ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh            int monitoringType;
570da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh            ArrayList<IGeofenceHardwareMonitorCallback> callbackList;
571da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh            IGeofenceHardwareMonitorCallback callback;
5728ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh
5738ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh            switch (msg.what) {
5748ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                case GPS_GEOFENCE_STATUS:
5758ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                    Location location = (Location) msg.obj;
5768ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                    int val = msg.arg1;
5778ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                    boolean available;
5788ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                    available = (val == GeofenceHardware.MONITOR_CURRENTLY_AVAILABLE ?
5798ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                            true : false);
5808ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                    callbackList = mCallbacks[GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE];
581cfa496f7cdc52711e9ad7521224f67d1aaee002cZhentao Sun                    if (callbackList != null) {
582cfa496f7cdc52711e9ad7521224f67d1aaee002cZhentao Sun                        if (DEBUG) Log.d(TAG, "MonitoringSystemChangeCallback: GPS : " + available);
583cfa496f7cdc52711e9ad7521224f67d1aaee002cZhentao Sun
584cfa496f7cdc52711e9ad7521224f67d1aaee002cZhentao Sun                        for (IGeofenceHardwareMonitorCallback c: callbackList) {
585cfa496f7cdc52711e9ad7521224f67d1aaee002cZhentao Sun                            try {
586cfa496f7cdc52711e9ad7521224f67d1aaee002cZhentao Sun                                c.onMonitoringSystemChange(
587cfa496f7cdc52711e9ad7521224f67d1aaee002cZhentao Sun                                        GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE, available,
588cfa496f7cdc52711e9ad7521224f67d1aaee002cZhentao Sun                                        location);
589cfa496f7cdc52711e9ad7521224f67d1aaee002cZhentao Sun                            } catch (RemoteException e) {}
590cfa496f7cdc52711e9ad7521224f67d1aaee002cZhentao Sun                        }
5918ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                    }
5928ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                    releaseWakeLock();
5938ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                    break;
5948ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                case CALLBACK_ADD:
5958ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                    monitoringType = msg.arg1;
596da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh                    callback = (IGeofenceHardwareMonitorCallback) msg.obj;
5978ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                    callbackList = mCallbacks[monitoringType];
5988ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                    if (callbackList == null) {
599da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh                        callbackList = new ArrayList<IGeofenceHardwareMonitorCallback>();
6008ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                        mCallbacks[monitoringType] = callbackList;
6018ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                    }
6028ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                    if (!callbackList.contains(callback)) callbackList.add(callback);
6038ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                    break;
6048ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                case CALLBACK_REMOVE:
6058ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                    monitoringType = msg.arg1;
606da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh                    callback = (IGeofenceHardwareMonitorCallback) msg.obj;
6078ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                    callbackList = mCallbacks[monitoringType];
6088ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                    if (callbackList != null) {
6098ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                        callbackList.remove(callback);
6108ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                    }
6118ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                    break;
612da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh                case MONITOR_CALLBACK_BINDER_DIED:
613da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh                    callback = (IGeofenceHardwareMonitorCallback) msg.obj;
614da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh                    if (DEBUG) Log.d(TAG, "Monitor callback reaped:" + callback);
615da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh                    callbackList = mCallbacks[msg.arg1];
616da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh                    if (callbackList != null && callbackList.contains(callback)) {
617da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh                        callbackList.remove(callback);
618da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh                    }
619da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh            }
620da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh        }
621da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh    };
622da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh
623da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh    // All operations on mReaper
624da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh    private Handler mReaperHandler = new Handler() {
625da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh        @Override
626da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh        public void handleMessage(Message msg) {
627da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh            Reaper r;
628da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh            IGeofenceHardwareCallback callback;
629da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh            IGeofenceHardwareMonitorCallback monitorCallback;
630da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh            int monitoringType;
631da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh
632da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh            switch (msg.what) {
633da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh                case REAPER_GEOFENCE_ADDED:
634da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh                    callback = (IGeofenceHardwareCallback) msg.obj;
635da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh                    monitoringType = msg.arg1;
636da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh                    r = new Reaper(callback, monitoringType);
637da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh                    if (!mReapers.contains(r)) {
638da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh                        mReapers.add(r);
639da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh                        IBinder b = callback.asBinder();
640da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh                        try {
641da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh                            b.linkToDeath(r, 0);
642da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh                        } catch (RemoteException e) {}
643da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh                    }
644da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh                    break;
645da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh                case REAPER_MONITOR_CALLBACK_ADDED:
646da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh                    monitorCallback = (IGeofenceHardwareMonitorCallback) msg.obj;
647da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh                    monitoringType = msg.arg1;
648da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh
649da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh                    r = new Reaper(monitorCallback, monitoringType);
650da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh                    if (!mReapers.contains(r)) {
651da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh                        mReapers.add(r);
652da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh                        IBinder b = monitorCallback.asBinder();
653da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh                        try {
654da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh                            b.linkToDeath(r, 0);
655da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh                        } catch (RemoteException e) {}
656da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh                    }
657da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh                    break;
658da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh                case REAPER_REMOVED:
659da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh                    r = (Reaper) msg.obj;
660da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh                    mReapers.remove(r);
6618ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh            }
6628ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        }
6638ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    };
6648ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh
6658ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    private class GeofenceTransition {
6668ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        private int mGeofenceId, mTransition;
6678ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        private long mTimestamp;
6688ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        private Location mLocation;
6698ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh
6708ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        GeofenceTransition(int geofenceId, int transition, long timestamp, Location location) {
6718ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh            mGeofenceId = geofenceId;
6728ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh            mTransition = transition;
6738ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh            mTimestamp = timestamp;
6748ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh            mLocation = location;
6758ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        }
6768ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    }
6778ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh
6788ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    private void setMonitorAvailability(int monitor, int val) {
6798ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        synchronized (mSupportedMonitorTypes) {
6808ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh            mSupportedMonitorTypes[monitor] = val;
6818ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        }
6828ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    }
6838ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh
6848ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh
6858ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    int getMonitoringResolutionLevel(int monitoringType) {
6868ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        switch (monitoringType) {
6878ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh            case GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE:
6888ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                return RESOLUTION_LEVEL_FINE;
6898ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        }
6908ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        return RESOLUTION_LEVEL_NONE;
6918ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    }
6928ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh
693da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh    class Reaper implements IBinder.DeathRecipient {
694da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh        private IGeofenceHardwareMonitorCallback mMonitorCallback;
695da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh        private IGeofenceHardwareCallback mCallback;
696da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh        private int mMonitoringType;
697da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh
698da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh        Reaper(IGeofenceHardwareCallback c, int monitoringType) {
699da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh            mCallback = c;
700da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh            mMonitoringType = monitoringType;
701da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh        }
702da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh
703da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh        Reaper(IGeofenceHardwareMonitorCallback c, int monitoringType) {
704da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh            mMonitorCallback = c;
705da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh            mMonitoringType = monitoringType;
706da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh        }
707da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh
708da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh        @Override
709da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh        public void binderDied() {
710da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh            Message m;
711da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh            if (mCallback != null) {
712da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh                m = mGeofenceHandler.obtainMessage(GEOFENCE_CALLBACK_BINDER_DIED, mCallback);
713da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh                m.arg1 = mMonitoringType;
714da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh                mGeofenceHandler.sendMessage(m);
715da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh            } else if (mMonitorCallback != null) {
716da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh                m = mCallbacksHandler.obtainMessage(MONITOR_CALLBACK_BINDER_DIED, mMonitorCallback);
717da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh                m.arg1 = mMonitoringType;
718da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh                mCallbacksHandler.sendMessage(m);
719da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh            }
720da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh            Message reaperMessage = mReaperHandler.obtainMessage(REAPER_REMOVED, this);
721da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh            mReaperHandler.sendMessage(reaperMessage);
722da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh        }
723da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh
724da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh        @Override
725da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh        public int hashCode() {
726da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh            int result = 17;
727da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh            result = 31 * result + (mCallback != null ? mCallback.hashCode() : 0);
728da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh            result = 31 * result + (mMonitorCallback != null ? mMonitorCallback.hashCode() : 0);
729da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh            result = 31 * result + mMonitoringType;
730da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh            return result;
731da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh        }
732da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh
733da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh        @Override
734da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh        public boolean equals(Object obj) {
735da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh            if (obj == null) return false;
736da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh            if (obj == this) return true;
737da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh
738da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh            Reaper rhs = (Reaper) obj;
739da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh            return rhs.mCallback == mCallback && rhs.mMonitorCallback == mMonitorCallback &&
740da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh                    rhs.mMonitoringType == mMonitoringType;
741da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh        }
742da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh    }
743da6508954a492f3dd4397e70e4fa08ee54bd2741Jaikumar Ganesh
7448ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    int getAllowedResolutionLevel(int pid, int uid) {
7458ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        if (mContext.checkPermission(android.Manifest.permission.ACCESS_FINE_LOCATION,
7468ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                pid, uid) == PackageManager.PERMISSION_GRANTED) {
7478ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh            return RESOLUTION_LEVEL_FINE;
7488ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        } else if (mContext.checkPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION,
7498ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                pid, uid) == PackageManager.PERMISSION_GRANTED) {
7508ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh            return RESOLUTION_LEVEL_COARSE;
7518ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        } else {
7528ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh            return RESOLUTION_LEVEL_NONE;
7538ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        }
7548ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    }
7558ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh
7568ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    private int getGeofenceStatus(int status) {
7578ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        switch (status) {
7588ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh            case GPS_GEOFENCE_OPERATION_SUCCESS:
7598ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                return GeofenceHardware.GEOFENCE_SUCCESS;
7608ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh            case GPS_GEOFENCE_ERROR_GENERIC:
7618ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                return GeofenceHardware.GEOFENCE_FAILURE;
7628ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh            case GPS_GEOFENCE_ERROR_ID_EXISTS:
7638ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                return GeofenceHardware.GEOFENCE_ERROR_ID_EXISTS;
7648ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh            case GPS_GEOFENCE_ERROR_INVALID_TRANSITION:
7658ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                return GeofenceHardware.GEOFENCE_ERROR_INVALID_TRANSITION;
7668ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh            case GPS_GEOFENCE_ERROR_TOO_MANY_GEOFENCES:
7678ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                return GeofenceHardware.GEOFENCE_ERROR_TOO_MANY_GEOFENCES;
7688ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh            case GPS_GEOFENCE_ERROR_ID_UNKNOWN:
7698ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh                return GeofenceHardware.GEOFENCE_ERROR_ID_UNKNOWN;
7708ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        }
7718ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh        return -1;
7728ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh    }
7738ce470dd4ba0608abb6b5eae117cefca927af96bJaikumar Ganesh}
774