blob: 9c76c19051e89d9e72efcdd5a2eec07169fc8cee [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
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800794 stopNavigating();
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700795 mAlarmManager.cancel(mWakeupIntent);
796 mAlarmManager.cancel(mTimeoutIntent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800797
Mike Lockwoodcf1d8cb2010-01-20 10:14:54 -0500798 // do this before releasing wakelock
799 native_cleanup();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800800 }
801
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700802 @Override
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500803 public boolean isEnabled() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700804 synchronized (mLock) {
805 return mEnabled;
806 }
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500807 }
808
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700809 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800810 public int getStatus(Bundle extras) {
811 if (extras != null) {
812 extras.putInt("satellites", mSvCount);
813 }
814 return mStatus;
815 }
816
817 private void updateStatus(int status, int svCount) {
818 if (status != mStatus || svCount != mSvCount) {
819 mStatus = status;
820 mSvCount = svCount;
821 mLocationExtras.putInt("satellites", svCount);
822 mStatusUpdateTime = SystemClock.elapsedRealtime();
823 }
824 }
825
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700826 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800827 public long getStatusUpdateTime() {
828 return mStatusUpdateTime;
829 }
830
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700831 @Override
832 public void setRequest(ProviderRequest request, WorkSource source) {
833 sendMessage(SET_REQUEST, 0, new GpsRequest(request, source));
Mike Lockwood62a8fc12010-03-22 14:23:26 -0400834 }
835
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700836 private void handleSetRequest(ProviderRequest request, WorkSource source) {
Stan Chesnutt1d72d8c2013-04-15 19:18:02 -0700837 boolean singleShot = false;
838
839 // see if the request is for a single update
840 if (request.locationRequests != null && request.locationRequests.size() > 0) {
841 // if any request has zero or more than one updates
842 // requested, then this is not single-shot mode
843 singleShot = true;
844
845 for (LocationRequest lr : request.locationRequests) {
846 if (lr.getNumUpdates() != 1) {
847 singleShot = false;
848 }
849 }
850 }
851
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700852 if (DEBUG) Log.d(TAG, "setRequest " + request);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700853 if (request.reportLocation) {
854 // update client uids
Dianne Hackborn002a54e2013-01-10 17:34:55 -0800855 updateClientUids(source);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800856
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700857 mFixInterval = (int) request.interval;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700858
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700859 // check for overflow
860 if (mFixInterval != request.interval) {
861 Log.w(TAG, "interval overflow: " + request.interval);
862 mFixInterval = Integer.MAX_VALUE;
863 }
Mike Lockwood03ca2162010-04-01 08:10:09 -0700864
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700865 // apply request to GPS engine
Mike Lockwood04598b62010-04-14 17:17:24 -0400866 if (mStarted && hasCapability(GPS_CAPABILITY_SCHEDULING)) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700867 // change period
Mike Lockwood04598b62010-04-14 17:17:24 -0400868 if (!native_set_position_mode(mPositionMode, GPS_POSITION_RECURRENCE_PERIODIC,
869 mFixInterval, 0, 0)) {
870 Log.e(TAG, "set_position_mode failed in setMinTime()");
871 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700872 } else if (!mStarted) {
873 // start GPS
Stan Chesnutt1d72d8c2013-04-15 19:18:02 -0700874 startNavigating(singleShot);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800875 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700876 } else {
Dianne Hackborn002a54e2013-01-10 17:34:55 -0800877 updateClientUids(new WorkSource());
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700878
879 stopNavigating();
880 mAlarmManager.cancel(mWakeupIntent);
881 mAlarmManager.cancel(mTimeoutIntent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800882 }
883 }
884
885 private final class Listener implements IBinder.DeathRecipient {
886 final IGpsStatusListener mListener;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700887
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800888 Listener(IGpsStatusListener listener) {
889 mListener = listener;
890 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700891
892 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800893 public void binderDied() {
Joe Onoratof5d95cb2010-01-07 21:48:32 -0500894 if (DEBUG) Log.d(TAG, "GPS status listener died");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800895
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700896 synchronized (mListeners) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800897 mListeners.remove(this);
898 }
Suchi Amalapurapufff2fda2009-06-30 21:36:16 -0700899 if (mListener != null) {
900 mListener.asBinder().unlinkToDeath(this, 0);
901 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800902 }
903 }
904
Dianne Hackborn002a54e2013-01-10 17:34:55 -0800905 private void updateClientUids(WorkSource source) {
906 // Update work source.
907 WorkSource[] changes = mClientSource.setReturningDiffs(source);
Victoria Leaseea78b852013-01-15 10:39:28 -0800908 if (changes == null) {
909 return;
910 }
Dianne Hackborn002a54e2013-01-10 17:34:55 -0800911 WorkSource newWork = changes[0];
912 WorkSource goneWork = changes[1];
913
914 // Update sources that were not previously tracked.
915 if (newWork != null) {
916 int lastuid = -1;
917 for (int i=0; i<newWork.size(); i++) {
Dianne Hackborn2e418422009-06-22 20:00:17 -0700918 try {
Dianne Hackborn002a54e2013-01-10 17:34:55 -0800919 int uid = newWork.get(i);
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700920 mAppOpsService.startOperation(AppOpsManager.getToken(mAppOpsService),
921 AppOpsManager.OP_GPS, uid, newWork.getName(i));
Dianne Hackborn002a54e2013-01-10 17:34:55 -0800922 if (uid != lastuid) {
923 lastuid = uid;
924 mBatteryStats.noteStartGps(uid);
925 }
Dianne Hackborn2e418422009-06-22 20:00:17 -0700926 } catch (RemoteException e) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700927 Log.w(TAG, "RemoteException", e);
928 }
929 }
930 }
931
Dianne Hackborn002a54e2013-01-10 17:34:55 -0800932 // Update sources that are no longer tracked.
933 if (goneWork != null) {
934 int lastuid = -1;
935 for (int i=0; i<goneWork.size(); i++) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700936 try {
Dianne Hackborn002a54e2013-01-10 17:34:55 -0800937 int uid = goneWork.get(i);
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700938 mAppOpsService.finishOperation(AppOpsManager.getToken(mAppOpsService),
939 AppOpsManager.OP_GPS, uid, goneWork.getName(i));
Dianne Hackborn002a54e2013-01-10 17:34:55 -0800940 if (uid != lastuid) {
941 lastuid = uid;
942 mBatteryStats.noteStopGps(uid);
943 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700944 } catch (RemoteException e) {
945 Log.w(TAG, "RemoteException", e);
Dianne Hackborn2e418422009-06-22 20:00:17 -0700946 }
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400947 }
948 }
949 }
950
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700951 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800952 public boolean sendExtraCommand(String command, Bundle extras) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700953
Mike Lockwood63aa5a62010-04-14 19:21:31 -0400954 long identity = Binder.clearCallingIdentity();
955 boolean result = false;
956
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800957 if ("delete_aiding_data".equals(command)) {
Mike Lockwood63aa5a62010-04-14 19:21:31 -0400958 result = deleteAidingData(extras);
959 } else if ("force_time_injection".equals(command)) {
Mike Lockwood98e48692010-04-07 16:32:51 -0400960 sendMessage(INJECT_NTP_TIME, 0, null);
Mike Lockwood63aa5a62010-04-14 19:21:31 -0400961 result = true;
962 } else if ("force_xtra_injection".equals(command)) {
Mike Lockwood1a1cd3a2010-08-17 07:42:54 -0400963 if (mSupportsXtra) {
Mike Lockwood93bc44d2009-05-20 16:58:22 -0400964 xtraDownloadRequest();
Mike Lockwood63aa5a62010-04-14 19:21:31 -0400965 result = true;
Mike Lockwood93bc44d2009-05-20 16:58:22 -0400966 }
Mike Lockwood63aa5a62010-04-14 19:21:31 -0400967 } else {
968 Log.w(TAG, "sendExtraCommand: unknown command " + command);
Mike Lockwood93bc44d2009-05-20 16:58:22 -0400969 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700970
Mike Lockwood63aa5a62010-04-14 19:21:31 -0400971 Binder.restoreCallingIdentity(identity);
972 return result;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800973 }
974
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -0700975 private IGpsGeofenceHardware mGpsGeofenceBinder = new IGpsGeofenceHardware.Stub() {
976 public boolean isHardwareGeofenceSupported() {
977 return native_is_geofence_supported();
978 }
979
980 public boolean addCircularHardwareGeofence(int geofenceId, double latitude,
981 double longitude, double radius, int lastTransition, int monitorTransitions,
982 int notificationResponsiveness, int unknownTimer) {
983 return native_add_geofence(geofenceId, latitude, longitude, radius,
984 lastTransition, monitorTransitions, notificationResponsiveness, unknownTimer);
985 }
986
987 public boolean removeHardwareGeofence(int geofenceId) {
988 return native_remove_geofence(geofenceId);
989 }
990
991 public boolean pauseHardwareGeofence(int geofenceId) {
992 return native_pause_geofence(geofenceId);
993 }
994
995 public boolean resumeHardwareGeofence(int geofenceId, int monitorTransition) {
996 return native_resume_geofence(geofenceId, monitorTransition);
997 }
998 };
999
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001000 private boolean deleteAidingData(Bundle extras) {
1001 int flags;
1002
1003 if (extras == null) {
1004 flags = GPS_DELETE_ALL;
1005 } else {
1006 flags = 0;
1007 if (extras.getBoolean("ephemeris")) flags |= GPS_DELETE_EPHEMERIS;
1008 if (extras.getBoolean("almanac")) flags |= GPS_DELETE_ALMANAC;
1009 if (extras.getBoolean("position")) flags |= GPS_DELETE_POSITION;
1010 if (extras.getBoolean("time")) flags |= GPS_DELETE_TIME;
1011 if (extras.getBoolean("iono")) flags |= GPS_DELETE_IONO;
1012 if (extras.getBoolean("utc")) flags |= GPS_DELETE_UTC;
1013 if (extras.getBoolean("health")) flags |= GPS_DELETE_HEALTH;
1014 if (extras.getBoolean("svdir")) flags |= GPS_DELETE_SVDIR;
1015 if (extras.getBoolean("svsteer")) flags |= GPS_DELETE_SVSTEER;
1016 if (extras.getBoolean("sadata")) flags |= GPS_DELETE_SADATA;
1017 if (extras.getBoolean("rti")) flags |= GPS_DELETE_RTI;
1018 if (extras.getBoolean("celldb-info")) flags |= GPS_DELETE_CELLDB_INFO;
1019 if (extras.getBoolean("all")) flags |= GPS_DELETE_ALL;
1020 }
1021
1022 if (flags != 0) {
1023 native_delete_aiding_data(flags);
1024 return true;
1025 }
1026
1027 return false;
1028 }
1029
Stan Chesnutt1d72d8c2013-04-15 19:18:02 -07001030 private void startNavigating(boolean singleShot) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001031 if (!mStarted) {
Stan Chesnutt1d72d8c2013-04-15 19:18:02 -07001032 if (DEBUG) Log.d(TAG, "startNavigating, singleShot is " + singleShot);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001033 mTimeToFirstFix = 0;
1034 mLastFixTime = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001035 mStarted = true;
Stan Chesnutt1d72d8c2013-04-15 19:18:02 -07001036 mSingleShot = singleShot;
Mike Lockwood03ca2162010-04-01 08:10:09 -07001037 mPositionMode = GPS_POSITION_MODE_STANDALONE;
1038
Jeff Brownbf6f6f92012-09-25 15:03:20 -07001039 if (Settings.Global.getInt(mContext.getContentResolver(),
1040 Settings.Global.ASSISTED_GPS_ENABLED, 1) != 0) {
Stan Chesnutt1d72d8c2013-04-15 19:18:02 -07001041 if (singleShot && hasCapability(GPS_CAPABILITY_MSA)) {
1042 mPositionMode = GPS_POSITION_MODE_MS_ASSISTED;
1043 } else if (hasCapability(GPS_CAPABILITY_MSB)) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07001044 mPositionMode = GPS_POSITION_MODE_MS_BASED;
1045 }
Mike Lockwoodbcab8df2009-06-25 16:39:09 -04001046 }
1047
Stan Chesnutt1d72d8c2013-04-15 19:18:02 -07001048 if (DEBUG) {
1049 String mode;
1050
1051 switch(mPositionMode) {
1052 case GPS_POSITION_MODE_STANDALONE:
1053 mode = "standalone";
1054 break;
1055 case GPS_POSITION_MODE_MS_ASSISTED:
1056 mode = "MS_ASSISTED";
1057 break;
1058 case GPS_POSITION_MODE_MS_BASED:
1059 mode = "MS_BASED";
1060 break;
1061 default:
1062 mode = "unknown";
1063 break;
1064 }
1065 Log.d(TAG, "setting position_mode to " + mode);
1066 }
1067
Mike Lockwood04598b62010-04-14 17:17:24 -04001068 int interval = (hasCapability(GPS_CAPABILITY_SCHEDULING) ? mFixInterval : 1000);
1069 if (!native_set_position_mode(mPositionMode, GPS_POSITION_RECURRENCE_PERIODIC,
1070 interval, 0, 0)) {
1071 mStarted = false;
1072 Log.e(TAG, "set_position_mode failed in startNavigating()");
1073 return;
1074 }
1075 if (!native_start()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001076 mStarted = false;
1077 Log.e(TAG, "native_start failed in startNavigating()");
Mike Lockwood0632ca72009-05-14 15:51:03 -04001078 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001079 }
1080
1081 // reset SV count to zero
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001082 updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE, 0);
Mike Lockwood29c84342009-05-06 14:01:15 -04001083 mFixRequestTime = System.currentTimeMillis();
Mike Lockwood04598b62010-04-14 17:17:24 -04001084 if (!hasCapability(GPS_CAPABILITY_SCHEDULING)) {
1085 // set timer to give up if we do not receive a fix within NO_FIX_TIMEOUT
1086 // and our fix interval is not short
1087 if (mFixInterval >= NO_FIX_TIMEOUT) {
1088 mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
1089 SystemClock.elapsedRealtime() + NO_FIX_TIMEOUT, mTimeoutIntent);
1090 }
Mike Lockwood0632ca72009-05-14 15:51:03 -04001091 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001092 }
1093 }
1094
Mike Lockwood62a8fc12010-03-22 14:23:26 -04001095 private void stopNavigating() {
Mike Lockwood29c84342009-05-06 14:01:15 -04001096 if (DEBUG) Log.d(TAG, "stopNavigating");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001097 if (mStarted) {
1098 mStarted = false;
Stan Chesnutt1d72d8c2013-04-15 19:18:02 -07001099 mSingleShot = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001100 native_stop();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001101 mTimeToFirstFix = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001102 mLastFixTime = 0;
1103 mLocationFlags = LOCATION_INVALID;
1104
1105 // reset SV count to zero
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001106 updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001107 }
1108 }
1109
Mike Lockwood0632ca72009-05-14 15:51:03 -04001110 private void hibernate() {
1111 // stop GPS until our next fix interval arrives
1112 stopNavigating();
Mike Lockwood0632ca72009-05-14 15:51:03 -04001113 mAlarmManager.cancel(mTimeoutIntent);
1114 mAlarmManager.cancel(mWakeupIntent);
1115 long now = SystemClock.elapsedRealtime();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001116 mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, now + mFixInterval, mWakeupIntent);
Mike Lockwood04598b62010-04-14 17:17:24 -04001117 }
1118
1119 private boolean hasCapability(int capability) {
1120 return ((mEngineCapabilities & capability) != 0);
Mike Lockwood0632ca72009-05-14 15:51:03 -04001121 }
1122
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -07001123
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001124 /**
1125 * called from native code to update our position.
1126 */
1127 private void reportLocation(int flags, double latitude, double longitude, double altitude,
1128 float speed, float bearing, float accuracy, long timestamp) {
Mike Lockwood29c84342009-05-06 14:01:15 -04001129 if (VERBOSE) Log.v(TAG, "reportLocation lat: " + latitude + " long: " + longitude +
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001130 " timestamp: " + timestamp);
1131
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001132 synchronized (mLocation) {
1133 mLocationFlags = flags;
1134 if ((flags & LOCATION_HAS_LAT_LONG) == LOCATION_HAS_LAT_LONG) {
1135 mLocation.setLatitude(latitude);
1136 mLocation.setLongitude(longitude);
1137 mLocation.setTime(timestamp);
Nick Pelly2eeeec22012-07-18 13:13:37 -07001138 // It would be nice to push the elapsed real-time timestamp
1139 // further down the stack, but this is still useful
Philip Milne41180122012-09-26 11:29:25 -07001140 mLocation.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001141 }
1142 if ((flags & LOCATION_HAS_ALTITUDE) == LOCATION_HAS_ALTITUDE) {
1143 mLocation.setAltitude(altitude);
1144 } else {
1145 mLocation.removeAltitude();
1146 }
1147 if ((flags & LOCATION_HAS_SPEED) == LOCATION_HAS_SPEED) {
1148 mLocation.setSpeed(speed);
1149 } else {
1150 mLocation.removeSpeed();
1151 }
1152 if ((flags & LOCATION_HAS_BEARING) == LOCATION_HAS_BEARING) {
1153 mLocation.setBearing(bearing);
1154 } else {
1155 mLocation.removeBearing();
1156 }
1157 if ((flags & LOCATION_HAS_ACCURACY) == LOCATION_HAS_ACCURACY) {
1158 mLocation.setAccuracy(accuracy);
1159 } else {
1160 mLocation.removeAccuracy();
1161 }
Sean Barbeauced2b2c2011-12-19 04:43:07 -05001162 mLocation.setExtras(mLocationExtras);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001163
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001164 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001165 mILocationManager.reportLocation(mLocation, false);
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001166 } catch (RemoteException e) {
1167 Log.e(TAG, "RemoteException calling reportLocation");
1168 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001169 }
1170
Hakan Gustavssonfa94ff02010-02-23 09:12:38 +01001171 mLastFixTime = System.currentTimeMillis();
1172 // report time to first fix
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001173 if (mTimeToFirstFix == 0 && (flags & LOCATION_HAS_LAT_LONG) == LOCATION_HAS_LAT_LONG) {
1174 mTimeToFirstFix = (int)(mLastFixTime - mFixRequestTime);
1175 if (DEBUG) Log.d(TAG, "TTFF: " + mTimeToFirstFix);
Hakan Gustavssonfa94ff02010-02-23 09:12:38 +01001176
1177 // notify status listeners
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001178 synchronized (mListeners) {
Hakan Gustavssonfa94ff02010-02-23 09:12:38 +01001179 int size = mListeners.size();
1180 for (int i = 0; i < size; i++) {
1181 Listener listener = mListeners.get(i);
1182 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001183 listener.mListener.onFirstFix(mTimeToFirstFix);
Hakan Gustavssonfa94ff02010-02-23 09:12:38 +01001184 } catch (RemoteException e) {
1185 Log.w(TAG, "RemoteException in stopNavigating");
1186 mListeners.remove(listener);
1187 // adjust for size of list changing
1188 size--;
1189 }
1190 }
1191 }
1192 }
1193
Stan Chesnutt1d72d8c2013-04-15 19:18:02 -07001194 if (mSingleShot) {
1195 stopNavigating();
1196 }
1197
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001198 if (mStarted && mStatus != LocationProvider.AVAILABLE) {
Mike Lockwoodd53ba012010-04-15 20:41:26 -04001199 // we want to time out if we do not receive a fix
Mike Lockwoodb7be5442010-02-24 14:34:50 -05001200 // within the time out and we are requesting infrequent fixes
Mike Lockwood04598b62010-04-14 17:17:24 -04001201 if (!hasCapability(GPS_CAPABILITY_SCHEDULING) && mFixInterval < NO_FIX_TIMEOUT) {
Mike Lockwoodb7be5442010-02-24 14:34:50 -05001202 mAlarmManager.cancel(mTimeoutIntent);
1203 }
1204
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001205 // send an intent to notify that the GPS is receiving fixes.
Mike Lockwood00b74272010-03-26 10:41:48 -04001206 Intent intent = new Intent(LocationManager.GPS_FIX_CHANGE_ACTION);
1207 intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, true);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001208 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001209 updateStatus(LocationProvider.AVAILABLE, mSvCount);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001210 }
Mike Lockwood29c84342009-05-06 14:01:15 -04001211
Nick Pellyb041f232012-05-07 17:12:25 -07001212 if (!hasCapability(GPS_CAPABILITY_SCHEDULING) && mStarted &&
1213 mFixInterval > GPS_POLLING_THRESHOLD_INTERVAL) {
Mike Lockwoodd53ba012010-04-15 20:41:26 -04001214 if (DEBUG) Log.d(TAG, "got fix, hibernating");
Mike Lockwood0632ca72009-05-14 15:51:03 -04001215 hibernate();
Mike Lockwood29c84342009-05-06 14:01:15 -04001216 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001217 }
1218
1219 /**
1220 * called from native code to update our status
1221 */
1222 private void reportStatus(int status) {
Mike Lockwoodb8d90332010-10-18 17:59:48 -04001223 if (DEBUG) Log.v(TAG, "reportStatus status: " + status);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001224
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001225 synchronized (mListeners) {
Dianne Hackborn2e418422009-06-22 20:00:17 -07001226 boolean wasNavigating = mNavigating;
Mike Lockwooddbd6fd82009-12-07 18:43:36 -05001227
Mike Lockwoodcf1d8cb2010-01-20 10:14:54 -05001228 switch (status) {
1229 case GPS_STATUS_SESSION_BEGIN:
1230 mNavigating = true;
Mike Lockwood271f9f12010-02-02 11:41:52 -05001231 mEngineOn = true;
Mike Lockwoodcf1d8cb2010-01-20 10:14:54 -05001232 break;
1233 case GPS_STATUS_SESSION_END:
1234 mNavigating = false;
1235 break;
1236 case GPS_STATUS_ENGINE_ON:
1237 mEngineOn = true;
1238 break;
1239 case GPS_STATUS_ENGINE_OFF:
1240 mEngineOn = false;
Mike Lockwood271f9f12010-02-02 11:41:52 -05001241 mNavigating = false;
Mike Lockwoodcf1d8cb2010-01-20 10:14:54 -05001242 break;
1243 }
1244
Mike Lockwooddbd6fd82009-12-07 18:43:36 -05001245 if (wasNavigating != mNavigating) {
1246 int size = mListeners.size();
1247 for (int i = 0; i < size; i++) {
1248 Listener listener = mListeners.get(i);
1249 try {
1250 if (mNavigating) {
1251 listener.mListener.onGpsStarted();
1252 } else {
1253 listener.mListener.onGpsStopped();
1254 }
1255 } catch (RemoteException e) {
1256 Log.w(TAG, "RemoteException in reportStatus");
1257 mListeners.remove(listener);
1258 // adjust for size of list changing
1259 size--;
1260 }
1261 }
1262
Mike Lockwooddbd6fd82009-12-07 18:43:36 -05001263 // send an intent to notify that the GPS has been enabled or disabled.
Mike Lockwood00b74272010-03-26 10:41:48 -04001264 Intent intent = new Intent(LocationManager.GPS_ENABLED_CHANGE_ACTION);
1265 intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, mNavigating);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001266 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001267 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001268 }
1269 }
1270
1271 /**
1272 * called from native code to update SV info
1273 */
1274 private void reportSvStatus() {
1275
1276 int svCount = native_read_sv_status(mSvs, mSnrs, mSvElevations, mSvAzimuths, mSvMasks);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001277
1278 synchronized (mListeners) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001279 int size = mListeners.size();
1280 for (int i = 0; i < size; i++) {
1281 Listener listener = mListeners.get(i);
1282 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001283 listener.mListener.onSvStatusChanged(svCount, mSvs, mSnrs,
1284 mSvElevations, mSvAzimuths, mSvMasks[EPHEMERIS_MASK],
1285 mSvMasks[ALMANAC_MASK], mSvMasks[USED_FOR_FIX_MASK]);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001286 } catch (RemoteException e) {
1287 Log.w(TAG, "RemoteException in reportSvInfo");
1288 mListeners.remove(listener);
1289 // adjust for size of list changing
1290 size--;
1291 }
1292 }
1293 }
1294
Mike Lockwood29c84342009-05-06 14:01:15 -04001295 if (VERBOSE) {
1296 Log.v(TAG, "SV count: " + svCount +
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001297 " ephemerisMask: " + Integer.toHexString(mSvMasks[EPHEMERIS_MASK]) +
1298 " almanacMask: " + Integer.toHexString(mSvMasks[ALMANAC_MASK]));
1299 for (int i = 0; i < svCount; i++) {
Mike Lockwood29c84342009-05-06 14:01:15 -04001300 Log.v(TAG, "sv: " + mSvs[i] +
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001301 " snr: " + mSnrs[i]/10 +
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001302 " elev: " + mSvElevations[i] +
1303 " azimuth: " + mSvAzimuths[i] +
1304 ((mSvMasks[EPHEMERIS_MASK] & (1 << (mSvs[i] - 1))) == 0 ? " " : " E") +
1305 ((mSvMasks[ALMANAC_MASK] & (1 << (mSvs[i] - 1))) == 0 ? " " : " A") +
1306 ((mSvMasks[USED_FOR_FIX_MASK] & (1 << (mSvs[i] - 1))) == 0 ? "" : "U"));
1307 }
1308 }
1309
Kevin.KY Tsai0881f4f2010-05-21 15:10:39 -04001310 // return number of sets used in fix instead of total
1311 updateStatus(mStatus, Integer.bitCount(mSvMasks[USED_FOR_FIX_MASK]));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001312
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001313 if (mNavigating && mStatus == LocationProvider.AVAILABLE && mLastFixTime > 0 &&
Mike Lockwood04598b62010-04-14 17:17:24 -04001314 System.currentTimeMillis() - mLastFixTime > RECENT_FIX_TIMEOUT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001315 // send an intent to notify that the GPS is no longer receiving fixes.
Mike Lockwood00b74272010-03-26 10:41:48 -04001316 Intent intent = new Intent(LocationManager.GPS_FIX_CHANGE_ACTION);
1317 intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, false);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001318 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001319 updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE, mSvCount);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001320 }
1321 }
Mike Lockwood58bda982009-04-14 16:25:07 -04001322
1323 /**
Mike Lockwoode3635c92009-05-11 08:38:02 -04001324 * called from native code to update AGPS status
Mike Lockwood58bda982009-04-14 16:25:07 -04001325 */
Stephen Li8efd74d2011-03-01 20:56:00 -08001326 private void reportAGpsStatus(int type, int status, int ipaddr) {
Mike Lockwood58bda982009-04-14 16:25:07 -04001327 switch (status) {
Mike Lockwoode3635c92009-05-11 08:38:02 -04001328 case GPS_REQUEST_AGPS_DATA_CONN:
Mike Lockwoodb6e5fa82010-10-09 20:10:46 -04001329 if (DEBUG) Log.d(TAG, "GPS_REQUEST_AGPS_DATA_CONN");
Mike Lockwood2acfd342010-09-22 12:13:39 -04001330 // Set mAGpsDataConnectionState before calling startUsingNetworkFeature
1331 // to avoid a race condition with handleUpdateNetworkState()
1332 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPENING;
1333 int result = mConnMgr.startUsingNetworkFeature(
Mike Lockwood58bda982009-04-14 16:25:07 -04001334 ConnectivityManager.TYPE_MOBILE, Phone.FEATURE_ENABLE_SUPL);
Stephen Li8efd74d2011-03-01 20:56:00 -08001335 mAGpsDataConnectionIpAddr = ipaddr;
Wink Savillea639b312012-07-10 12:37:54 -07001336 if (result == PhoneConstants.APN_ALREADY_ACTIVE) {
1337 if (DEBUG) Log.d(TAG, "PhoneConstants.APN_ALREADY_ACTIVE");
Mike Lockwoodb362a9a2009-06-22 16:20:39 -04001338 if (mAGpsApn != null) {
Stephen Li8efd74d2011-03-01 20:56:00 -08001339 Log.d(TAG, "mAGpsDataConnectionIpAddr " + mAGpsDataConnectionIpAddr);
1340 if (mAGpsDataConnectionIpAddr != 0xffffffff) {
1341 boolean route_result;
1342 if (DEBUG) Log.d(TAG, "call requestRouteToHost");
1343 route_result = mConnMgr.requestRouteToHost(
1344 ConnectivityManager.TYPE_MOBILE_SUPL,
1345 mAGpsDataConnectionIpAddr);
1346 if (route_result == false) Log.d(TAG, "call requestRouteToHost failed");
1347 }
Mike Lockwoodb362a9a2009-06-22 16:20:39 -04001348 native_agps_data_conn_open(mAGpsApn);
1349 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPEN;
1350 } else {
Wink Savillea639b312012-07-10 12:37:54 -07001351 Log.e(TAG, "mAGpsApn not set when receiving PhoneConstants.APN_ALREADY_ACTIVE");
Mike Lockwood2acfd342010-09-22 12:13:39 -04001352 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_CLOSED;
Mike Lockwoodb362a9a2009-06-22 16:20:39 -04001353 native_agps_data_conn_failed();
1354 }
Wink Savillea639b312012-07-10 12:37:54 -07001355 } else if (result == PhoneConstants.APN_REQUEST_STARTED) {
1356 if (DEBUG) Log.d(TAG, "PhoneConstants.APN_REQUEST_STARTED");
Mike Lockwood2acfd342010-09-22 12:13:39 -04001357 // Nothing to do here
Mike Lockwood58bda982009-04-14 16:25:07 -04001358 } else {
Stan Chesnutt1d72d8c2013-04-15 19:18:02 -07001359 if (DEBUG) Log.d(TAG, "startUsingNetworkFeature failed, value is " +
1360 result);
Mike Lockwood2acfd342010-09-22 12:13:39 -04001361 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_CLOSED;
Mike Lockwoode3635c92009-05-11 08:38:02 -04001362 native_agps_data_conn_failed();
Mike Lockwood58bda982009-04-14 16:25:07 -04001363 }
1364 break;
Mike Lockwoode3635c92009-05-11 08:38:02 -04001365 case GPS_RELEASE_AGPS_DATA_CONN:
Mike Lockwoodb6e5fa82010-10-09 20:10:46 -04001366 if (DEBUG) Log.d(TAG, "GPS_RELEASE_AGPS_DATA_CONN");
Mike Lockwoode3635c92009-05-11 08:38:02 -04001367 if (mAGpsDataConnectionState != AGPS_DATA_CONNECTION_CLOSED) {
Mike Lockwood58bda982009-04-14 16:25:07 -04001368 mConnMgr.stopUsingNetworkFeature(
1369 ConnectivityManager.TYPE_MOBILE, Phone.FEATURE_ENABLE_SUPL);
Mike Lockwoode3635c92009-05-11 08:38:02 -04001370 native_agps_data_conn_closed();
1371 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_CLOSED;
Mike Lockwood58bda982009-04-14 16:25:07 -04001372 }
1373 break;
Mike Lockwoode3635c92009-05-11 08:38:02 -04001374 case GPS_AGPS_DATA_CONNECTED:
Mike Lockwoodb6e5fa82010-10-09 20:10:46 -04001375 if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONNECTED");
Mike Lockwood58bda982009-04-14 16:25:07 -04001376 break;
Mike Lockwoode3635c92009-05-11 08:38:02 -04001377 case GPS_AGPS_DATA_CONN_DONE:
Mike Lockwoodb6e5fa82010-10-09 20:10:46 -04001378 if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONN_DONE");
Mike Lockwood58bda982009-04-14 16:25:07 -04001379 break;
Mike Lockwoode3635c92009-05-11 08:38:02 -04001380 case GPS_AGPS_DATA_CONN_FAILED:
Mike Lockwoodb6e5fa82010-10-09 20:10:46 -04001381 if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONN_FAILED");
Mike Lockwood58bda982009-04-14 16:25:07 -04001382 break;
1383 }
1384 }
1385
Mike Lockwoodb16e7802009-08-06 09:26:02 -04001386 /**
1387 * called from native code to report NMEA data received
1388 */
Mike Lockwoodf602d362010-06-20 14:28:16 -07001389 private void reportNmea(long timestamp) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001390 synchronized (mListeners) {
Mike Lockwoodb16e7802009-08-06 09:26:02 -04001391 int size = mListeners.size();
1392 if (size > 0) {
1393 // don't bother creating the String if we have no listeners
Mike Lockwoodf602d362010-06-20 14:28:16 -07001394 int length = native_read_nmea(mNmeaBuffer, mNmeaBuffer.length);
Mike Lockwoodb16e7802009-08-06 09:26:02 -04001395 String nmea = new String(mNmeaBuffer, 0, length);
1396
1397 for (int i = 0; i < size; i++) {
1398 Listener listener = mListeners.get(i);
1399 try {
1400 listener.mListener.onNmeaReceived(timestamp, nmea);
1401 } catch (RemoteException e) {
1402 Log.w(TAG, "RemoteException in reportNmea");
1403 mListeners.remove(listener);
1404 // adjust for size of list changing
1405 size--;
1406 }
1407 }
1408 }
1409 }
1410 }
1411
Mike Lockwood62a8fc12010-03-22 14:23:26 -04001412 /**
Mike Lockwood04598b62010-04-14 17:17:24 -04001413 * called from native code to inform us what the GPS engine capabilities are
1414 */
1415 private void setEngineCapabilities(int capabilities) {
1416 mEngineCapabilities = capabilities;
Mike Lockwood9b9fb5c2011-06-29 15:09:40 -04001417
1418 if (!hasCapability(GPS_CAPABILITY_ON_DEMAND_TIME) && !mPeriodicTimeInjection) {
1419 mPeriodicTimeInjection = true;
1420 requestUtcTime();
1421 }
Mike Lockwood04598b62010-04-14 17:17:24 -04001422 }
1423
1424 /**
Mike Lockwood62a8fc12010-03-22 14:23:26 -04001425 * called from native code to request XTRA data
1426 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001427 private void xtraDownloadRequest() {
Joe Onoratof5d95cb2010-01-07 21:48:32 -05001428 if (DEBUG) Log.d(TAG, "xtraDownloadRequest");
Mike Lockwood98e48692010-04-07 16:32:51 -04001429 sendMessage(DOWNLOAD_XTRA_DATA, 0, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001430 }
1431
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -07001432 /**
destradaa0682809a2013-08-12 18:50:30 -07001433 * Helper method to construct a location object.
1434 */
1435 private Location buildLocation(
1436 int flags,
1437 double latitude,
1438 double longitude,
1439 double altitude,
1440 float speed,
1441 float bearing,
1442 float accuracy,
1443 long timestamp) {
1444 Location location = new Location(LocationManager.GPS_PROVIDER);
1445 if((flags & LOCATION_HAS_LAT_LONG) == LOCATION_HAS_LAT_LONG) {
1446 location.setLatitude(latitude);
1447 location.setLongitude(longitude);
1448 location.setTime(timestamp);
1449 location.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());
1450 }
1451 if((flags & LOCATION_HAS_ALTITUDE) == LOCATION_HAS_ALTITUDE) {
1452 location.setAltitude(altitude);
1453 }
1454 if((flags & LOCATION_HAS_SPEED) == LOCATION_HAS_SPEED) {
1455 location.setSpeed(speed);
1456 }
1457 if((flags & LOCATION_HAS_BEARING) == LOCATION_HAS_BEARING) {
1458 location.setBearing(bearing);
1459 }
1460 if((flags & LOCATION_HAS_ACCURACY) == LOCATION_HAS_ACCURACY) {
1461 location.setAccuracy(accuracy);
1462 }
1463 return location;
1464 }
1465
1466 /**
1467 * Converts the GPS HAL status to the internal Geofence Hardware status.
1468 */
1469 private int getGeofenceStatus(int status) {
1470 switch(status) {
1471 case GPS_GEOFENCE_OPERATION_SUCCESS:
1472 return GeofenceHardware.GEOFENCE_SUCCESS;
1473 case GPS_GEOFENCE_ERROR_GENERIC:
1474 return GeofenceHardware.GEOFENCE_FAILURE;
1475 case GPS_GEOFENCE_ERROR_ID_EXISTS:
1476 return GeofenceHardware.GEOFENCE_ERROR_ID_EXISTS;
1477 case GPS_GEOFENCE_ERROR_INVALID_TRANSITION:
1478 return GeofenceHardware.GEOFENCE_ERROR_INVALID_TRANSITION;
1479 case GPS_GEOFENCE_ERROR_TOO_MANY_GEOFENCES:
1480 return GeofenceHardware.GEOFENCE_ERROR_TOO_MANY_GEOFENCES;
1481 case GPS_GEOFENCE_ERROR_ID_UNKNOWN:
1482 return GeofenceHardware.GEOFENCE_ERROR_ID_UNKNOWN;
1483 default:
1484 return -1;
1485 }
1486 }
1487
1488 /**
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -07001489 * Called from native to report GPS Geofence transition
1490 * All geofence callbacks are called on the same thread
1491 */
1492 private void reportGeofenceTransition(int geofenceId, int flags, double latitude,
1493 double longitude, double altitude, float speed, float bearing, float accuracy,
1494 long timestamp, int transition, long transitionTimestamp) {
1495 if (mGeofenceHardwareImpl == null) {
1496 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
1497 }
destradaa0682809a2013-08-12 18:50:30 -07001498 Location location = buildLocation(
1499 flags,
1500 latitude,
1501 longitude,
1502 altitude,
1503 speed,
1504 bearing,
1505 accuracy,
1506 timestamp);
1507 mGeofenceHardwareImpl.reportGeofenceTransition(
1508 geofenceId,
1509 location,
1510 transition,
1511 transitionTimestamp,
1512 GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE,
1513 FusedBatchOptions.SourceTechnologies.GNSS);
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -07001514 }
1515
1516 /**
1517 * called from native code to report GPS status change.
1518 */
1519 private void reportGeofenceStatus(int status, int flags, double latitude,
1520 double longitude, double altitude, float speed, float bearing, float accuracy,
1521 long timestamp) {
1522 if (mGeofenceHardwareImpl == null) {
1523 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
1524 }
destradaa0682809a2013-08-12 18:50:30 -07001525 Location location = buildLocation(
1526 flags,
1527 latitude,
1528 longitude,
1529 altitude,
1530 speed,
1531 bearing,
1532 accuracy,
1533 timestamp);
1534 int monitorStatus = GeofenceHardware.MONITOR_CURRENTLY_UNAVAILABLE;
1535 if(status == GPS_GEOFENCE_AVAILABLE) {
1536 monitorStatus = GeofenceHardware.MONITOR_CURRENTLY_AVAILABLE;
1537 }
1538 mGeofenceHardwareImpl.reportGeofenceMonitorStatus(
1539 GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE,
1540 monitorStatus,
1541 location,
1542 FusedBatchOptions.SourceTechnologies.GNSS);
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -07001543 }
1544
1545 /**
1546 * called from native code - Geofence Add callback
1547 */
1548 private void reportGeofenceAddStatus(int geofenceId, int status) {
1549 if (mGeofenceHardwareImpl == null) {
1550 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
1551 }
destradaa0682809a2013-08-12 18:50:30 -07001552 mGeofenceHardwareImpl.reportGeofenceAddStatus(geofenceId, getGeofenceStatus(status));
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -07001553 }
1554
1555 /**
1556 * called from native code - Geofence Remove callback
1557 */
1558 private void reportGeofenceRemoveStatus(int geofenceId, int status) {
1559 if (mGeofenceHardwareImpl == null) {
1560 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
1561 }
destradaa0682809a2013-08-12 18:50:30 -07001562 mGeofenceHardwareImpl.reportGeofenceRemoveStatus(geofenceId, getGeofenceStatus(status));
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -07001563 }
1564
1565 /**
1566 * called from native code - Geofence Pause callback
1567 */
1568 private void reportGeofencePauseStatus(int geofenceId, int status) {
1569 if (mGeofenceHardwareImpl == null) {
1570 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
1571 }
destradaa0682809a2013-08-12 18:50:30 -07001572 mGeofenceHardwareImpl.reportGeofencePauseStatus(geofenceId, getGeofenceStatus(status));
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -07001573 }
1574
1575 /**
1576 * called from native code - Geofence Resume callback
1577 */
1578 private void reportGeofenceResumeStatus(int geofenceId, int status) {
1579 if (mGeofenceHardwareImpl == null) {
1580 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
1581 }
destradaa0682809a2013-08-12 18:50:30 -07001582 mGeofenceHardwareImpl.reportGeofenceResumeStatus(geofenceId, getGeofenceStatus(status));
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -07001583 }
1584
Danke Xie22d1f9f2009-08-18 18:28:45 -04001585 //=============================================================
1586 // NI Client support
Miguel Torroja1e84da82010-07-27 07:02:24 +02001587 //=============================================================
Danke Xie22d1f9f2009-08-18 18:28:45 -04001588 private final INetInitiatedListener mNetInitiatedListener = new INetInitiatedListener.Stub() {
Miguel Torroja1e84da82010-07-27 07:02:24 +02001589 // Sends a response for an NI reqeust to HAL.
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001590 @Override
Miguel Torroja1e84da82010-07-27 07:02:24 +02001591 public boolean sendNiResponse(int notificationId, int userResponse)
1592 {
1593 // TODO Add Permission check
Danke Xie22d1f9f2009-08-18 18:28:45 -04001594
Miguel Torroja1e84da82010-07-27 07:02:24 +02001595 if (DEBUG) Log.d(TAG, "sendNiResponse, notifId: " + notificationId +
1596 ", response: " + userResponse);
1597 native_send_ni_response(notificationId, userResponse);
1598 return true;
1599 }
Danke Xie22d1f9f2009-08-18 18:28:45 -04001600 };
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001601
Danke Xie22d1f9f2009-08-18 18:28:45 -04001602 public INetInitiatedListener getNetInitiatedListener() {
1603 return mNetInitiatedListener;
1604 }
1605
1606 // Called by JNI function to report an NI request.
Miguel Torroja1e84da82010-07-27 07:02:24 +02001607 public void reportNiNotification(
1608 int notificationId,
1609 int niType,
1610 int notifyFlags,
1611 int timeout,
1612 int defaultResponse,
1613 String requestorId,
1614 String text,
1615 int requestorIdEncoding,
1616 int textEncoding,
1617 String extras // Encoded extra data
Danke Xie22d1f9f2009-08-18 18:28:45 -04001618 )
Miguel Torroja1e84da82010-07-27 07:02:24 +02001619 {
1620 Log.i(TAG, "reportNiNotification: entered");
1621 Log.i(TAG, "notificationId: " + notificationId +
1622 ", niType: " + niType +
1623 ", notifyFlags: " + notifyFlags +
1624 ", timeout: " + timeout +
1625 ", defaultResponse: " + defaultResponse);
1626
1627 Log.i(TAG, "requestorId: " + requestorId +
1628 ", text: " + text +
1629 ", requestorIdEncoding: " + requestorIdEncoding +
1630 ", textEncoding: " + textEncoding);
1631
1632 GpsNiNotification notification = new GpsNiNotification();
1633
1634 notification.notificationId = notificationId;
1635 notification.niType = niType;
1636 notification.needNotify = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_NEED_NOTIFY) != 0;
1637 notification.needVerify = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_NEED_VERIFY) != 0;
1638 notification.privacyOverride = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_PRIVACY_OVERRIDE) != 0;
1639 notification.timeout = timeout;
1640 notification.defaultResponse = defaultResponse;
1641 notification.requestorId = requestorId;
1642 notification.text = text;
1643 notification.requestorIdEncoding = requestorIdEncoding;
1644 notification.textEncoding = textEncoding;
1645
1646 // Process extras, assuming the format is
1647 // one of more lines of "key = value"
1648 Bundle bundle = new Bundle();
1649
1650 if (extras == null) extras = "";
1651 Properties extraProp = new Properties();
1652
1653 try {
Jeff Sharkey104344e2011-07-10 14:20:41 -07001654 extraProp.load(new StringReader(extras));
Miguel Torroja1e84da82010-07-27 07:02:24 +02001655 }
1656 catch (IOException e)
1657 {
1658 Log.e(TAG, "reportNiNotification cannot parse extras data: " + extras);
1659 }
1660
1661 for (Entry<Object, Object> ent : extraProp.entrySet())
1662 {
1663 bundle.putString((String) ent.getKey(), (String) ent.getValue());
1664 }
1665
1666 notification.extras = bundle;
1667
1668 mNIHandler.handleNiNotification(notification);
1669 }
1670
1671 /**
1672 * Called from native code to request set id info.
1673 * We should be careful about receiving null string from the TelephonyManager,
1674 * because sending null String to JNI function would cause a crash.
1675 */
1676
1677 private void requestSetID(int flags) {
1678 TelephonyManager phone = (TelephonyManager)
1679 mContext.getSystemService(Context.TELEPHONY_SERVICE);
1680 int type = AGPS_SETID_TYPE_NONE;
1681 String data = "";
1682
1683 if ((flags & AGPS_RIL_REQUEST_SETID_IMSI) == AGPS_RIL_REQUEST_SETID_IMSI) {
1684 String data_temp = phone.getSubscriberId();
1685 if (data_temp == null) {
1686 // This means the framework does not have the SIM card ready.
1687 } else {
1688 // This means the framework has the SIM card.
1689 data = data_temp;
1690 type = AGPS_SETID_TYPE_IMSI;
1691 }
1692 }
1693 else if ((flags & AGPS_RIL_REQUEST_SETID_MSISDN) == AGPS_RIL_REQUEST_SETID_MSISDN) {
1694 String data_temp = phone.getLine1Number();
1695 if (data_temp == null) {
1696 // This means the framework does not have the SIM card ready.
1697 } else {
1698 // This means the framework has the SIM card.
1699 data = data_temp;
1700 type = AGPS_SETID_TYPE_MSISDN;
1701 }
1702 }
1703 native_agps_set_id(type, data);
1704 }
1705
1706 /**
Mike Lockwood9b9fb5c2011-06-29 15:09:40 -04001707 * Called from native code to request utc time info
1708 */
1709
1710 private void requestUtcTime() {
1711 sendMessage(INJECT_NTP_TIME, 0, null);
1712 }
1713
1714 /**
Miguel Torroja1e84da82010-07-27 07:02:24 +02001715 * Called from native code to request reference location info
1716 */
1717
1718 private void requestRefLocation(int flags) {
1719 TelephonyManager phone = (TelephonyManager)
1720 mContext.getSystemService(Context.TELEPHONY_SERVICE);
Victoria Leased50d0c32012-10-29 13:16:17 -07001721 final int phoneType = phone.getPhoneType();
1722 if (phoneType == TelephonyManager.PHONE_TYPE_GSM) {
Miguel Torroja1e84da82010-07-27 07:02:24 +02001723 GsmCellLocation gsm_cell = (GsmCellLocation) phone.getCellLocation();
Victoria Leased50d0c32012-10-29 13:16:17 -07001724 if ((gsm_cell != null) && (phone.getNetworkOperator() != null)
1725 && (phone.getNetworkOperator().length() > 3)) {
Miguel Torroja1e84da82010-07-27 07:02:24 +02001726 int type;
1727 int mcc = Integer.parseInt(phone.getNetworkOperator().substring(0,3));
1728 int mnc = Integer.parseInt(phone.getNetworkOperator().substring(3));
Mike Lockwoodedc0f3872010-10-22 09:16:17 -04001729 int networkType = phone.getNetworkType();
1730 if (networkType == TelephonyManager.NETWORK_TYPE_UMTS
1731 || networkType == TelephonyManager.NETWORK_TYPE_HSDPA
1732 || networkType == TelephonyManager.NETWORK_TYPE_HSUPA
Arun Ravindran58d46122012-07-30 17:50:21 +03001733 || networkType == TelephonyManager.NETWORK_TYPE_HSPA
1734 || networkType == TelephonyManager.NETWORK_TYPE_HSPAP) {
Miguel Torroja1e84da82010-07-27 07:02:24 +02001735 type = AGPS_REF_LOCATION_TYPE_UMTS_CELLID;
Mike Lockwoodedc0f3872010-10-22 09:16:17 -04001736 } else {
Miguel Torroja1e84da82010-07-27 07:02:24 +02001737 type = AGPS_REF_LOCATION_TYPE_GSM_CELLID;
Mike Lockwoodedc0f3872010-10-22 09:16:17 -04001738 }
Miguel Torroja1e84da82010-07-27 07:02:24 +02001739 native_agps_set_ref_location_cellid(type, mcc, mnc,
1740 gsm_cell.getLac(), gsm_cell.getCid());
Mike Lockwoodedc0f3872010-10-22 09:16:17 -04001741 } else {
Miguel Torroja1e84da82010-07-27 07:02:24 +02001742 Log.e(TAG,"Error getting cell location info.");
Mike Lockwoodedc0f3872010-10-22 09:16:17 -04001743 }
Victoria Leased50d0c32012-10-29 13:16:17 -07001744 } else if (phoneType == TelephonyManager.PHONE_TYPE_CDMA) {
1745 Log.e(TAG, "CDMA not supported.");
Mike Lockwoodedc0f3872010-10-22 09:16:17 -04001746 }
Miguel Torroja1e84da82010-07-27 07:02:24 +02001747 }
Danke Xie22d1f9f2009-08-18 18:28:45 -04001748
Mike Lockwood98e48692010-04-07 16:32:51 -04001749 private void sendMessage(int message, int arg, Object obj) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001750 // hold a wake lock until this message is delivered
Jeff Brown028872f2012-08-25 13:07:01 -07001751 // note that this assumes the message will not be removed from the queue before
1752 // it is handled (otherwise the wake lock would be leaked).
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001753 mWakeLock.acquire();
1754 mHandler.obtainMessage(message, arg, 1, obj).sendToTarget();
Mike Lockwood98e48692010-04-07 16:32:51 -04001755 }
1756
Mike Lockwood62a8fc12010-03-22 14:23:26 -04001757 private final class ProviderHandler extends Handler {
Victoria Lease5cd731a2012-12-19 15:04:21 -08001758 public ProviderHandler(Looper looper) {
1759 super(looper, null, true /*async*/);
Jeff Brown028872f2012-08-25 13:07:01 -07001760 }
1761
Mike Lockwood62a8fc12010-03-22 14:23:26 -04001762 @Override
Mike Lockwood4a7b65e2010-10-25 16:35:55 -04001763 public void handleMessage(Message msg) {
Mike Lockwood98e48692010-04-07 16:32:51 -04001764 int message = msg.what;
1765 switch (message) {
Mike Lockwood62a8fc12010-03-22 14:23:26 -04001766 case ENABLE:
1767 if (msg.arg1 == 1) {
1768 handleEnable();
1769 } else {
1770 handleDisable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001771 }
Mike Lockwood62a8fc12010-03-22 14:23:26 -04001772 break;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001773 case SET_REQUEST:
1774 GpsRequest gpsRequest = (GpsRequest) msg.obj;
1775 handleSetRequest(gpsRequest.request, gpsRequest.source);
Mike Lockwood03ca2162010-04-01 08:10:09 -07001776 break;
Mike Lockwood62a8fc12010-03-22 14:23:26 -04001777 case UPDATE_NETWORK_STATE:
1778 handleUpdateNetworkState(msg.arg1, (NetworkInfo)msg.obj);
1779 break;
1780 case INJECT_NTP_TIME:
1781 handleInjectNtpTime();
1782 break;
1783 case DOWNLOAD_XTRA_DATA:
Mike Lockwood1a1cd3a2010-08-17 07:42:54 -04001784 if (mSupportsXtra) {
Mike Lockwood62a8fc12010-03-22 14:23:26 -04001785 handleDownloadXtraData();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001786 }
Mike Lockwood62a8fc12010-03-22 14:23:26 -04001787 break;
Kevin Tang40e1baf2012-01-10 14:32:44 -08001788 case INJECT_NTP_TIME_FINISHED:
1789 mInjectNtpTimePending = STATE_IDLE;
1790 break;
1791 case DOWNLOAD_XTRA_DATA_FINISHED:
1792 mDownloadXtraDataPending = STATE_IDLE;
1793 break;
Mike Lockwood62a8fc12010-03-22 14:23:26 -04001794 case UPDATE_LOCATION:
1795 handleUpdateLocation((Location)msg.obj);
1796 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001797 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001798 if (msg.arg2 == 1) {
1799 // wakelock was taken for this message, release it
1800 mWakeLock.release();
Mike Lockwood98e48692010-04-07 16:32:51 -04001801 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001802 }
Mike Lockwood62a8fc12010-03-22 14:23:26 -04001803 };
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001804
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001805 private final class NetworkLocationListener implements LocationListener {
1806 @Override
1807 public void onLocationChanged(Location location) {
1808 // this callback happens on mHandler looper
1809 if (LocationManager.NETWORK_PROVIDER.equals(location.getProvider())) {
1810 handleUpdateLocation(location);
1811 }
1812 }
1813 @Override
1814 public void onStatusChanged(String provider, int status, Bundle extras) { }
1815 @Override
1816 public void onProviderEnabled(String provider) { }
1817 @Override
1818 public void onProviderDisabled(String provider) { }
1819 }
1820
Kevin Tanga5fe6b22011-06-05 14:25:16 -07001821 private String getSelectedApn() {
1822 Uri uri = Uri.parse("content://telephony/carriers/preferapn");
1823 String apn = null;
1824
1825 Cursor cursor = mContext.getContentResolver().query(uri, new String[] {"apn"},
1826 null, null, Carriers.DEFAULT_SORT_ORDER);
1827
1828 if (null != cursor) {
1829 try {
1830 if (cursor.moveToFirst()) {
1831 apn = cursor.getString(0);
1832 }
1833 } finally {
1834 cursor.close();
1835 }
1836 }
1837 return apn;
1838 }
1839
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001840 @Override
1841 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1842 StringBuilder s = new StringBuilder();
1843 s.append(" mFixInterval=").append(mFixInterval).append("\n");
1844 s.append(" mEngineCapabilities=0x").append(Integer.toHexString(mEngineCapabilities)).append(" (");
1845 if (hasCapability(GPS_CAPABILITY_SCHEDULING)) s.append("SCHED ");
1846 if (hasCapability(GPS_CAPABILITY_MSB)) s.append("MSB ");
1847 if (hasCapability(GPS_CAPABILITY_MSA)) s.append("MSA ");
1848 if (hasCapability(GPS_CAPABILITY_SINGLE_SHOT)) s.append("SINGLE_SHOT ");
1849 if (hasCapability(GPS_CAPABILITY_ON_DEMAND_TIME)) s.append("ON_DEMAND_TIME ");
1850 s.append(")\n");
1851
1852 s.append(native_get_internal_state());
1853 pw.append(s);
1854 }
1855
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001856 // for GPS SV statistics
1857 private static final int MAX_SVS = 32;
1858 private static final int EPHEMERIS_MASK = 0;
1859 private static final int ALMANAC_MASK = 1;
1860 private static final int USED_FOR_FIX_MASK = 2;
1861
1862 // preallocated arrays, to avoid memory allocation in reportStatus()
1863 private int mSvs[] = new int[MAX_SVS];
1864 private float mSnrs[] = new float[MAX_SVS];
1865 private float mSvElevations[] = new float[MAX_SVS];
1866 private float mSvAzimuths[] = new float[MAX_SVS];
1867 private int mSvMasks[] = new int[3];
1868 private int mSvCount;
Mike Lockwoodb16e7802009-08-06 09:26:02 -04001869 // preallocated to avoid memory allocation in reportNmea()
1870 private byte[] mNmeaBuffer = new byte[120];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001871
1872 static { class_init_native(); }
1873 private static native void class_init_native();
1874 private static native boolean native_is_supported();
1875
1876 private native boolean native_init();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001877 private native void native_cleanup();
Mike Lockwood04598b62010-04-14 17:17:24 -04001878 private native boolean native_set_position_mode(int mode, int recurrence, int min_interval,
1879 int preferred_accuracy, int preferred_time);
1880 private native boolean native_start();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001881 private native boolean native_stop();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001882 private native void native_delete_aiding_data(int flags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001883 // returns number of SVs
1884 // mask[0] is ephemeris mask and mask[1] is almanac mask
1885 private native int native_read_sv_status(int[] svs, float[] snrs,
1886 float[] elevations, float[] azimuths, int[] masks);
Mike Lockwoodf602d362010-06-20 14:28:16 -07001887 private native int native_read_nmea(byte[] buffer, int bufferSize);
Mike Lockwoodd26ce0d2009-06-11 12:25:46 -04001888 private native void native_inject_location(double latitude, double longitude, float accuracy);
1889
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06001890 // XTRA Support
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001891 private native void native_inject_time(long time, long timeReference, int uncertainty);
1892 private native boolean native_supports_xtra();
1893 private native void native_inject_xtra_data(byte[] data, int length);
The Android Open Source Project10592532009-03-18 17:39:46 -07001894
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06001895 // DEBUG Support
1896 private native String native_get_internal_state();
1897
1898 // AGPS Support
Mike Lockwoode3635c92009-05-11 08:38:02 -04001899 private native void native_agps_data_conn_open(String apn);
1900 private native void native_agps_data_conn_closed();
1901 private native void native_agps_data_conn_failed();
Miguel Torroja1e84da82010-07-27 07:02:24 +02001902 private native void native_agps_ni_message(byte [] msg, int length);
Mike Lockwooda9e54612009-06-19 14:54:42 -04001903 private native void native_set_agps_server(int type, String hostname, int port);
Danke Xie22d1f9f2009-08-18 18:28:45 -04001904
1905 // Network-initiated (NI) Support
1906 private native void native_send_ni_response(int notificationId, int userResponse);
Miguel Torroja1e84da82010-07-27 07:02:24 +02001907
1908 // AGPS ril suport
1909 private native void native_agps_set_ref_location_cellid(int type, int mcc, int mnc,
1910 int lac, int cid);
1911 private native void native_agps_set_id(int type, String setid);
Mike Lockwood50130bb2010-10-11 06:22:50 -04001912
1913 private native void native_update_network_state(boolean connected, int type,
Kevin Tanga5fe6b22011-06-05 14:25:16 -07001914 boolean roaming, boolean available, String extraInfo, String defaultAPN);
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -07001915
1916 // Hardware Geofence support.
1917 private static native boolean native_is_geofence_supported();
1918 private static native boolean native_add_geofence(int geofenceId, double latitude,
1919 double longitude, double radius, int lastTransition,int monitorTransitions,
1920 int notificationResponsivenes, int unknownTimer);
1921 private static native boolean native_remove_geofence(int geofenceId);
1922 private static native boolean native_resume_geofence(int geofenceId, int transitions);
1923 private static native boolean native_pause_geofence(int geofenceId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001924}