blob: c6cf68f3ff085fe367cf1b57ce7267bcef244e3d [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Mike Lockwood00b74272010-03-26 10:41:48 -040017package com.android.server.location;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080018
Mike Lockwood29c84342009-05-06 14:01:15 -040019import android.app.AlarmManager;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080020import android.app.AppOpsManager;
Mike Lockwood29c84342009-05-06 14:01:15 -040021import android.app.PendingIntent;
The Android Open Source Project10592532009-03-18 17:39:46 -070022import android.content.BroadcastReceiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080023import android.content.Context;
24import android.content.Intent;
The Android Open Source Project10592532009-03-18 17:39:46 -070025import android.content.IntentFilter;
Kevin Tanga5fe6b22011-06-05 14:25:16 -070026import android.database.Cursor;
destradaa0682809a2013-08-12 18:50:30 -070027import android.hardware.location.GeofenceHardware;
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -070028import android.hardware.location.GeofenceHardwareImpl;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080029import android.location.Criteria;
destradaa0682809a2013-08-12 18:50:30 -070030import android.location.FusedBatchOptions;
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -070031import android.location.IGpsGeofenceHardware;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080032import android.location.IGpsStatusListener;
Mike Lockwood15e3d0f2009-05-01 07:53:28 -040033import android.location.IGpsStatusProvider;
Mike Lockwood4e50b782009-04-03 08:24:43 -070034import android.location.ILocationManager;
Danke Xie22d1f9f2009-08-18 18:28:45 -040035import android.location.INetInitiatedListener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080036import android.location.Location;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070037import android.location.LocationListener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080038import android.location.LocationManager;
39import android.location.LocationProvider;
Stan Chesnutt1d72d8c2013-04-15 19:18:02 -070040import android.location.LocationRequest;
Mike Lockwood58bda982009-04-14 16:25:07 -040041import android.net.ConnectivityManager;
Mike Lockwood03d24672009-10-08 15:45:03 -040042import android.net.NetworkInfo;
Kevin Tanga5fe6b22011-06-05 14:25:16 -070043import android.net.Uri;
Kevin Tang40e1baf2012-01-10 14:32:44 -080044import android.os.AsyncTask;
Dianne Hackborn91268cf2013-06-13 19:06:50 -070045import android.os.BatteryStats;
Mike Lockwood63aa5a62010-04-14 19:21:31 -040046import android.os.Binder;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080047import android.os.Bundle;
Mike Lockwood62a8fc12010-03-22 14:23:26 -040048import android.os.Handler;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080049import android.os.IBinder;
Victoria Lease5cd731a2012-12-19 15:04:21 -080050import android.os.Looper;
Mike Lockwood62a8fc12010-03-22 14:23:26 -040051import android.os.Message;
Mike Lockwood0528b9b2009-05-07 10:12:54 -040052import android.os.PowerManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080053import android.os.RemoteException;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -040054import android.os.ServiceManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080055import android.os.SystemClock;
Dianne Hackborn5ac72a22012-08-29 18:32:08 -070056import android.os.UserHandle;
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -070057import android.os.WorkSource;
Mike Lockwoodbcab8df2009-06-25 16:39:09 -040058import android.provider.Settings;
Kevin Tanga5fe6b22011-06-05 14:25:16 -070059import android.provider.Telephony.Carriers;
Miguel Torroja1e84da82010-07-27 07:02:24 +020060import android.provider.Telephony.Sms.Intents;
Jake Hambyb49a73d2011-03-15 20:09:46 -070061import android.telephony.SmsMessage;
Miguel Torroja1e84da82010-07-27 07:02:24 +020062import android.telephony.TelephonyManager;
63import android.telephony.gsm.GsmCellLocation;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080064import android.util.Log;
Jeff Sharkey104344e2011-07-10 14:20:41 -070065import android.util.NtpTrustedTime;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080066
67import com.android.internal.app.IAppOpsService;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -040068import com.android.internal.app.IBatteryStats;
Danke Xie22d1f9f2009-08-18 18:28:45 -040069import com.android.internal.location.GpsNetInitiatedHandler;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070070import com.android.internal.location.ProviderProperties;
71import com.android.internal.location.ProviderRequest;
Danke Xie22d1f9f2009-08-18 18:28:45 -040072import com.android.internal.location.GpsNetInitiatedHandler.GpsNiNotification;
Jake Hambyb49a73d2011-03-15 20:09:46 -070073import com.android.internal.telephony.Phone;
Wink Savillea639b312012-07-10 12:37:54 -070074import com.android.internal.telephony.PhoneConstants;
The Android Open Source Project10592532009-03-18 17:39:46 -070075
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080076import java.io.File;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070077import java.io.FileDescriptor;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080078import java.io.FileInputStream;
79import java.io.IOException;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070080import java.io.PrintWriter;
Jeff Sharkey104344e2011-07-10 14:20:41 -070081import java.io.StringReader;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080082import java.util.ArrayList;
Mike Lockwoodf1218be2010-01-29 09:20:06 -050083import java.util.Date;
Danke Xie22d1f9f2009-08-18 18:28:45 -040084import java.util.Map.Entry;
Jake Hambyb49a73d2011-03-15 20:09:46 -070085import java.util.Properties;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080086
87/**
88 * A GPS implementation of LocationProvider used by LocationManager.
89 *
90 * {@hide}
91 */
Mike Lockwood89096312010-03-24 10:14:55 -040092public class GpsLocationProvider implements LocationProviderInterface {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080093
94 private static final String TAG = "GpsLocationProvider";
Mike Lockwood29c84342009-05-06 14:01:15 -040095
Brian Muramatsu1715cb32012-08-08 17:32:21 -070096 private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
97 private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
Mike Lockwood62a8fc12010-03-22 14:23:26 -040098
Nick Pelly6fa9ad42012-07-16 12:18:23 -070099 private static final ProviderProperties PROPERTIES = new ProviderProperties(
100 true, true, false, false, true, true, true,
101 Criteria.POWER_HIGH, Criteria.ACCURACY_FINE);
102
The Android Open Source Project10592532009-03-18 17:39:46 -0700103 // these need to match GpsPositionMode enum in gps.h
104 private static final int GPS_POSITION_MODE_STANDALONE = 0;
105 private static final int GPS_POSITION_MODE_MS_BASED = 1;
106 private static final int GPS_POSITION_MODE_MS_ASSISTED = 2;
107
Mike Lockwood04598b62010-04-14 17:17:24 -0400108 // these need to match GpsPositionRecurrence enum in gps.h
109 private static final int GPS_POSITION_RECURRENCE_PERIODIC = 0;
110 private static final int GPS_POSITION_RECURRENCE_SINGLE = 1;
111
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800112 // these need to match GpsStatusValue defines in gps.h
113 private static final int GPS_STATUS_NONE = 0;
114 private static final int GPS_STATUS_SESSION_BEGIN = 1;
115 private static final int GPS_STATUS_SESSION_END = 2;
116 private static final int GPS_STATUS_ENGINE_ON = 3;
117 private static final int GPS_STATUS_ENGINE_OFF = 4;
118
Mike Lockwoode3635c92009-05-11 08:38:02 -0400119 // these need to match GpsApgsStatusValue defines in gps.h
120 /** AGPS status event values. */
121 private static final int GPS_REQUEST_AGPS_DATA_CONN = 1;
122 private static final int GPS_RELEASE_AGPS_DATA_CONN = 2;
123 private static final int GPS_AGPS_DATA_CONNECTED = 3;
124 private static final int GPS_AGPS_DATA_CONN_DONE = 4;
125 private static final int GPS_AGPS_DATA_CONN_FAILED = 5;
Mike Lockwood58bda982009-04-14 16:25:07 -0400126
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800127 // these need to match GpsLocationFlags enum in gps.h
128 private static final int LOCATION_INVALID = 0;
129 private static final int LOCATION_HAS_LAT_LONG = 1;
130 private static final int LOCATION_HAS_ALTITUDE = 2;
131 private static final int LOCATION_HAS_SPEED = 4;
132 private static final int LOCATION_HAS_BEARING = 8;
133 private static final int LOCATION_HAS_ACCURACY = 16;
Mike Lockwoode3635c92009-05-11 08:38:02 -0400134
135// IMPORTANT - the GPS_DELETE_* symbols here must match constants in gps.h
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800136 private static final int GPS_DELETE_EPHEMERIS = 0x0001;
137 private static final int GPS_DELETE_ALMANAC = 0x0002;
138 private static final int GPS_DELETE_POSITION = 0x0004;
139 private static final int GPS_DELETE_TIME = 0x0008;
140 private static final int GPS_DELETE_IONO = 0x0010;
141 private static final int GPS_DELETE_UTC = 0x0020;
142 private static final int GPS_DELETE_HEALTH = 0x0040;
143 private static final int GPS_DELETE_SVDIR = 0x0080;
144 private static final int GPS_DELETE_SVSTEER = 0x0100;
145 private static final int GPS_DELETE_SADATA = 0x0200;
146 private static final int GPS_DELETE_RTI = 0x0400;
147 private static final int GPS_DELETE_CELLDB_INFO = 0x8000;
148 private static final int GPS_DELETE_ALL = 0xFFFF;
149
Mike Lockwood04598b62010-04-14 17:17:24 -0400150 // The GPS_CAPABILITY_* flags must match the values in gps.h
151 private static final int GPS_CAPABILITY_SCHEDULING = 0x0000001;
152 private static final int GPS_CAPABILITY_MSB = 0x0000002;
153 private static final int GPS_CAPABILITY_MSA = 0x0000004;
154 private static final int GPS_CAPABILITY_SINGLE_SHOT = 0x0000008;
Mike Lockwood9b9fb5c2011-06-29 15:09:40 -0400155 private static final int GPS_CAPABILITY_ON_DEMAND_TIME = 0x0000010;
Mike Lockwood04598b62010-04-14 17:17:24 -0400156
Mike Lockwoode3635c92009-05-11 08:38:02 -0400157 // these need to match AGpsType enum in gps.h
158 private static final int AGPS_TYPE_SUPL = 1;
159 private static final int AGPS_TYPE_C2K = 2;
160
161 // for mAGpsDataConnectionState
162 private static final int AGPS_DATA_CONNECTION_CLOSED = 0;
163 private static final int AGPS_DATA_CONNECTION_OPENING = 1;
164 private static final int AGPS_DATA_CONNECTION_OPEN = 2;
Mike Lockwood58bda982009-04-14 16:25:07 -0400165
Mike Lockwood62a8fc12010-03-22 14:23:26 -0400166 // Handler messages
167 private static final int CHECK_LOCATION = 1;
168 private static final int ENABLE = 2;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700169 private static final int SET_REQUEST = 3;
Mike Lockwood62a8fc12010-03-22 14:23:26 -0400170 private static final int UPDATE_NETWORK_STATE = 4;
171 private static final int INJECT_NTP_TIME = 5;
172 private static final int DOWNLOAD_XTRA_DATA = 6;
173 private static final int UPDATE_LOCATION = 7;
174 private static final int ADD_LISTENER = 8;
175 private static final int REMOVE_LISTENER = 9;
Kevin Tang40e1baf2012-01-10 14:32:44 -0800176 private static final int INJECT_NTP_TIME_FINISHED = 10;
177 private static final int DOWNLOAD_XTRA_DATA_FINISHED = 11;
Mike Lockwood62a8fc12010-03-22 14:23:26 -0400178
Miguel Torroja1e84da82010-07-27 07:02:24 +0200179 // Request setid
180 private static final int AGPS_RIL_REQUEST_SETID_IMSI = 1;
181 private static final int AGPS_RIL_REQUEST_SETID_MSISDN = 2;
182
183 // Request ref location
184 private static final int AGPS_RIL_REQUEST_REFLOC_CELLID = 1;
185 private static final int AGPS_RIL_REQUEST_REFLOC_MAC = 2;
186
187 // ref. location info
188 private static final int AGPS_REF_LOCATION_TYPE_GSM_CELLID = 1;
189 private static final int AGPS_REF_LOCATION_TYPE_UMTS_CELLID = 2;
190 private static final int AGPS_REG_LOCATION_TYPE_MAC = 3;
191
192 // set id info
193 private static final int AGPS_SETID_TYPE_NONE = 0;
194 private static final int AGPS_SETID_TYPE_IMSI = 1;
195 private static final int AGPS_SETID_TYPE_MSISDN = 2;
196
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800197 private static final String PROPERTIES_FILE = "/etc/gps.conf";
198
destradaa0682809a2013-08-12 18:50:30 -0700199 private static final int GPS_GEOFENCE_UNAVAILABLE = 1<<0L;
200 private static final int GPS_GEOFENCE_AVAILABLE = 1<<1L;
201
202 // GPS Geofence errors. Should match gps.h constants.
203 private static final int GPS_GEOFENCE_OPERATION_SUCCESS = 0;
204 private static final int GPS_GEOFENCE_ERROR_TOO_MANY_GEOFENCES = 100;
205 private static final int GPS_GEOFENCE_ERROR_ID_EXISTS = -101;
206 private static final int GPS_GEOFENCE_ERROR_ID_UNKNOWN = -102;
207 private static final int GPS_GEOFENCE_ERROR_INVALID_TRANSITION = -103;
208 private static final int GPS_GEOFENCE_ERROR_GENERIC = -149;
209
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700210 /** simpler wrapper for ProviderRequest + Worksource */
211 private static class GpsRequest {
212 public ProviderRequest request;
213 public WorkSource source;
214 public GpsRequest(ProviderRequest request, WorkSource source) {
215 this.request = request;
216 this.source = source;
217 }
218 }
219
220 private Object mLock = new Object();
221
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800222 private int mLocationFlags = LOCATION_INVALID;
223
224 // current status
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400225 private int mStatus = LocationProvider.TEMPORARILY_UNAVAILABLE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800226
227 // time for last status update
228 private long mStatusUpdateTime = SystemClock.elapsedRealtime();
Mike Lockwoodd53ba012010-04-15 20:41:26 -0400229
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800230 // turn off GPS fix icon if we haven't received a fix in 10 seconds
Mike Lockwood04598b62010-04-14 17:17:24 -0400231 private static final long RECENT_FIX_TIMEOUT = 10 * 1000;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800232
Mike Lockwood0632ca72009-05-14 15:51:03 -0400233 // stop trying if we do not receive a fix within 60 seconds
Mike Lockwood04598b62010-04-14 17:17:24 -0400234 private static final int NO_FIX_TIMEOUT = 60 * 1000;
Mike Lockwood0632ca72009-05-14 15:51:03 -0400235
Nick Pellyb041f232012-05-07 17:12:25 -0700236 // if the fix interval is below this we leave GPS on,
237 // if above then we cycle the GPS driver.
238 // Typical hot TTTF is ~5 seconds, so 10 seconds seems sane.
239 private static final int GPS_POLLING_THRESHOLD_INTERVAL = 10 * 1000;
240
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700241 // how often to request NTP time, in milliseconds
242 // current setting 24 hours
243 private static final long NTP_INTERVAL = 24*60*60*1000;
244 // how long to wait if we have a network error in NTP or XTRA downloading
245 // current setting - 5 minutes
246 private static final long RETRY_INTERVAL = 5*60*1000;
247
248 // true if we are enabled, protected by this
249 private boolean mEnabled;
250
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800251 // true if we have network connectivity
252 private boolean mNetworkAvailable;
253
Kevin Tang40e1baf2012-01-10 14:32:44 -0800254 // states for injecting ntp and downloading xtra data
255 private static final int STATE_PENDING_NETWORK = 0;
256 private static final int STATE_DOWNLOADING = 1;
257 private static final int STATE_IDLE = 2;
258
Mike Lockwood62a8fc12010-03-22 14:23:26 -0400259 // flags to trigger NTP or XTRA data download when network becomes available
260 // initialized to true so we do NTP and XTRA when the network comes up after booting
Kevin Tang40e1baf2012-01-10 14:32:44 -0800261 private int mInjectNtpTimePending = STATE_PENDING_NETWORK;
262 private int mDownloadXtraDataPending = STATE_PENDING_NETWORK;
Mike Lockwood62a8fc12010-03-22 14:23:26 -0400263
Mike Lockwood9b9fb5c2011-06-29 15:09:40 -0400264 // set to true if the GPS engine does not do on-demand NTP time requests
265 private boolean mPeriodicTimeInjection;
266
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800267 // true if GPS is navigating
268 private boolean mNavigating;
Mike Lockwoodcf1d8cb2010-01-20 10:14:54 -0500269
270 // true if GPS engine is on
271 private boolean mEngineOn;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700272
Mike Lockwood04598b62010-04-14 17:17:24 -0400273 // requested frequency of fixes, in milliseconds
274 private int mFixInterval = 1000;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800275
276 // true if we started navigation
277 private boolean mStarted;
278
Stan Chesnutt1d72d8c2013-04-15 19:18:02 -0700279 // true if single shot request is in progress
280 private boolean mSingleShot;
281
Mike Lockwood04598b62010-04-14 17:17:24 -0400282 // capabilities of the GPS engine
283 private int mEngineCapabilities;
284
Mike Lockwood1a1cd3a2010-08-17 07:42:54 -0400285 // true if XTRA is supported
286 private boolean mSupportsXtra;
287
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800288 // for calculating time to first fix
289 private long mFixRequestTime = 0;
290 // time to first fix for most recent session
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700291 private int mTimeToFirstFix = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800292 // time we received our last fix
293 private long mLastFixTime;
294
Mike Lockwood04598b62010-04-14 17:17:24 -0400295 private int mPositionMode;
296
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800297 // properties loaded from PROPERTIES_FILE
298 private Properties mProperties;
Mike Lockwood734d6032009-07-28 18:30:25 -0700299 private String mSuplServerHost;
300 private int mSuplServerPort;
301 private String mC2KServerHost;
302 private int mC2KServerPort;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800303
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400304 private final Context mContext;
Jeff Sharkey104344e2011-07-10 14:20:41 -0700305 private final NtpTrustedTime mNtpTime;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700306 private final ILocationManager mILocationManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800307 private Location mLocation = new Location(LocationManager.GPS_PROVIDER);
308 private Bundle mLocationExtras = new Bundle();
309 private ArrayList<Listener> mListeners = new ArrayList<Listener>();
Mike Lockwood62a8fc12010-03-22 14:23:26 -0400310
Victoria Lease5c24fd02012-10-01 11:00:50 -0700311 // Handler for processing events
Mike Lockwood62a8fc12010-03-22 14:23:26 -0400312 private Handler mHandler;
The Android Open Source Project10592532009-03-18 17:39:46 -0700313
Mike Lockwoode3635c92009-05-11 08:38:02 -0400314 private String mAGpsApn;
315 private int mAGpsDataConnectionState;
Stephen Li8efd74d2011-03-01 20:56:00 -0800316 private int mAGpsDataConnectionIpAddr;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400317 private final ConnectivityManager mConnMgr;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700318 private final GpsNetInitiatedHandler mNIHandler;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400319
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400320 // Wakelocks
321 private final static String WAKELOCK_KEY = "GpsLocationProvider";
322 private final PowerManager.WakeLock mWakeLock;
323
Mike Lockwood29c84342009-05-06 14:01:15 -0400324 // Alarms
325 private final static String ALARM_WAKEUP = "com.android.internal.location.ALARM_WAKEUP";
Mike Lockwood0632ca72009-05-14 15:51:03 -0400326 private final static String ALARM_TIMEOUT = "com.android.internal.location.ALARM_TIMEOUT";
Mike Lockwood29c84342009-05-06 14:01:15 -0400327 private final AlarmManager mAlarmManager;
328 private final PendingIntent mWakeupIntent;
Mike Lockwood0632ca72009-05-14 15:51:03 -0400329 private final PendingIntent mTimeoutIntent;
Mike Lockwood29c84342009-05-06 14:01:15 -0400330
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800331 private final IAppOpsService mAppOpsService;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400332 private final IBatteryStats mBatteryStats;
The Android Open Source Project10592532009-03-18 17:39:46 -0700333
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700334 // only modified on handler thread
Dianne Hackborn002a54e2013-01-10 17:34:55 -0800335 private WorkSource mClientSource = new WorkSource();
Mike Lockwoodf1218be2010-01-29 09:20:06 -0500336
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -0700337 private GeofenceHardwareImpl mGeofenceHardwareImpl;
338
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400339 private final IGpsStatusProvider mGpsStatusProvider = new IGpsStatusProvider.Stub() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700340 @Override
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400341 public void addGpsStatusListener(IGpsStatusListener listener) throws RemoteException {
342 if (listener == null) {
343 throw new NullPointerException("listener is null in addGpsStatusListener");
344 }
345
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700346 synchronized (mListeners) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400347 IBinder binder = listener.asBinder();
348 int size = mListeners.size();
349 for (int i = 0; i < size; i++) {
350 Listener test = mListeners.get(i);
351 if (binder.equals(test.mListener.asBinder())) {
352 // listener already added
353 return;
354 }
355 }
356
357 Listener l = new Listener(listener);
358 binder.linkToDeath(l, 0);
359 mListeners.add(l);
360 }
361 }
362
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700363 @Override
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400364 public void removeGpsStatusListener(IGpsStatusListener listener) {
365 if (listener == null) {
366 throw new NullPointerException("listener is null in addGpsStatusListener");
367 }
368
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700369 synchronized (mListeners) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400370 IBinder binder = listener.asBinder();
371 Listener l = null;
372 int size = mListeners.size();
373 for (int i = 0; i < size && l == null; i++) {
374 Listener test = mListeners.get(i);
375 if (binder.equals(test.mListener.asBinder())) {
376 l = test;
377 }
378 }
379
380 if (l != null) {
381 mListeners.remove(l);
382 binder.unlinkToDeath(l, 0);
383 }
384 }
385 }
386 };
387
388 public IGpsStatusProvider getGpsStatusProvider() {
389 return mGpsStatusProvider;
390 }
391
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -0700392 public IGpsGeofenceHardware getGpsGeofenceProxy() {
393 return mGpsGeofenceBinder;
394 }
395
Mike Lockwood29c84342009-05-06 14:01:15 -0400396 private final BroadcastReceiver mBroadcastReciever = new BroadcastReceiver() {
The Android Open Source Project10592532009-03-18 17:39:46 -0700397 @Override public void onReceive(Context context, Intent intent) {
398 String action = intent.getAction();
399
Mike Lockwood29c84342009-05-06 14:01:15 -0400400 if (action.equals(ALARM_WAKEUP)) {
401 if (DEBUG) Log.d(TAG, "ALARM_WAKEUP");
Stan Chesnutt1d72d8c2013-04-15 19:18:02 -0700402 startNavigating(false);
Mike Lockwood0632ca72009-05-14 15:51:03 -0400403 } else if (action.equals(ALARM_TIMEOUT)) {
404 if (DEBUG) Log.d(TAG, "ALARM_TIMEOUT");
405 hibernate();
Miguel Torroja1e84da82010-07-27 07:02:24 +0200406 } else if (action.equals(Intents.DATA_SMS_RECEIVED_ACTION)) {
407 checkSmsSuplInit(intent);
408 } else if (action.equals(Intents.WAP_PUSH_RECEIVED_ACTION)) {
409 checkWapSuplInit(intent);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700410 } else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
411 int networkState;
412 if (intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false)) {
413 networkState = LocationProvider.TEMPORARILY_UNAVAILABLE;
414 } else {
415 networkState = LocationProvider.AVAILABLE;
416 }
417
418 // retrieve NetworkInfo result for this UID
419 NetworkInfo info =
420 intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
421 ConnectivityManager connManager = (ConnectivityManager)
422 mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
423 info = connManager.getNetworkInfo(info.getType());
424
425 updateNetworkState(networkState, info);
Miguel Torroja1e84da82010-07-27 07:02:24 +0200426 }
The Android Open Source Project10592532009-03-18 17:39:46 -0700427 }
Mike Lockwood29c84342009-05-06 14:01:15 -0400428 };
The Android Open Source Project10592532009-03-18 17:39:46 -0700429
Miguel Torroja1e84da82010-07-27 07:02:24 +0200430 private void checkSmsSuplInit(Intent intent) {
431 SmsMessage[] messages = Intents.getMessagesFromIntent(intent);
432 for (int i=0; i <messages.length; i++) {
433 byte[] supl_init = messages[i].getUserData();
434 native_agps_ni_message(supl_init,supl_init.length);
435 }
436 }
437
438 private void checkWapSuplInit(Intent intent) {
439 byte[] supl_init = (byte[]) intent.getExtra("data");
440 native_agps_ni_message(supl_init,supl_init.length);
441 }
442
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800443 public static boolean isSupported() {
444 return native_is_supported();
445 }
446
Victoria Lease5cd731a2012-12-19 15:04:21 -0800447 public GpsLocationProvider(Context context, ILocationManager ilocationManager,
448 Looper looper) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800449 mContext = context;
Jeff Sharkey104344e2011-07-10 14:20:41 -0700450 mNtpTime = NtpTrustedTime.getInstance(context);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700451 mILocationManager = ilocationManager;
Mike Lockwood79e642e2010-03-17 23:19:25 -0400452 mNIHandler = new GpsNetInitiatedHandler(context);
Mike Lockwood63598a02010-02-24 11:52:59 -0500453
454 mLocation.setExtras(mLocationExtras);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800455
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400456 // Create a wake lock
457 PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
458 mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700459 mWakeLock.setReferenceCounted(true);
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400460
Mike Lockwood29c84342009-05-06 14:01:15 -0400461 mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
462 mWakeupIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_WAKEUP), 0);
Mike Lockwood0632ca72009-05-14 15:51:03 -0400463 mTimeoutIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_TIMEOUT), 0);
Mike Lockwood29c84342009-05-06 14:01:15 -0400464
Mike Lockwood58bda982009-04-14 16:25:07 -0400465 mConnMgr = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
466
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800467 // App ops service to keep track of who is accessing the GPS
468 mAppOpsService = IAppOpsService.Stub.asInterface(ServiceManager.getService(
469 Context.APP_OPS_SERVICE));
470
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400471 // Battery statistics service to be notified when GPS turns on or off
Dianne Hackborn91268cf2013-06-13 19:06:50 -0700472 mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService(
473 BatteryStats.SERVICE_NAME));
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400474
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800475 mProperties = new Properties();
476 try {
477 File file = new File(PROPERTIES_FILE);
478 FileInputStream stream = new FileInputStream(file);
479 mProperties.load(stream);
480 stream.close();
Mike Lockwoode3635c92009-05-11 08:38:02 -0400481
Mike Lockwood734d6032009-07-28 18:30:25 -0700482 mSuplServerHost = mProperties.getProperty("SUPL_HOST");
Mike Lockwoode3635c92009-05-11 08:38:02 -0400483 String portString = mProperties.getProperty("SUPL_PORT");
Mike Lockwood734d6032009-07-28 18:30:25 -0700484 if (mSuplServerHost != null && portString != null) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700485 try {
Mike Lockwood734d6032009-07-28 18:30:25 -0700486 mSuplServerPort = Integer.parseInt(portString);
The Android Open Source Project10592532009-03-18 17:39:46 -0700487 } catch (NumberFormatException e) {
Mike Lockwoode3635c92009-05-11 08:38:02 -0400488 Log.e(TAG, "unable to parse SUPL_PORT: " + portString);
489 }
490 }
491
Mike Lockwood734d6032009-07-28 18:30:25 -0700492 mC2KServerHost = mProperties.getProperty("C2K_HOST");
Mike Lockwoode3635c92009-05-11 08:38:02 -0400493 portString = mProperties.getProperty("C2K_PORT");
Mike Lockwood734d6032009-07-28 18:30:25 -0700494 if (mC2KServerHost != null && portString != null) {
Mike Lockwoode3635c92009-05-11 08:38:02 -0400495 try {
Mike Lockwood734d6032009-07-28 18:30:25 -0700496 mC2KServerPort = Integer.parseInt(portString);
Mike Lockwoode3635c92009-05-11 08:38:02 -0400497 } catch (NumberFormatException e) {
498 Log.e(TAG, "unable to parse C2K_PORT: " + portString);
The Android Open Source Project10592532009-03-18 17:39:46 -0700499 }
500 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800501 } catch (IOException e) {
502 Log.w(TAG, "Could not open GPS configuration file " + PROPERTIES_FILE);
503 }
Mike Lockwood62a8fc12010-03-22 14:23:26 -0400504
Victoria Lease5c24fd02012-10-01 11:00:50 -0700505 // construct handler, listen for events
Victoria Lease5cd731a2012-12-19 15:04:21 -0800506 mHandler = new ProviderHandler(looper);
Victoria Lease5c24fd02012-10-01 11:00:50 -0700507 listenForBroadcasts();
508
509 // also listen for PASSIVE_PROVIDER updates
510 mHandler.post(new Runnable() {
511 @Override
512 public void run() {
513 LocationManager locManager =
514 (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
David Christie9e9ce922013-09-12 13:04:32 -0700515 final long minTime = 0;
516 final float minDistance = 0;
517 final boolean oneShot = false;
518 LocationRequest request = LocationRequest.createFromDeprecatedProvider(
519 LocationManager.PASSIVE_PROVIDER,
520 minTime,
521 minDistance,
522 oneShot);
523 // Don't keep track of this request since it's done on behalf of other clients
524 // (which are kept track of separately).
525 request.setHideFromAppOps(true);
526 locManager.requestLocationUpdates(
527 request,
528 new NetworkLocationListener(),
529 mHandler.getLooper());
Mike Lockwood89096312010-03-24 10:14:55 -0400530 }
Victoria Lease5c24fd02012-10-01 11:00:50 -0700531 });
Mike Lockwood62a8fc12010-03-22 14:23:26 -0400532 }
533
Victoria Lease5c24fd02012-10-01 11:00:50 -0700534 private void listenForBroadcasts() {
Mike Lockwood62a8fc12010-03-22 14:23:26 -0400535 IntentFilter intentFilter = new IntentFilter();
Victoria Lease5c24fd02012-10-01 11:00:50 -0700536 intentFilter.addAction(Intents.DATA_SMS_RECEIVED_ACTION);
537 intentFilter.addDataScheme("sms");
538 intentFilter.addDataAuthority("localhost","7275");
539 mContext.registerReceiver(mBroadcastReciever, intentFilter, null, mHandler);
540
541 intentFilter = new IntentFilter();
542 intentFilter.addAction(Intents.WAP_PUSH_RECEIVED_ACTION);
543 try {
544 intentFilter.addDataType("application/vnd.omaloc-supl-init");
545 } catch (IntentFilter.MalformedMimeTypeException e) {
546 Log.w(TAG, "Malformed SUPL init mime type");
547 }
548 mContext.registerReceiver(mBroadcastReciever, intentFilter, null, mHandler);
549
550 intentFilter = new IntentFilter();
Mike Lockwood62a8fc12010-03-22 14:23:26 -0400551 intentFilter.addAction(ALARM_WAKEUP);
552 intentFilter.addAction(ALARM_TIMEOUT);
Brian Muramatsub94b41f2012-08-21 16:30:57 -0700553 intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
Victoria Lease5c24fd02012-10-01 11:00:50 -0700554 mContext.registerReceiver(mBroadcastReciever, intentFilter, null, mHandler);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800555 }
556
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800557 /**
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500558 * Returns the name of this provider.
559 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700560 @Override
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500561 public String getName() {
562 return LocationManager.GPS_PROVIDER;
563 }
564
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700565 @Override
566 public ProviderProperties getProperties() {
567 return PROPERTIES;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800568 }
569
Mike Lockwood03d24672009-10-08 15:45:03 -0400570 public void updateNetworkState(int state, NetworkInfo info) {
Mike Lockwood98e48692010-04-07 16:32:51 -0400571 sendMessage(UPDATE_NETWORK_STATE, state, info);
Mike Lockwood62a8fc12010-03-22 14:23:26 -0400572 }
573
574 private void handleUpdateNetworkState(int state, NetworkInfo info) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800575 mNetworkAvailable = (state == LocationProvider.AVAILABLE);
576
Joe Onoratof5d95cb2010-01-07 21:48:32 -0500577 if (DEBUG) {
Mike Lockwood03d24672009-10-08 15:45:03 -0400578 Log.d(TAG, "updateNetworkState " + (mNetworkAvailable ? "available" : "unavailable")
579 + " info: " + info);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800580 }
Mike Lockwood03d24672009-10-08 15:45:03 -0400581
Mike Lockwood50130bb2010-10-11 06:22:50 -0400582 if (info != null) {
Jeff Brownbf6f6f92012-09-25 15:03:20 -0700583 boolean dataEnabled = Settings.Global.getInt(mContext.getContentResolver(),
584 Settings.Global.MOBILE_DATA, 1) == 1;
Kevin Tanga5fe6b22011-06-05 14:25:16 -0700585 boolean networkAvailable = info.isAvailable() && dataEnabled;
586 String defaultApn = getSelectedApn();
587 if (defaultApn == null) {
588 defaultApn = "dummy-apn";
589 }
590
Mike Lockwood50130bb2010-10-11 06:22:50 -0400591 native_update_network_state(info.isConnected(), info.getType(),
Kevin Tanga5fe6b22011-06-05 14:25:16 -0700592 info.isRoaming(), networkAvailable,
593 info.getExtraInfo(), defaultApn);
Mike Lockwood50130bb2010-10-11 06:22:50 -0400594 }
595
Mike Lockwood03d24672009-10-08 15:45:03 -0400596 if (info != null && info.getType() == ConnectivityManager.TYPE_MOBILE_SUPL
597 && mAGpsDataConnectionState == AGPS_DATA_CONNECTION_OPENING) {
598 String apnName = info.getExtraInfo();
Stephen Li83b69712011-01-25 18:47:28 -0800599 if (mNetworkAvailable) {
600 if (apnName == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700601 /* Assign a dummy value in the case of C2K as otherwise we will have a runtime
Stephen Li83b69712011-01-25 18:47:28 -0800602 exception in the following call to native_agps_data_conn_open*/
603 apnName = "dummy-apn";
604 }
Mike Lockwood03d24672009-10-08 15:45:03 -0400605 mAGpsApn = apnName;
Stephen Li8efd74d2011-03-01 20:56:00 -0800606 if (DEBUG) Log.d(TAG, "mAGpsDataConnectionIpAddr " + mAGpsDataConnectionIpAddr);
607 if (mAGpsDataConnectionIpAddr != 0xffffffff) {
608 boolean route_result;
609 if (DEBUG) Log.d(TAG, "call requestRouteToHost");
610 route_result = mConnMgr.requestRouteToHost(ConnectivityManager.TYPE_MOBILE_SUPL,
611 mAGpsDataConnectionIpAddr);
612 if (route_result == false) Log.d(TAG, "call requestRouteToHost failed");
613 }
Mike Lockwood03d24672009-10-08 15:45:03 -0400614 if (DEBUG) Log.d(TAG, "call native_agps_data_conn_open");
615 native_agps_data_conn_open(apnName);
616 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPEN;
617 } else {
618 if (DEBUG) Log.d(TAG, "call native_agps_data_conn_failed");
619 mAGpsApn = null;
620 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_CLOSED;
621 native_agps_data_conn_failed();
622 }
623 }
624
Mike Lockwood62a8fc12010-03-22 14:23:26 -0400625 if (mNetworkAvailable) {
Kevin Tang40e1baf2012-01-10 14:32:44 -0800626 if (mInjectNtpTimePending == STATE_PENDING_NETWORK) {
Mike Lockwood98e48692010-04-07 16:32:51 -0400627 sendMessage(INJECT_NTP_TIME, 0, null);
Mike Lockwood62a8fc12010-03-22 14:23:26 -0400628 }
Kevin Tang40e1baf2012-01-10 14:32:44 -0800629 if (mDownloadXtraDataPending == STATE_PENDING_NETWORK) {
Mike Lockwood98e48692010-04-07 16:32:51 -0400630 sendMessage(DOWNLOAD_XTRA_DATA, 0, null);
Mike Lockwood62a8fc12010-03-22 14:23:26 -0400631 }
632 }
633 }
634
635 private void handleInjectNtpTime() {
Kevin Tang40e1baf2012-01-10 14:32:44 -0800636 if (mInjectNtpTimePending == STATE_DOWNLOADING) {
637 // already downloading data
Mike Lockwood62a8fc12010-03-22 14:23:26 -0400638 return;
639 }
Kevin Tang40e1baf2012-01-10 14:32:44 -0800640 if (!mNetworkAvailable) {
641 // try again when network is up
642 mInjectNtpTimePending = STATE_PENDING_NETWORK;
643 return;
Jeff Sharkey104344e2011-07-10 14:20:41 -0700644 }
Kevin Tang40e1baf2012-01-10 14:32:44 -0800645 mInjectNtpTimePending = STATE_DOWNLOADING;
Jeff Sharkey104344e2011-07-10 14:20:41 -0700646
Jeff Brown028872f2012-08-25 13:07:01 -0700647 // hold wake lock while task runs
648 mWakeLock.acquire();
Kevin Tang40e1baf2012-01-10 14:32:44 -0800649 AsyncTask.THREAD_POOL_EXECUTOR.execute(new Runnable() {
650 @Override
651 public void run() {
652 long delay;
Mike Lockwood62a8fc12010-03-22 14:23:26 -0400653
Kevin Tang40e1baf2012-01-10 14:32:44 -0800654 // force refresh NTP cache when outdated
655 if (mNtpTime.getCacheAge() >= NTP_INTERVAL) {
656 mNtpTime.forceRefresh();
657 }
Mike Lockwood62a8fc12010-03-22 14:23:26 -0400658
Kevin Tang40e1baf2012-01-10 14:32:44 -0800659 // only update when NTP time is fresh
660 if (mNtpTime.getCacheAge() < NTP_INTERVAL) {
661 long time = mNtpTime.getCachedNtpTime();
662 long timeReference = mNtpTime.getCachedNtpTimeReference();
663 long certainty = mNtpTime.getCacheCertainty();
664 long now = System.currentTimeMillis();
Mike Lockwood62a8fc12010-03-22 14:23:26 -0400665
Kevin Tang40e1baf2012-01-10 14:32:44 -0800666 Log.d(TAG, "NTP server returned: "
667 + time + " (" + new Date(time)
668 + ") reference: " + timeReference
669 + " certainty: " + certainty
670 + " system time offset: " + (time - now));
671
672 native_inject_time(time, timeReference, (int) certainty);
673 delay = NTP_INTERVAL;
674 } else {
675 if (DEBUG) Log.d(TAG, "requestTime failed");
676 delay = RETRY_INTERVAL;
677 }
678
Jeff Brown028872f2012-08-25 13:07:01 -0700679 sendMessage(INJECT_NTP_TIME_FINISHED, 0, null);
Kevin Tang40e1baf2012-01-10 14:32:44 -0800680
681 if (mPeriodicTimeInjection) {
682 // send delayed message for next NTP injection
683 // since this is delayed and not urgent we do not hold a wake lock here
Jeff Brown028872f2012-08-25 13:07:01 -0700684 mHandler.sendEmptyMessageDelayed(INJECT_NTP_TIME, delay);
Kevin Tang40e1baf2012-01-10 14:32:44 -0800685 }
Jeff Brown028872f2012-08-25 13:07:01 -0700686
687 // release wake lock held by task
688 mWakeLock.release();
Kevin Tang40e1baf2012-01-10 14:32:44 -0800689 }
690 });
Mike Lockwood62a8fc12010-03-22 14:23:26 -0400691 }
692
693 private void handleDownloadXtraData() {
Kevin Tang40e1baf2012-01-10 14:32:44 -0800694 if (mDownloadXtraDataPending == STATE_DOWNLOADING) {
695 // already downloading data
Mike Lockwood62a8fc12010-03-22 14:23:26 -0400696 return;
697 }
Kevin Tang40e1baf2012-01-10 14:32:44 -0800698 if (!mNetworkAvailable) {
699 // try again when network is up
700 mDownloadXtraDataPending = STATE_PENDING_NETWORK;
701 return;
Mike Lockwood62a8fc12010-03-22 14:23:26 -0400702 }
Kevin Tang40e1baf2012-01-10 14:32:44 -0800703 mDownloadXtraDataPending = STATE_DOWNLOADING;
704
Jeff Brown028872f2012-08-25 13:07:01 -0700705 // hold wake lock while task runs
706 mWakeLock.acquire();
Kevin Tang40e1baf2012-01-10 14:32:44 -0800707 AsyncTask.THREAD_POOL_EXECUTOR.execute(new Runnable() {
708 @Override
709 public void run() {
710 GpsXtraDownloader xtraDownloader = new GpsXtraDownloader(mContext, mProperties);
711 byte[] data = xtraDownloader.downloadXtraData();
712 if (data != null) {
713 if (DEBUG) {
714 Log.d(TAG, "calling native_inject_xtra_data");
715 }
716 native_inject_xtra_data(data, data.length);
717 }
718
Jeff Brown028872f2012-08-25 13:07:01 -0700719 sendMessage(DOWNLOAD_XTRA_DATA_FINISHED, 0, null);
Kevin Tang40e1baf2012-01-10 14:32:44 -0800720
721 if (data == null) {
722 // try again later
723 // since this is delayed and not urgent we do not hold a wake lock here
Jeff Brown028872f2012-08-25 13:07:01 -0700724 mHandler.sendEmptyMessageDelayed(DOWNLOAD_XTRA_DATA, RETRY_INTERVAL);
Kevin Tang40e1baf2012-01-10 14:32:44 -0800725 }
Kevin Tang40e1baf2012-01-10 14:32:44 -0800726
Jeff Brown028872f2012-08-25 13:07:01 -0700727 // release wake lock held by task
728 mWakeLock.release();
729 }
Kevin Tang40e1baf2012-01-10 14:32:44 -0800730 });
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800731 }
732
Mike Lockwood62a8fc12010-03-22 14:23:26 -0400733 private void handleUpdateLocation(Location location) {
Mike Lockwoodd26ce0d2009-06-11 12:25:46 -0400734 if (location.hasAccuracy()) {
735 native_inject_location(location.getLatitude(), location.getLongitude(),
736 location.getAccuracy());
737 }
Mike Lockwoodfd6e5f02009-05-21 11:28:20 -0400738 }
739
740 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800741 * Enables this provider. When enabled, calls to getStatus()
Mike Lockwood4e50b782009-04-03 08:24:43 -0700742 * must be handled. Hardware may be started up
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800743 * when the provider is enabled.
744 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700745 @Override
Mike Lockwood62a8fc12010-03-22 14:23:26 -0400746 public void enable() {
Laurent Tu7b5aeca2013-01-24 15:10:24 -0800747 synchronized (mLock) {
748 if (mEnabled) return;
749 mEnabled = true;
750 }
751
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700752 sendMessage(ENABLE, 1, null);
Mike Lockwood62a8fc12010-03-22 14:23:26 -0400753 }
754
755 private void handleEnable() {
756 if (DEBUG) Log.d(TAG, "handleEnable");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800757
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700758 boolean enabled = native_init();
759
760 if (enabled) {
Mike Lockwood1a1cd3a2010-08-17 07:42:54 -0400761 mSupportsXtra = native_supports_xtra();
Mike Lockwood734d6032009-07-28 18:30:25 -0700762 if (mSuplServerHost != null) {
763 native_set_agps_server(AGPS_TYPE_SUPL, mSuplServerHost, mSuplServerPort);
764 }
765 if (mC2KServerHost != null) {
766 native_set_agps_server(AGPS_TYPE_C2K, mC2KServerHost, mC2KServerPort);
767 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800768 } else {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700769 synchronized (mLock) {
770 mEnabled = false;
771 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800772 Log.w(TAG, "Failed to enable location provider");
773 }
774 }
775
776 /**
777 * Disables this provider. When disabled, calls to getStatus()
Mike Lockwood4e50b782009-04-03 08:24:43 -0700778 * need not be handled. Hardware may be shut
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800779 * down while the provider is disabled.
780 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700781 @Override
Mike Lockwood62a8fc12010-03-22 14:23:26 -0400782 public void disable() {
Laurent Tu7b5aeca2013-01-24 15:10:24 -0800783 synchronized (mLock) {
784 if (!mEnabled) return;
785 mEnabled = false;
786 }
787
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700788 sendMessage(ENABLE, 0, null);
Mike Lockwood62a8fc12010-03-22 14:23:26 -0400789 }
790
791 private void handleDisable() {
Mike Lockwood89096312010-03-24 10:14:55 -0400792 if (DEBUG) Log.d(TAG, "handleDisable");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800793
David Christie3bc26142013-12-19 14:53:44 -0800794 updateClientUids(new WorkSource());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800795 stopNavigating();
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700796 mAlarmManager.cancel(mWakeupIntent);
797 mAlarmManager.cancel(mTimeoutIntent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800798
Mike Lockwoodcf1d8cb2010-01-20 10:14:54 -0500799 // do this before releasing wakelock
800 native_cleanup();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800801 }
802
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700803 @Override
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500804 public boolean isEnabled() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700805 synchronized (mLock) {
806 return mEnabled;
807 }
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500808 }
809
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700810 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800811 public int getStatus(Bundle extras) {
812 if (extras != null) {
813 extras.putInt("satellites", mSvCount);
814 }
815 return mStatus;
816 }
817
818 private void updateStatus(int status, int svCount) {
819 if (status != mStatus || svCount != mSvCount) {
820 mStatus = status;
821 mSvCount = svCount;
822 mLocationExtras.putInt("satellites", svCount);
823 mStatusUpdateTime = SystemClock.elapsedRealtime();
824 }
825 }
826
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700827 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800828 public long getStatusUpdateTime() {
829 return mStatusUpdateTime;
830 }
831
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700832 @Override
833 public void setRequest(ProviderRequest request, WorkSource source) {
834 sendMessage(SET_REQUEST, 0, new GpsRequest(request, source));
Mike Lockwood62a8fc12010-03-22 14:23:26 -0400835 }
836
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700837 private void handleSetRequest(ProviderRequest request, WorkSource source) {
Stan Chesnutt1d72d8c2013-04-15 19:18:02 -0700838 boolean singleShot = false;
839
840 // see if the request is for a single update
841 if (request.locationRequests != null && request.locationRequests.size() > 0) {
842 // if any request has zero or more than one updates
843 // requested, then this is not single-shot mode
844 singleShot = true;
845
846 for (LocationRequest lr : request.locationRequests) {
847 if (lr.getNumUpdates() != 1) {
848 singleShot = false;
849 }
850 }
851 }
852
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700853 if (DEBUG) Log.d(TAG, "setRequest " + request);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700854 if (request.reportLocation) {
855 // update client uids
Dianne Hackborn002a54e2013-01-10 17:34:55 -0800856 updateClientUids(source);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800857
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700858 mFixInterval = (int) request.interval;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700859
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700860 // check for overflow
861 if (mFixInterval != request.interval) {
862 Log.w(TAG, "interval overflow: " + request.interval);
863 mFixInterval = Integer.MAX_VALUE;
864 }
Mike Lockwood03ca2162010-04-01 08:10:09 -0700865
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700866 // apply request to GPS engine
Mike Lockwood04598b62010-04-14 17:17:24 -0400867 if (mStarted && hasCapability(GPS_CAPABILITY_SCHEDULING)) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700868 // change period
Mike Lockwood04598b62010-04-14 17:17:24 -0400869 if (!native_set_position_mode(mPositionMode, GPS_POSITION_RECURRENCE_PERIODIC,
870 mFixInterval, 0, 0)) {
871 Log.e(TAG, "set_position_mode failed in setMinTime()");
872 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700873 } else if (!mStarted) {
874 // start GPS
Stan Chesnutt1d72d8c2013-04-15 19:18:02 -0700875 startNavigating(singleShot);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800876 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700877 } else {
Dianne Hackborn002a54e2013-01-10 17:34:55 -0800878 updateClientUids(new WorkSource());
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700879
880 stopNavigating();
881 mAlarmManager.cancel(mWakeupIntent);
882 mAlarmManager.cancel(mTimeoutIntent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800883 }
884 }
885
886 private final class Listener implements IBinder.DeathRecipient {
887 final IGpsStatusListener mListener;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700888
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800889 Listener(IGpsStatusListener listener) {
890 mListener = listener;
891 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700892
893 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800894 public void binderDied() {
Joe Onoratof5d95cb2010-01-07 21:48:32 -0500895 if (DEBUG) Log.d(TAG, "GPS status listener died");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800896
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700897 synchronized (mListeners) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800898 mListeners.remove(this);
899 }
Suchi Amalapurapufff2fda2009-06-30 21:36:16 -0700900 if (mListener != null) {
901 mListener.asBinder().unlinkToDeath(this, 0);
902 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800903 }
904 }
905
Dianne Hackborn002a54e2013-01-10 17:34:55 -0800906 private void updateClientUids(WorkSource source) {
907 // Update work source.
908 WorkSource[] changes = mClientSource.setReturningDiffs(source);
Victoria Leaseea78b852013-01-15 10:39:28 -0800909 if (changes == null) {
910 return;
911 }
Dianne Hackborn002a54e2013-01-10 17:34:55 -0800912 WorkSource newWork = changes[0];
913 WorkSource goneWork = changes[1];
914
915 // Update sources that were not previously tracked.
916 if (newWork != null) {
917 int lastuid = -1;
918 for (int i=0; i<newWork.size(); i++) {
Dianne Hackborn2e418422009-06-22 20:00:17 -0700919 try {
Dianne Hackborn002a54e2013-01-10 17:34:55 -0800920 int uid = newWork.get(i);
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700921 mAppOpsService.startOperation(AppOpsManager.getToken(mAppOpsService),
922 AppOpsManager.OP_GPS, uid, newWork.getName(i));
Dianne Hackborn002a54e2013-01-10 17:34:55 -0800923 if (uid != lastuid) {
924 lastuid = uid;
925 mBatteryStats.noteStartGps(uid);
926 }
Dianne Hackborn2e418422009-06-22 20:00:17 -0700927 } catch (RemoteException e) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700928 Log.w(TAG, "RemoteException", e);
929 }
930 }
931 }
932
Dianne Hackborn002a54e2013-01-10 17:34:55 -0800933 // Update sources that are no longer tracked.
934 if (goneWork != null) {
935 int lastuid = -1;
936 for (int i=0; i<goneWork.size(); i++) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700937 try {
Dianne Hackborn002a54e2013-01-10 17:34:55 -0800938 int uid = goneWork.get(i);
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700939 mAppOpsService.finishOperation(AppOpsManager.getToken(mAppOpsService),
940 AppOpsManager.OP_GPS, uid, goneWork.getName(i));
Dianne Hackborn002a54e2013-01-10 17:34:55 -0800941 if (uid != lastuid) {
942 lastuid = uid;
943 mBatteryStats.noteStopGps(uid);
944 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700945 } catch (RemoteException e) {
946 Log.w(TAG, "RemoteException", e);
Dianne Hackborn2e418422009-06-22 20:00:17 -0700947 }
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400948 }
949 }
950 }
951
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700952 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800953 public boolean sendExtraCommand(String command, Bundle extras) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700954
Mike Lockwood63aa5a62010-04-14 19:21:31 -0400955 long identity = Binder.clearCallingIdentity();
956 boolean result = false;
957
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800958 if ("delete_aiding_data".equals(command)) {
Mike Lockwood63aa5a62010-04-14 19:21:31 -0400959 result = deleteAidingData(extras);
960 } else if ("force_time_injection".equals(command)) {
Mike Lockwood98e48692010-04-07 16:32:51 -0400961 sendMessage(INJECT_NTP_TIME, 0, null);
Mike Lockwood63aa5a62010-04-14 19:21:31 -0400962 result = true;
963 } else if ("force_xtra_injection".equals(command)) {
Mike Lockwood1a1cd3a2010-08-17 07:42:54 -0400964 if (mSupportsXtra) {
Mike Lockwood93bc44d2009-05-20 16:58:22 -0400965 xtraDownloadRequest();
Mike Lockwood63aa5a62010-04-14 19:21:31 -0400966 result = true;
Mike Lockwood93bc44d2009-05-20 16:58:22 -0400967 }
Mike Lockwood63aa5a62010-04-14 19:21:31 -0400968 } else {
969 Log.w(TAG, "sendExtraCommand: unknown command " + command);
Mike Lockwood93bc44d2009-05-20 16:58:22 -0400970 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700971
Mike Lockwood63aa5a62010-04-14 19:21:31 -0400972 Binder.restoreCallingIdentity(identity);
973 return result;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800974 }
975
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -0700976 private IGpsGeofenceHardware mGpsGeofenceBinder = new IGpsGeofenceHardware.Stub() {
977 public boolean isHardwareGeofenceSupported() {
978 return native_is_geofence_supported();
979 }
980
981 public boolean addCircularHardwareGeofence(int geofenceId, double latitude,
982 double longitude, double radius, int lastTransition, int monitorTransitions,
983 int notificationResponsiveness, int unknownTimer) {
984 return native_add_geofence(geofenceId, latitude, longitude, radius,
985 lastTransition, monitorTransitions, notificationResponsiveness, unknownTimer);
986 }
987
988 public boolean removeHardwareGeofence(int geofenceId) {
989 return native_remove_geofence(geofenceId);
990 }
991
992 public boolean pauseHardwareGeofence(int geofenceId) {
993 return native_pause_geofence(geofenceId);
994 }
995
996 public boolean resumeHardwareGeofence(int geofenceId, int monitorTransition) {
997 return native_resume_geofence(geofenceId, monitorTransition);
998 }
999 };
1000
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001001 private boolean deleteAidingData(Bundle extras) {
1002 int flags;
1003
1004 if (extras == null) {
1005 flags = GPS_DELETE_ALL;
1006 } else {
1007 flags = 0;
1008 if (extras.getBoolean("ephemeris")) flags |= GPS_DELETE_EPHEMERIS;
1009 if (extras.getBoolean("almanac")) flags |= GPS_DELETE_ALMANAC;
1010 if (extras.getBoolean("position")) flags |= GPS_DELETE_POSITION;
1011 if (extras.getBoolean("time")) flags |= GPS_DELETE_TIME;
1012 if (extras.getBoolean("iono")) flags |= GPS_DELETE_IONO;
1013 if (extras.getBoolean("utc")) flags |= GPS_DELETE_UTC;
1014 if (extras.getBoolean("health")) flags |= GPS_DELETE_HEALTH;
1015 if (extras.getBoolean("svdir")) flags |= GPS_DELETE_SVDIR;
1016 if (extras.getBoolean("svsteer")) flags |= GPS_DELETE_SVSTEER;
1017 if (extras.getBoolean("sadata")) flags |= GPS_DELETE_SADATA;
1018 if (extras.getBoolean("rti")) flags |= GPS_DELETE_RTI;
1019 if (extras.getBoolean("celldb-info")) flags |= GPS_DELETE_CELLDB_INFO;
1020 if (extras.getBoolean("all")) flags |= GPS_DELETE_ALL;
1021 }
1022
1023 if (flags != 0) {
1024 native_delete_aiding_data(flags);
1025 return true;
1026 }
1027
1028 return false;
1029 }
1030
Stan Chesnutt1d72d8c2013-04-15 19:18:02 -07001031 private void startNavigating(boolean singleShot) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001032 if (!mStarted) {
Stan Chesnutt1d72d8c2013-04-15 19:18:02 -07001033 if (DEBUG) Log.d(TAG, "startNavigating, singleShot is " + singleShot);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001034 mTimeToFirstFix = 0;
1035 mLastFixTime = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001036 mStarted = true;
Stan Chesnutt1d72d8c2013-04-15 19:18:02 -07001037 mSingleShot = singleShot;
Mike Lockwood03ca2162010-04-01 08:10:09 -07001038 mPositionMode = GPS_POSITION_MODE_STANDALONE;
1039
Jeff Brownbf6f6f92012-09-25 15:03:20 -07001040 if (Settings.Global.getInt(mContext.getContentResolver(),
1041 Settings.Global.ASSISTED_GPS_ENABLED, 1) != 0) {
Stan Chesnutt1d72d8c2013-04-15 19:18:02 -07001042 if (singleShot && hasCapability(GPS_CAPABILITY_MSA)) {
1043 mPositionMode = GPS_POSITION_MODE_MS_ASSISTED;
1044 } else if (hasCapability(GPS_CAPABILITY_MSB)) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07001045 mPositionMode = GPS_POSITION_MODE_MS_BASED;
1046 }
Mike Lockwoodbcab8df2009-06-25 16:39:09 -04001047 }
1048
Stan Chesnutt1d72d8c2013-04-15 19:18:02 -07001049 if (DEBUG) {
1050 String mode;
1051
1052 switch(mPositionMode) {
1053 case GPS_POSITION_MODE_STANDALONE:
1054 mode = "standalone";
1055 break;
1056 case GPS_POSITION_MODE_MS_ASSISTED:
1057 mode = "MS_ASSISTED";
1058 break;
1059 case GPS_POSITION_MODE_MS_BASED:
1060 mode = "MS_BASED";
1061 break;
1062 default:
1063 mode = "unknown";
1064 break;
1065 }
1066 Log.d(TAG, "setting position_mode to " + mode);
1067 }
1068
Mike Lockwood04598b62010-04-14 17:17:24 -04001069 int interval = (hasCapability(GPS_CAPABILITY_SCHEDULING) ? mFixInterval : 1000);
1070 if (!native_set_position_mode(mPositionMode, GPS_POSITION_RECURRENCE_PERIODIC,
1071 interval, 0, 0)) {
1072 mStarted = false;
1073 Log.e(TAG, "set_position_mode failed in startNavigating()");
1074 return;
1075 }
1076 if (!native_start()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001077 mStarted = false;
1078 Log.e(TAG, "native_start failed in startNavigating()");
Mike Lockwood0632ca72009-05-14 15:51:03 -04001079 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001080 }
1081
1082 // reset SV count to zero
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001083 updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE, 0);
Mike Lockwood29c84342009-05-06 14:01:15 -04001084 mFixRequestTime = System.currentTimeMillis();
Mike Lockwood04598b62010-04-14 17:17:24 -04001085 if (!hasCapability(GPS_CAPABILITY_SCHEDULING)) {
1086 // set timer to give up if we do not receive a fix within NO_FIX_TIMEOUT
1087 // and our fix interval is not short
1088 if (mFixInterval >= NO_FIX_TIMEOUT) {
1089 mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
1090 SystemClock.elapsedRealtime() + NO_FIX_TIMEOUT, mTimeoutIntent);
1091 }
Mike Lockwood0632ca72009-05-14 15:51:03 -04001092 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001093 }
1094 }
1095
Mike Lockwood62a8fc12010-03-22 14:23:26 -04001096 private void stopNavigating() {
Mike Lockwood29c84342009-05-06 14:01:15 -04001097 if (DEBUG) Log.d(TAG, "stopNavigating");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001098 if (mStarted) {
1099 mStarted = false;
Stan Chesnutt1d72d8c2013-04-15 19:18:02 -07001100 mSingleShot = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001101 native_stop();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001102 mTimeToFirstFix = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001103 mLastFixTime = 0;
1104 mLocationFlags = LOCATION_INVALID;
1105
1106 // reset SV count to zero
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001107 updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001108 }
1109 }
1110
Mike Lockwood0632ca72009-05-14 15:51:03 -04001111 private void hibernate() {
1112 // stop GPS until our next fix interval arrives
1113 stopNavigating();
Mike Lockwood0632ca72009-05-14 15:51:03 -04001114 mAlarmManager.cancel(mTimeoutIntent);
1115 mAlarmManager.cancel(mWakeupIntent);
1116 long now = SystemClock.elapsedRealtime();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001117 mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, now + mFixInterval, mWakeupIntent);
Mike Lockwood04598b62010-04-14 17:17:24 -04001118 }
1119
1120 private boolean hasCapability(int capability) {
1121 return ((mEngineCapabilities & capability) != 0);
Mike Lockwood0632ca72009-05-14 15:51:03 -04001122 }
1123
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -07001124
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001125 /**
1126 * called from native code to update our position.
1127 */
1128 private void reportLocation(int flags, double latitude, double longitude, double altitude,
1129 float speed, float bearing, float accuracy, long timestamp) {
Mike Lockwood29c84342009-05-06 14:01:15 -04001130 if (VERBOSE) Log.v(TAG, "reportLocation lat: " + latitude + " long: " + longitude +
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001131 " timestamp: " + timestamp);
1132
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001133 synchronized (mLocation) {
1134 mLocationFlags = flags;
1135 if ((flags & LOCATION_HAS_LAT_LONG) == LOCATION_HAS_LAT_LONG) {
1136 mLocation.setLatitude(latitude);
1137 mLocation.setLongitude(longitude);
1138 mLocation.setTime(timestamp);
Nick Pelly2eeeec22012-07-18 13:13:37 -07001139 // It would be nice to push the elapsed real-time timestamp
1140 // further down the stack, but this is still useful
Philip Milne41180122012-09-26 11:29:25 -07001141 mLocation.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001142 }
1143 if ((flags & LOCATION_HAS_ALTITUDE) == LOCATION_HAS_ALTITUDE) {
1144 mLocation.setAltitude(altitude);
1145 } else {
1146 mLocation.removeAltitude();
1147 }
1148 if ((flags & LOCATION_HAS_SPEED) == LOCATION_HAS_SPEED) {
1149 mLocation.setSpeed(speed);
1150 } else {
1151 mLocation.removeSpeed();
1152 }
1153 if ((flags & LOCATION_HAS_BEARING) == LOCATION_HAS_BEARING) {
1154 mLocation.setBearing(bearing);
1155 } else {
1156 mLocation.removeBearing();
1157 }
1158 if ((flags & LOCATION_HAS_ACCURACY) == LOCATION_HAS_ACCURACY) {
1159 mLocation.setAccuracy(accuracy);
1160 } else {
1161 mLocation.removeAccuracy();
1162 }
Sean Barbeauced2b2c2011-12-19 04:43:07 -05001163 mLocation.setExtras(mLocationExtras);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001164
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001165 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001166 mILocationManager.reportLocation(mLocation, false);
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001167 } catch (RemoteException e) {
1168 Log.e(TAG, "RemoteException calling reportLocation");
1169 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001170 }
1171
Hakan Gustavssonfa94ff02010-02-23 09:12:38 +01001172 mLastFixTime = System.currentTimeMillis();
1173 // report time to first fix
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001174 if (mTimeToFirstFix == 0 && (flags & LOCATION_HAS_LAT_LONG) == LOCATION_HAS_LAT_LONG) {
1175 mTimeToFirstFix = (int)(mLastFixTime - mFixRequestTime);
1176 if (DEBUG) Log.d(TAG, "TTFF: " + mTimeToFirstFix);
Hakan Gustavssonfa94ff02010-02-23 09:12:38 +01001177
1178 // notify status listeners
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001179 synchronized (mListeners) {
Hakan Gustavssonfa94ff02010-02-23 09:12:38 +01001180 int size = mListeners.size();
1181 for (int i = 0; i < size; i++) {
1182 Listener listener = mListeners.get(i);
1183 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001184 listener.mListener.onFirstFix(mTimeToFirstFix);
Hakan Gustavssonfa94ff02010-02-23 09:12:38 +01001185 } catch (RemoteException e) {
1186 Log.w(TAG, "RemoteException in stopNavigating");
1187 mListeners.remove(listener);
1188 // adjust for size of list changing
1189 size--;
1190 }
1191 }
1192 }
1193 }
1194
Stan Chesnutt1d72d8c2013-04-15 19:18:02 -07001195 if (mSingleShot) {
1196 stopNavigating();
1197 }
1198
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001199 if (mStarted && mStatus != LocationProvider.AVAILABLE) {
Mike Lockwoodd53ba012010-04-15 20:41:26 -04001200 // we want to time out if we do not receive a fix
Mike Lockwoodb7be5442010-02-24 14:34:50 -05001201 // within the time out and we are requesting infrequent fixes
Mike Lockwood04598b62010-04-14 17:17:24 -04001202 if (!hasCapability(GPS_CAPABILITY_SCHEDULING) && mFixInterval < NO_FIX_TIMEOUT) {
Mike Lockwoodb7be5442010-02-24 14:34:50 -05001203 mAlarmManager.cancel(mTimeoutIntent);
1204 }
1205
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001206 // send an intent to notify that the GPS is receiving fixes.
Mike Lockwood00b74272010-03-26 10:41:48 -04001207 Intent intent = new Intent(LocationManager.GPS_FIX_CHANGE_ACTION);
1208 intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, true);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001209 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001210 updateStatus(LocationProvider.AVAILABLE, mSvCount);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001211 }
Mike Lockwood29c84342009-05-06 14:01:15 -04001212
Nick Pellyb041f232012-05-07 17:12:25 -07001213 if (!hasCapability(GPS_CAPABILITY_SCHEDULING) && mStarted &&
1214 mFixInterval > GPS_POLLING_THRESHOLD_INTERVAL) {
Mike Lockwoodd53ba012010-04-15 20:41:26 -04001215 if (DEBUG) Log.d(TAG, "got fix, hibernating");
Mike Lockwood0632ca72009-05-14 15:51:03 -04001216 hibernate();
Mike Lockwood29c84342009-05-06 14:01:15 -04001217 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001218 }
1219
1220 /**
1221 * called from native code to update our status
1222 */
1223 private void reportStatus(int status) {
Mike Lockwoodb8d90332010-10-18 17:59:48 -04001224 if (DEBUG) Log.v(TAG, "reportStatus status: " + status);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001225
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001226 synchronized (mListeners) {
Dianne Hackborn2e418422009-06-22 20:00:17 -07001227 boolean wasNavigating = mNavigating;
Mike Lockwooddbd6fd82009-12-07 18:43:36 -05001228
Mike Lockwoodcf1d8cb2010-01-20 10:14:54 -05001229 switch (status) {
1230 case GPS_STATUS_SESSION_BEGIN:
1231 mNavigating = true;
Mike Lockwood271f9f12010-02-02 11:41:52 -05001232 mEngineOn = true;
Mike Lockwoodcf1d8cb2010-01-20 10:14:54 -05001233 break;
1234 case GPS_STATUS_SESSION_END:
1235 mNavigating = false;
1236 break;
1237 case GPS_STATUS_ENGINE_ON:
1238 mEngineOn = true;
1239 break;
1240 case GPS_STATUS_ENGINE_OFF:
1241 mEngineOn = false;
Mike Lockwood271f9f12010-02-02 11:41:52 -05001242 mNavigating = false;
Mike Lockwoodcf1d8cb2010-01-20 10:14:54 -05001243 break;
1244 }
1245
Mike Lockwooddbd6fd82009-12-07 18:43:36 -05001246 if (wasNavigating != mNavigating) {
1247 int size = mListeners.size();
1248 for (int i = 0; i < size; i++) {
1249 Listener listener = mListeners.get(i);
1250 try {
1251 if (mNavigating) {
1252 listener.mListener.onGpsStarted();
1253 } else {
1254 listener.mListener.onGpsStopped();
1255 }
1256 } catch (RemoteException e) {
1257 Log.w(TAG, "RemoteException in reportStatus");
1258 mListeners.remove(listener);
1259 // adjust for size of list changing
1260 size--;
1261 }
1262 }
1263
Mike Lockwooddbd6fd82009-12-07 18:43:36 -05001264 // send an intent to notify that the GPS has been enabled or disabled.
Mike Lockwood00b74272010-03-26 10:41:48 -04001265 Intent intent = new Intent(LocationManager.GPS_ENABLED_CHANGE_ACTION);
1266 intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, mNavigating);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001267 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001268 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001269 }
1270 }
1271
1272 /**
1273 * called from native code to update SV info
1274 */
1275 private void reportSvStatus() {
1276
1277 int svCount = native_read_sv_status(mSvs, mSnrs, mSvElevations, mSvAzimuths, mSvMasks);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001278
1279 synchronized (mListeners) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001280 int size = mListeners.size();
1281 for (int i = 0; i < size; i++) {
1282 Listener listener = mListeners.get(i);
1283 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001284 listener.mListener.onSvStatusChanged(svCount, mSvs, mSnrs,
1285 mSvElevations, mSvAzimuths, mSvMasks[EPHEMERIS_MASK],
1286 mSvMasks[ALMANAC_MASK], mSvMasks[USED_FOR_FIX_MASK]);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001287 } catch (RemoteException e) {
1288 Log.w(TAG, "RemoteException in reportSvInfo");
1289 mListeners.remove(listener);
1290 // adjust for size of list changing
1291 size--;
1292 }
1293 }
1294 }
1295
Mike Lockwood29c84342009-05-06 14:01:15 -04001296 if (VERBOSE) {
1297 Log.v(TAG, "SV count: " + svCount +
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001298 " ephemerisMask: " + Integer.toHexString(mSvMasks[EPHEMERIS_MASK]) +
1299 " almanacMask: " + Integer.toHexString(mSvMasks[ALMANAC_MASK]));
1300 for (int i = 0; i < svCount; i++) {
Mike Lockwood29c84342009-05-06 14:01:15 -04001301 Log.v(TAG, "sv: " + mSvs[i] +
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001302 " snr: " + mSnrs[i]/10 +
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001303 " elev: " + mSvElevations[i] +
1304 " azimuth: " + mSvAzimuths[i] +
1305 ((mSvMasks[EPHEMERIS_MASK] & (1 << (mSvs[i] - 1))) == 0 ? " " : " E") +
1306 ((mSvMasks[ALMANAC_MASK] & (1 << (mSvs[i] - 1))) == 0 ? " " : " A") +
1307 ((mSvMasks[USED_FOR_FIX_MASK] & (1 << (mSvs[i] - 1))) == 0 ? "" : "U"));
1308 }
1309 }
1310
Kevin.KY Tsai0881f4f2010-05-21 15:10:39 -04001311 // return number of sets used in fix instead of total
1312 updateStatus(mStatus, Integer.bitCount(mSvMasks[USED_FOR_FIX_MASK]));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001313
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001314 if (mNavigating && mStatus == LocationProvider.AVAILABLE && mLastFixTime > 0 &&
Mike Lockwood04598b62010-04-14 17:17:24 -04001315 System.currentTimeMillis() - mLastFixTime > RECENT_FIX_TIMEOUT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001316 // send an intent to notify that the GPS is no longer receiving fixes.
Mike Lockwood00b74272010-03-26 10:41:48 -04001317 Intent intent = new Intent(LocationManager.GPS_FIX_CHANGE_ACTION);
1318 intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, false);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001319 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001320 updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE, mSvCount);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001321 }
1322 }
Mike Lockwood58bda982009-04-14 16:25:07 -04001323
1324 /**
Mike Lockwoode3635c92009-05-11 08:38:02 -04001325 * called from native code to update AGPS status
Mike Lockwood58bda982009-04-14 16:25:07 -04001326 */
Stephen Li8efd74d2011-03-01 20:56:00 -08001327 private void reportAGpsStatus(int type, int status, int ipaddr) {
Mike Lockwood58bda982009-04-14 16:25:07 -04001328 switch (status) {
Mike Lockwoode3635c92009-05-11 08:38:02 -04001329 case GPS_REQUEST_AGPS_DATA_CONN:
Mike Lockwoodb6e5fa82010-10-09 20:10:46 -04001330 if (DEBUG) Log.d(TAG, "GPS_REQUEST_AGPS_DATA_CONN");
Mike Lockwood2acfd342010-09-22 12:13:39 -04001331 // Set mAGpsDataConnectionState before calling startUsingNetworkFeature
1332 // to avoid a race condition with handleUpdateNetworkState()
1333 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPENING;
1334 int result = mConnMgr.startUsingNetworkFeature(
Mike Lockwood58bda982009-04-14 16:25:07 -04001335 ConnectivityManager.TYPE_MOBILE, Phone.FEATURE_ENABLE_SUPL);
Stephen Li8efd74d2011-03-01 20:56:00 -08001336 mAGpsDataConnectionIpAddr = ipaddr;
Wink Savillea639b312012-07-10 12:37:54 -07001337 if (result == PhoneConstants.APN_ALREADY_ACTIVE) {
1338 if (DEBUG) Log.d(TAG, "PhoneConstants.APN_ALREADY_ACTIVE");
Mike Lockwoodb362a9a2009-06-22 16:20:39 -04001339 if (mAGpsApn != null) {
Stephen Li8efd74d2011-03-01 20:56:00 -08001340 Log.d(TAG, "mAGpsDataConnectionIpAddr " + mAGpsDataConnectionIpAddr);
1341 if (mAGpsDataConnectionIpAddr != 0xffffffff) {
1342 boolean route_result;
1343 if (DEBUG) Log.d(TAG, "call requestRouteToHost");
1344 route_result = mConnMgr.requestRouteToHost(
1345 ConnectivityManager.TYPE_MOBILE_SUPL,
1346 mAGpsDataConnectionIpAddr);
1347 if (route_result == false) Log.d(TAG, "call requestRouteToHost failed");
1348 }
Mike Lockwoodb362a9a2009-06-22 16:20:39 -04001349 native_agps_data_conn_open(mAGpsApn);
1350 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPEN;
1351 } else {
Wink Savillea639b312012-07-10 12:37:54 -07001352 Log.e(TAG, "mAGpsApn not set when receiving PhoneConstants.APN_ALREADY_ACTIVE");
Mike Lockwood2acfd342010-09-22 12:13:39 -04001353 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_CLOSED;
Mike Lockwoodb362a9a2009-06-22 16:20:39 -04001354 native_agps_data_conn_failed();
1355 }
Wink Savillea639b312012-07-10 12:37:54 -07001356 } else if (result == PhoneConstants.APN_REQUEST_STARTED) {
1357 if (DEBUG) Log.d(TAG, "PhoneConstants.APN_REQUEST_STARTED");
Mike Lockwood2acfd342010-09-22 12:13:39 -04001358 // Nothing to do here
Mike Lockwood58bda982009-04-14 16:25:07 -04001359 } else {
Stan Chesnutt1d72d8c2013-04-15 19:18:02 -07001360 if (DEBUG) Log.d(TAG, "startUsingNetworkFeature failed, value is " +
1361 result);
Mike Lockwood2acfd342010-09-22 12:13:39 -04001362 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_CLOSED;
Mike Lockwoode3635c92009-05-11 08:38:02 -04001363 native_agps_data_conn_failed();
Mike Lockwood58bda982009-04-14 16:25:07 -04001364 }
1365 break;
Mike Lockwoode3635c92009-05-11 08:38:02 -04001366 case GPS_RELEASE_AGPS_DATA_CONN:
Mike Lockwoodb6e5fa82010-10-09 20:10:46 -04001367 if (DEBUG) Log.d(TAG, "GPS_RELEASE_AGPS_DATA_CONN");
Mike Lockwoode3635c92009-05-11 08:38:02 -04001368 if (mAGpsDataConnectionState != AGPS_DATA_CONNECTION_CLOSED) {
Mike Lockwood58bda982009-04-14 16:25:07 -04001369 mConnMgr.stopUsingNetworkFeature(
1370 ConnectivityManager.TYPE_MOBILE, Phone.FEATURE_ENABLE_SUPL);
Mike Lockwoode3635c92009-05-11 08:38:02 -04001371 native_agps_data_conn_closed();
1372 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_CLOSED;
Mike Lockwood58bda982009-04-14 16:25:07 -04001373 }
1374 break;
Mike Lockwoode3635c92009-05-11 08:38:02 -04001375 case GPS_AGPS_DATA_CONNECTED:
Mike Lockwoodb6e5fa82010-10-09 20:10:46 -04001376 if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONNECTED");
Mike Lockwood58bda982009-04-14 16:25:07 -04001377 break;
Mike Lockwoode3635c92009-05-11 08:38:02 -04001378 case GPS_AGPS_DATA_CONN_DONE:
Mike Lockwoodb6e5fa82010-10-09 20:10:46 -04001379 if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONN_DONE");
Mike Lockwood58bda982009-04-14 16:25:07 -04001380 break;
Mike Lockwoode3635c92009-05-11 08:38:02 -04001381 case GPS_AGPS_DATA_CONN_FAILED:
Mike Lockwoodb6e5fa82010-10-09 20:10:46 -04001382 if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONN_FAILED");
Mike Lockwood58bda982009-04-14 16:25:07 -04001383 break;
1384 }
1385 }
1386
Mike Lockwoodb16e7802009-08-06 09:26:02 -04001387 /**
1388 * called from native code to report NMEA data received
1389 */
Mike Lockwoodf602d362010-06-20 14:28:16 -07001390 private void reportNmea(long timestamp) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001391 synchronized (mListeners) {
Mike Lockwoodb16e7802009-08-06 09:26:02 -04001392 int size = mListeners.size();
1393 if (size > 0) {
1394 // don't bother creating the String if we have no listeners
Mike Lockwoodf602d362010-06-20 14:28:16 -07001395 int length = native_read_nmea(mNmeaBuffer, mNmeaBuffer.length);
Mike Lockwoodb16e7802009-08-06 09:26:02 -04001396 String nmea = new String(mNmeaBuffer, 0, length);
1397
1398 for (int i = 0; i < size; i++) {
1399 Listener listener = mListeners.get(i);
1400 try {
1401 listener.mListener.onNmeaReceived(timestamp, nmea);
1402 } catch (RemoteException e) {
1403 Log.w(TAG, "RemoteException in reportNmea");
1404 mListeners.remove(listener);
1405 // adjust for size of list changing
1406 size--;
1407 }
1408 }
1409 }
1410 }
1411 }
1412
Mike Lockwood62a8fc12010-03-22 14:23:26 -04001413 /**
Mike Lockwood04598b62010-04-14 17:17:24 -04001414 * called from native code to inform us what the GPS engine capabilities are
1415 */
1416 private void setEngineCapabilities(int capabilities) {
1417 mEngineCapabilities = capabilities;
Mike Lockwood9b9fb5c2011-06-29 15:09:40 -04001418
1419 if (!hasCapability(GPS_CAPABILITY_ON_DEMAND_TIME) && !mPeriodicTimeInjection) {
1420 mPeriodicTimeInjection = true;
1421 requestUtcTime();
1422 }
Mike Lockwood04598b62010-04-14 17:17:24 -04001423 }
1424
1425 /**
Mike Lockwood62a8fc12010-03-22 14:23:26 -04001426 * called from native code to request XTRA data
1427 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001428 private void xtraDownloadRequest() {
Joe Onoratof5d95cb2010-01-07 21:48:32 -05001429 if (DEBUG) Log.d(TAG, "xtraDownloadRequest");
Mike Lockwood98e48692010-04-07 16:32:51 -04001430 sendMessage(DOWNLOAD_XTRA_DATA, 0, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001431 }
1432
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -07001433 /**
destradaa0682809a2013-08-12 18:50:30 -07001434 * Helper method to construct a location object.
1435 */
1436 private Location buildLocation(
1437 int flags,
1438 double latitude,
1439 double longitude,
1440 double altitude,
1441 float speed,
1442 float bearing,
1443 float accuracy,
1444 long timestamp) {
1445 Location location = new Location(LocationManager.GPS_PROVIDER);
1446 if((flags & LOCATION_HAS_LAT_LONG) == LOCATION_HAS_LAT_LONG) {
1447 location.setLatitude(latitude);
1448 location.setLongitude(longitude);
1449 location.setTime(timestamp);
1450 location.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());
1451 }
1452 if((flags & LOCATION_HAS_ALTITUDE) == LOCATION_HAS_ALTITUDE) {
1453 location.setAltitude(altitude);
1454 }
1455 if((flags & LOCATION_HAS_SPEED) == LOCATION_HAS_SPEED) {
1456 location.setSpeed(speed);
1457 }
1458 if((flags & LOCATION_HAS_BEARING) == LOCATION_HAS_BEARING) {
1459 location.setBearing(bearing);
1460 }
1461 if((flags & LOCATION_HAS_ACCURACY) == LOCATION_HAS_ACCURACY) {
1462 location.setAccuracy(accuracy);
1463 }
1464 return location;
1465 }
1466
1467 /**
1468 * Converts the GPS HAL status to the internal Geofence Hardware status.
1469 */
1470 private int getGeofenceStatus(int status) {
1471 switch(status) {
1472 case GPS_GEOFENCE_OPERATION_SUCCESS:
1473 return GeofenceHardware.GEOFENCE_SUCCESS;
1474 case GPS_GEOFENCE_ERROR_GENERIC:
1475 return GeofenceHardware.GEOFENCE_FAILURE;
1476 case GPS_GEOFENCE_ERROR_ID_EXISTS:
1477 return GeofenceHardware.GEOFENCE_ERROR_ID_EXISTS;
1478 case GPS_GEOFENCE_ERROR_INVALID_TRANSITION:
1479 return GeofenceHardware.GEOFENCE_ERROR_INVALID_TRANSITION;
1480 case GPS_GEOFENCE_ERROR_TOO_MANY_GEOFENCES:
1481 return GeofenceHardware.GEOFENCE_ERROR_TOO_MANY_GEOFENCES;
1482 case GPS_GEOFENCE_ERROR_ID_UNKNOWN:
1483 return GeofenceHardware.GEOFENCE_ERROR_ID_UNKNOWN;
1484 default:
1485 return -1;
1486 }
1487 }
1488
1489 /**
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -07001490 * Called from native to report GPS Geofence transition
1491 * All geofence callbacks are called on the same thread
1492 */
1493 private void reportGeofenceTransition(int geofenceId, int flags, double latitude,
1494 double longitude, double altitude, float speed, float bearing, float accuracy,
1495 long timestamp, int transition, long transitionTimestamp) {
1496 if (mGeofenceHardwareImpl == null) {
1497 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
1498 }
destradaa0682809a2013-08-12 18:50:30 -07001499 Location location = buildLocation(
1500 flags,
1501 latitude,
1502 longitude,
1503 altitude,
1504 speed,
1505 bearing,
1506 accuracy,
1507 timestamp);
1508 mGeofenceHardwareImpl.reportGeofenceTransition(
1509 geofenceId,
1510 location,
1511 transition,
1512 transitionTimestamp,
1513 GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE,
1514 FusedBatchOptions.SourceTechnologies.GNSS);
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -07001515 }
1516
1517 /**
1518 * called from native code to report GPS status change.
1519 */
1520 private void reportGeofenceStatus(int status, int flags, double latitude,
1521 double longitude, double altitude, float speed, float bearing, float accuracy,
1522 long timestamp) {
1523 if (mGeofenceHardwareImpl == null) {
1524 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
1525 }
destradaa0682809a2013-08-12 18:50:30 -07001526 Location location = buildLocation(
1527 flags,
1528 latitude,
1529 longitude,
1530 altitude,
1531 speed,
1532 bearing,
1533 accuracy,
1534 timestamp);
1535 int monitorStatus = GeofenceHardware.MONITOR_CURRENTLY_UNAVAILABLE;
1536 if(status == GPS_GEOFENCE_AVAILABLE) {
1537 monitorStatus = GeofenceHardware.MONITOR_CURRENTLY_AVAILABLE;
1538 }
1539 mGeofenceHardwareImpl.reportGeofenceMonitorStatus(
1540 GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE,
1541 monitorStatus,
1542 location,
1543 FusedBatchOptions.SourceTechnologies.GNSS);
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -07001544 }
1545
1546 /**
1547 * called from native code - Geofence Add callback
1548 */
1549 private void reportGeofenceAddStatus(int geofenceId, int status) {
1550 if (mGeofenceHardwareImpl == null) {
1551 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
1552 }
destradaa0682809a2013-08-12 18:50:30 -07001553 mGeofenceHardwareImpl.reportGeofenceAddStatus(geofenceId, getGeofenceStatus(status));
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -07001554 }
1555
1556 /**
1557 * called from native code - Geofence Remove callback
1558 */
1559 private void reportGeofenceRemoveStatus(int geofenceId, int status) {
1560 if (mGeofenceHardwareImpl == null) {
1561 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
1562 }
destradaa0682809a2013-08-12 18:50:30 -07001563 mGeofenceHardwareImpl.reportGeofenceRemoveStatus(geofenceId, getGeofenceStatus(status));
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -07001564 }
1565
1566 /**
1567 * called from native code - Geofence Pause callback
1568 */
1569 private void reportGeofencePauseStatus(int geofenceId, int status) {
1570 if (mGeofenceHardwareImpl == null) {
1571 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
1572 }
destradaa0682809a2013-08-12 18:50:30 -07001573 mGeofenceHardwareImpl.reportGeofencePauseStatus(geofenceId, getGeofenceStatus(status));
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -07001574 }
1575
1576 /**
1577 * called from native code - Geofence Resume callback
1578 */
1579 private void reportGeofenceResumeStatus(int geofenceId, int status) {
1580 if (mGeofenceHardwareImpl == null) {
1581 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
1582 }
destradaa0682809a2013-08-12 18:50:30 -07001583 mGeofenceHardwareImpl.reportGeofenceResumeStatus(geofenceId, getGeofenceStatus(status));
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -07001584 }
1585
Danke Xie22d1f9f2009-08-18 18:28:45 -04001586 //=============================================================
1587 // NI Client support
Miguel Torroja1e84da82010-07-27 07:02:24 +02001588 //=============================================================
Danke Xie22d1f9f2009-08-18 18:28:45 -04001589 private final INetInitiatedListener mNetInitiatedListener = new INetInitiatedListener.Stub() {
Miguel Torroja1e84da82010-07-27 07:02:24 +02001590 // Sends a response for an NI reqeust to HAL.
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001591 @Override
Miguel Torroja1e84da82010-07-27 07:02:24 +02001592 public boolean sendNiResponse(int notificationId, int userResponse)
1593 {
1594 // TODO Add Permission check
Danke Xie22d1f9f2009-08-18 18:28:45 -04001595
Miguel Torroja1e84da82010-07-27 07:02:24 +02001596 if (DEBUG) Log.d(TAG, "sendNiResponse, notifId: " + notificationId +
1597 ", response: " + userResponse);
1598 native_send_ni_response(notificationId, userResponse);
1599 return true;
1600 }
Danke Xie22d1f9f2009-08-18 18:28:45 -04001601 };
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001602
Danke Xie22d1f9f2009-08-18 18:28:45 -04001603 public INetInitiatedListener getNetInitiatedListener() {
1604 return mNetInitiatedListener;
1605 }
1606
1607 // Called by JNI function to report an NI request.
Miguel Torroja1e84da82010-07-27 07:02:24 +02001608 public void reportNiNotification(
1609 int notificationId,
1610 int niType,
1611 int notifyFlags,
1612 int timeout,
1613 int defaultResponse,
1614 String requestorId,
1615 String text,
1616 int requestorIdEncoding,
1617 int textEncoding,
1618 String extras // Encoded extra data
Danke Xie22d1f9f2009-08-18 18:28:45 -04001619 )
Miguel Torroja1e84da82010-07-27 07:02:24 +02001620 {
1621 Log.i(TAG, "reportNiNotification: entered");
1622 Log.i(TAG, "notificationId: " + notificationId +
1623 ", niType: " + niType +
1624 ", notifyFlags: " + notifyFlags +
1625 ", timeout: " + timeout +
1626 ", defaultResponse: " + defaultResponse);
1627
1628 Log.i(TAG, "requestorId: " + requestorId +
1629 ", text: " + text +
1630 ", requestorIdEncoding: " + requestorIdEncoding +
1631 ", textEncoding: " + textEncoding);
1632
1633 GpsNiNotification notification = new GpsNiNotification();
1634
1635 notification.notificationId = notificationId;
1636 notification.niType = niType;
1637 notification.needNotify = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_NEED_NOTIFY) != 0;
1638 notification.needVerify = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_NEED_VERIFY) != 0;
1639 notification.privacyOverride = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_PRIVACY_OVERRIDE) != 0;
1640 notification.timeout = timeout;
1641 notification.defaultResponse = defaultResponse;
1642 notification.requestorId = requestorId;
1643 notification.text = text;
1644 notification.requestorIdEncoding = requestorIdEncoding;
1645 notification.textEncoding = textEncoding;
1646
1647 // Process extras, assuming the format is
1648 // one of more lines of "key = value"
1649 Bundle bundle = new Bundle();
1650
1651 if (extras == null) extras = "";
1652 Properties extraProp = new Properties();
1653
1654 try {
Jeff Sharkey104344e2011-07-10 14:20:41 -07001655 extraProp.load(new StringReader(extras));
Miguel Torroja1e84da82010-07-27 07:02:24 +02001656 }
1657 catch (IOException e)
1658 {
1659 Log.e(TAG, "reportNiNotification cannot parse extras data: " + extras);
1660 }
1661
1662 for (Entry<Object, Object> ent : extraProp.entrySet())
1663 {
1664 bundle.putString((String) ent.getKey(), (String) ent.getValue());
1665 }
1666
1667 notification.extras = bundle;
1668
1669 mNIHandler.handleNiNotification(notification);
1670 }
1671
1672 /**
1673 * Called from native code to request set id info.
1674 * We should be careful about receiving null string from the TelephonyManager,
1675 * because sending null String to JNI function would cause a crash.
1676 */
1677
1678 private void requestSetID(int flags) {
1679 TelephonyManager phone = (TelephonyManager)
1680 mContext.getSystemService(Context.TELEPHONY_SERVICE);
1681 int type = AGPS_SETID_TYPE_NONE;
1682 String data = "";
1683
1684 if ((flags & AGPS_RIL_REQUEST_SETID_IMSI) == AGPS_RIL_REQUEST_SETID_IMSI) {
1685 String data_temp = phone.getSubscriberId();
1686 if (data_temp == null) {
1687 // This means the framework does not have the SIM card ready.
1688 } else {
1689 // This means the framework has the SIM card.
1690 data = data_temp;
1691 type = AGPS_SETID_TYPE_IMSI;
1692 }
1693 }
1694 else if ((flags & AGPS_RIL_REQUEST_SETID_MSISDN) == AGPS_RIL_REQUEST_SETID_MSISDN) {
1695 String data_temp = phone.getLine1Number();
1696 if (data_temp == null) {
1697 // This means the framework does not have the SIM card ready.
1698 } else {
1699 // This means the framework has the SIM card.
1700 data = data_temp;
1701 type = AGPS_SETID_TYPE_MSISDN;
1702 }
1703 }
1704 native_agps_set_id(type, data);
1705 }
1706
1707 /**
Mike Lockwood9b9fb5c2011-06-29 15:09:40 -04001708 * Called from native code to request utc time info
1709 */
1710
1711 private void requestUtcTime() {
1712 sendMessage(INJECT_NTP_TIME, 0, null);
1713 }
1714
1715 /**
Miguel Torroja1e84da82010-07-27 07:02:24 +02001716 * Called from native code to request reference location info
1717 */
1718
1719 private void requestRefLocation(int flags) {
1720 TelephonyManager phone = (TelephonyManager)
1721 mContext.getSystemService(Context.TELEPHONY_SERVICE);
Victoria Leased50d0c32012-10-29 13:16:17 -07001722 final int phoneType = phone.getPhoneType();
1723 if (phoneType == TelephonyManager.PHONE_TYPE_GSM) {
Miguel Torroja1e84da82010-07-27 07:02:24 +02001724 GsmCellLocation gsm_cell = (GsmCellLocation) phone.getCellLocation();
Victoria Leased50d0c32012-10-29 13:16:17 -07001725 if ((gsm_cell != null) && (phone.getNetworkOperator() != null)
1726 && (phone.getNetworkOperator().length() > 3)) {
Miguel Torroja1e84da82010-07-27 07:02:24 +02001727 int type;
1728 int mcc = Integer.parseInt(phone.getNetworkOperator().substring(0,3));
1729 int mnc = Integer.parseInt(phone.getNetworkOperator().substring(3));
Mike Lockwoodedc0f3872010-10-22 09:16:17 -04001730 int networkType = phone.getNetworkType();
1731 if (networkType == TelephonyManager.NETWORK_TYPE_UMTS
1732 || networkType == TelephonyManager.NETWORK_TYPE_HSDPA
1733 || networkType == TelephonyManager.NETWORK_TYPE_HSUPA
Arun Ravindran58d46122012-07-30 17:50:21 +03001734 || networkType == TelephonyManager.NETWORK_TYPE_HSPA
1735 || networkType == TelephonyManager.NETWORK_TYPE_HSPAP) {
Miguel Torroja1e84da82010-07-27 07:02:24 +02001736 type = AGPS_REF_LOCATION_TYPE_UMTS_CELLID;
Mike Lockwoodedc0f3872010-10-22 09:16:17 -04001737 } else {
Miguel Torroja1e84da82010-07-27 07:02:24 +02001738 type = AGPS_REF_LOCATION_TYPE_GSM_CELLID;
Mike Lockwoodedc0f3872010-10-22 09:16:17 -04001739 }
Miguel Torroja1e84da82010-07-27 07:02:24 +02001740 native_agps_set_ref_location_cellid(type, mcc, mnc,
1741 gsm_cell.getLac(), gsm_cell.getCid());
Mike Lockwoodedc0f3872010-10-22 09:16:17 -04001742 } else {
Miguel Torroja1e84da82010-07-27 07:02:24 +02001743 Log.e(TAG,"Error getting cell location info.");
Mike Lockwoodedc0f3872010-10-22 09:16:17 -04001744 }
Victoria Leased50d0c32012-10-29 13:16:17 -07001745 } else if (phoneType == TelephonyManager.PHONE_TYPE_CDMA) {
1746 Log.e(TAG, "CDMA not supported.");
Mike Lockwoodedc0f3872010-10-22 09:16:17 -04001747 }
Miguel Torroja1e84da82010-07-27 07:02:24 +02001748 }
Danke Xie22d1f9f2009-08-18 18:28:45 -04001749
Mike Lockwood98e48692010-04-07 16:32:51 -04001750 private void sendMessage(int message, int arg, Object obj) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001751 // hold a wake lock until this message is delivered
Jeff Brown028872f2012-08-25 13:07:01 -07001752 // note that this assumes the message will not be removed from the queue before
1753 // it is handled (otherwise the wake lock would be leaked).
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001754 mWakeLock.acquire();
1755 mHandler.obtainMessage(message, arg, 1, obj).sendToTarget();
Mike Lockwood98e48692010-04-07 16:32:51 -04001756 }
1757
Mike Lockwood62a8fc12010-03-22 14:23:26 -04001758 private final class ProviderHandler extends Handler {
Victoria Lease5cd731a2012-12-19 15:04:21 -08001759 public ProviderHandler(Looper looper) {
1760 super(looper, null, true /*async*/);
Jeff Brown028872f2012-08-25 13:07:01 -07001761 }
1762
Mike Lockwood62a8fc12010-03-22 14:23:26 -04001763 @Override
Mike Lockwood4a7b65e2010-10-25 16:35:55 -04001764 public void handleMessage(Message msg) {
Mike Lockwood98e48692010-04-07 16:32:51 -04001765 int message = msg.what;
1766 switch (message) {
Mike Lockwood62a8fc12010-03-22 14:23:26 -04001767 case ENABLE:
1768 if (msg.arg1 == 1) {
1769 handleEnable();
1770 } else {
1771 handleDisable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001772 }
Mike Lockwood62a8fc12010-03-22 14:23:26 -04001773 break;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001774 case SET_REQUEST:
1775 GpsRequest gpsRequest = (GpsRequest) msg.obj;
1776 handleSetRequest(gpsRequest.request, gpsRequest.source);
Mike Lockwood03ca2162010-04-01 08:10:09 -07001777 break;
Mike Lockwood62a8fc12010-03-22 14:23:26 -04001778 case UPDATE_NETWORK_STATE:
1779 handleUpdateNetworkState(msg.arg1, (NetworkInfo)msg.obj);
1780 break;
1781 case INJECT_NTP_TIME:
1782 handleInjectNtpTime();
1783 break;
1784 case DOWNLOAD_XTRA_DATA:
Mike Lockwood1a1cd3a2010-08-17 07:42:54 -04001785 if (mSupportsXtra) {
Mike Lockwood62a8fc12010-03-22 14:23:26 -04001786 handleDownloadXtraData();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001787 }
Mike Lockwood62a8fc12010-03-22 14:23:26 -04001788 break;
Kevin Tang40e1baf2012-01-10 14:32:44 -08001789 case INJECT_NTP_TIME_FINISHED:
1790 mInjectNtpTimePending = STATE_IDLE;
1791 break;
1792 case DOWNLOAD_XTRA_DATA_FINISHED:
1793 mDownloadXtraDataPending = STATE_IDLE;
1794 break;
Mike Lockwood62a8fc12010-03-22 14:23:26 -04001795 case UPDATE_LOCATION:
1796 handleUpdateLocation((Location)msg.obj);
1797 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001798 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001799 if (msg.arg2 == 1) {
1800 // wakelock was taken for this message, release it
1801 mWakeLock.release();
Mike Lockwood98e48692010-04-07 16:32:51 -04001802 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001803 }
Mike Lockwood62a8fc12010-03-22 14:23:26 -04001804 };
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001805
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001806 private final class NetworkLocationListener implements LocationListener {
1807 @Override
1808 public void onLocationChanged(Location location) {
1809 // this callback happens on mHandler looper
1810 if (LocationManager.NETWORK_PROVIDER.equals(location.getProvider())) {
1811 handleUpdateLocation(location);
1812 }
1813 }
1814 @Override
1815 public void onStatusChanged(String provider, int status, Bundle extras) { }
1816 @Override
1817 public void onProviderEnabled(String provider) { }
1818 @Override
1819 public void onProviderDisabled(String provider) { }
1820 }
1821
Kevin Tanga5fe6b22011-06-05 14:25:16 -07001822 private String getSelectedApn() {
1823 Uri uri = Uri.parse("content://telephony/carriers/preferapn");
1824 String apn = null;
1825
1826 Cursor cursor = mContext.getContentResolver().query(uri, new String[] {"apn"},
1827 null, null, Carriers.DEFAULT_SORT_ORDER);
1828
1829 if (null != cursor) {
1830 try {
1831 if (cursor.moveToFirst()) {
1832 apn = cursor.getString(0);
1833 }
1834 } finally {
1835 cursor.close();
1836 }
1837 }
1838 return apn;
1839 }
1840
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001841 @Override
1842 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1843 StringBuilder s = new StringBuilder();
1844 s.append(" mFixInterval=").append(mFixInterval).append("\n");
1845 s.append(" mEngineCapabilities=0x").append(Integer.toHexString(mEngineCapabilities)).append(" (");
1846 if (hasCapability(GPS_CAPABILITY_SCHEDULING)) s.append("SCHED ");
1847 if (hasCapability(GPS_CAPABILITY_MSB)) s.append("MSB ");
1848 if (hasCapability(GPS_CAPABILITY_MSA)) s.append("MSA ");
1849 if (hasCapability(GPS_CAPABILITY_SINGLE_SHOT)) s.append("SINGLE_SHOT ");
1850 if (hasCapability(GPS_CAPABILITY_ON_DEMAND_TIME)) s.append("ON_DEMAND_TIME ");
1851 s.append(")\n");
1852
1853 s.append(native_get_internal_state());
1854 pw.append(s);
1855 }
1856
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001857 // for GPS SV statistics
1858 private static final int MAX_SVS = 32;
1859 private static final int EPHEMERIS_MASK = 0;
1860 private static final int ALMANAC_MASK = 1;
1861 private static final int USED_FOR_FIX_MASK = 2;
1862
1863 // preallocated arrays, to avoid memory allocation in reportStatus()
1864 private int mSvs[] = new int[MAX_SVS];
1865 private float mSnrs[] = new float[MAX_SVS];
1866 private float mSvElevations[] = new float[MAX_SVS];
1867 private float mSvAzimuths[] = new float[MAX_SVS];
1868 private int mSvMasks[] = new int[3];
1869 private int mSvCount;
Mike Lockwoodb16e7802009-08-06 09:26:02 -04001870 // preallocated to avoid memory allocation in reportNmea()
1871 private byte[] mNmeaBuffer = new byte[120];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001872
1873 static { class_init_native(); }
1874 private static native void class_init_native();
1875 private static native boolean native_is_supported();
1876
1877 private native boolean native_init();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001878 private native void native_cleanup();
Mike Lockwood04598b62010-04-14 17:17:24 -04001879 private native boolean native_set_position_mode(int mode, int recurrence, int min_interval,
1880 int preferred_accuracy, int preferred_time);
1881 private native boolean native_start();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001882 private native boolean native_stop();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001883 private native void native_delete_aiding_data(int flags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001884 // returns number of SVs
1885 // mask[0] is ephemeris mask and mask[1] is almanac mask
1886 private native int native_read_sv_status(int[] svs, float[] snrs,
1887 float[] elevations, float[] azimuths, int[] masks);
Mike Lockwoodf602d362010-06-20 14:28:16 -07001888 private native int native_read_nmea(byte[] buffer, int bufferSize);
Mike Lockwoodd26ce0d2009-06-11 12:25:46 -04001889 private native void native_inject_location(double latitude, double longitude, float accuracy);
1890
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06001891 // XTRA Support
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001892 private native void native_inject_time(long time, long timeReference, int uncertainty);
1893 private native boolean native_supports_xtra();
1894 private native void native_inject_xtra_data(byte[] data, int length);
The Android Open Source Project10592532009-03-18 17:39:46 -07001895
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06001896 // DEBUG Support
1897 private native String native_get_internal_state();
1898
1899 // AGPS Support
Mike Lockwoode3635c92009-05-11 08:38:02 -04001900 private native void native_agps_data_conn_open(String apn);
1901 private native void native_agps_data_conn_closed();
1902 private native void native_agps_data_conn_failed();
Miguel Torroja1e84da82010-07-27 07:02:24 +02001903 private native void native_agps_ni_message(byte [] msg, int length);
Mike Lockwooda9e54612009-06-19 14:54:42 -04001904 private native void native_set_agps_server(int type, String hostname, int port);
Danke Xie22d1f9f2009-08-18 18:28:45 -04001905
1906 // Network-initiated (NI) Support
1907 private native void native_send_ni_response(int notificationId, int userResponse);
Miguel Torroja1e84da82010-07-27 07:02:24 +02001908
1909 // AGPS ril suport
1910 private native void native_agps_set_ref_location_cellid(int type, int mcc, int mnc,
1911 int lac, int cid);
1912 private native void native_agps_set_id(int type, String setid);
Mike Lockwood50130bb2010-10-11 06:22:50 -04001913
1914 private native void native_update_network_state(boolean connected, int type,
Kevin Tanga5fe6b22011-06-05 14:25:16 -07001915 boolean roaming, boolean available, String extraInfo, String defaultAPN);
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -07001916
1917 // Hardware Geofence support.
1918 private static native boolean native_is_geofence_supported();
1919 private static native boolean native_add_geofence(int geofenceId, double latitude,
1920 double longitude, double radius, int lastTransition,int monitorTransitions,
1921 int notificationResponsivenes, int unknownTimer);
1922 private static native boolean native_remove_geofence(int geofenceId);
1923 private static native boolean native_resume_geofence(int geofenceId, int transitions);
1924 private static native boolean native_pause_geofence(int geofenceId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001925}