blob: 38453c883ba65fbac6975091dc3654332ebdddda [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;
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -070027import android.hardware.location.GeofenceHardwareImpl;
28import android.hardware.location.IGeofenceHardware;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080029import android.location.Criteria;
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -070030import android.location.IGpsGeofenceHardware;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080031import android.location.IGpsStatusListener;
Mike Lockwood15e3d0f2009-05-01 07:53:28 -040032import android.location.IGpsStatusProvider;
Mike Lockwood4e50b782009-04-03 08:24:43 -070033import android.location.ILocationManager;
Danke Xie22d1f9f2009-08-18 18:28:45 -040034import android.location.INetInitiatedListener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080035import android.location.Location;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070036import android.location.LocationListener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080037import android.location.LocationManager;
38import android.location.LocationProvider;
Stan Chesnutt1d72d8c2013-04-15 19:18:02 -070039import android.location.LocationRequest;
Mike Lockwood58bda982009-04-14 16:25:07 -040040import android.net.ConnectivityManager;
Mike Lockwood03d24672009-10-08 15:45:03 -040041import android.net.NetworkInfo;
Kevin Tanga5fe6b22011-06-05 14:25:16 -070042import android.net.Uri;
Kevin Tang40e1baf2012-01-10 14:32:44 -080043import android.os.AsyncTask;
Dianne Hackborn91268cf2013-06-13 19:06:50 -070044import android.os.BatteryStats;
Mike Lockwood63aa5a62010-04-14 19:21:31 -040045import android.os.Binder;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080046import android.os.Bundle;
Mike Lockwood62a8fc12010-03-22 14:23:26 -040047import android.os.Handler;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080048import android.os.IBinder;
Victoria Lease5cd731a2012-12-19 15:04:21 -080049import android.os.Looper;
Mike Lockwood62a8fc12010-03-22 14:23:26 -040050import android.os.Message;
Mike Lockwood0528b9b2009-05-07 10:12:54 -040051import android.os.PowerManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080052import android.os.RemoteException;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -040053import android.os.ServiceManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080054import android.os.SystemClock;
Dianne Hackborn5ac72a22012-08-29 18:32:08 -070055import android.os.UserHandle;
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -070056import android.os.WorkSource;
Mike Lockwoodbcab8df2009-06-25 16:39:09 -040057import android.provider.Settings;
Kevin Tanga5fe6b22011-06-05 14:25:16 -070058import android.provider.Telephony.Carriers;
Miguel Torroja1e84da82010-07-27 07:02:24 +020059import android.provider.Telephony.Sms.Intents;
Jake Hambyb49a73d2011-03-15 20:09:46 -070060import android.telephony.SmsMessage;
Miguel Torroja1e84da82010-07-27 07:02:24 +020061import android.telephony.TelephonyManager;
62import android.telephony.gsm.GsmCellLocation;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080063import android.util.Log;
Jeff Sharkey104344e2011-07-10 14:20:41 -070064import android.util.NtpTrustedTime;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080065
66import com.android.internal.app.IAppOpsService;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -040067import com.android.internal.app.IBatteryStats;
Danke Xie22d1f9f2009-08-18 18:28:45 -040068import com.android.internal.location.GpsNetInitiatedHandler;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070069import com.android.internal.location.ProviderProperties;
70import com.android.internal.location.ProviderRequest;
Danke Xie22d1f9f2009-08-18 18:28:45 -040071import com.android.internal.location.GpsNetInitiatedHandler.GpsNiNotification;
Jake Hambyb49a73d2011-03-15 20:09:46 -070072import com.android.internal.telephony.Phone;
Wink Savillea639b312012-07-10 12:37:54 -070073import com.android.internal.telephony.PhoneConstants;
The Android Open Source Project10592532009-03-18 17:39:46 -070074
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080075import java.io.File;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070076import java.io.FileDescriptor;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080077import java.io.FileInputStream;
78import java.io.IOException;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070079import java.io.PrintWriter;
Jeff Sharkey104344e2011-07-10 14:20:41 -070080import java.io.StringReader;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080081import java.util.ArrayList;
Mike Lockwoodf1218be2010-01-29 09:20:06 -050082import java.util.Date;
Danke Xie22d1f9f2009-08-18 18:28:45 -040083import java.util.Map.Entry;
Jake Hambyb49a73d2011-03-15 20:09:46 -070084import java.util.Properties;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080085
86/**
87 * A GPS implementation of LocationProvider used by LocationManager.
88 *
89 * {@hide}
90 */
Mike Lockwood89096312010-03-24 10:14:55 -040091public class GpsLocationProvider implements LocationProviderInterface {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080092
93 private static final String TAG = "GpsLocationProvider";
Mike Lockwood29c84342009-05-06 14:01:15 -040094
Brian Muramatsu1715cb32012-08-08 17:32:21 -070095 private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
96 private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
Mike Lockwood62a8fc12010-03-22 14:23:26 -040097
Nick Pelly6fa9ad42012-07-16 12:18:23 -070098 private static final ProviderProperties PROPERTIES = new ProviderProperties(
99 true, true, false, false, true, true, true,
100 Criteria.POWER_HIGH, Criteria.ACCURACY_FINE);
101
The Android Open Source Project10592532009-03-18 17:39:46 -0700102 // these need to match GpsPositionMode enum in gps.h
103 private static final int GPS_POSITION_MODE_STANDALONE = 0;
104 private static final int GPS_POSITION_MODE_MS_BASED = 1;
105 private static final int GPS_POSITION_MODE_MS_ASSISTED = 2;
106
Mike Lockwood04598b62010-04-14 17:17:24 -0400107 // these need to match GpsPositionRecurrence enum in gps.h
108 private static final int GPS_POSITION_RECURRENCE_PERIODIC = 0;
109 private static final int GPS_POSITION_RECURRENCE_SINGLE = 1;
110
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800111 // these need to match GpsStatusValue defines in gps.h
112 private static final int GPS_STATUS_NONE = 0;
113 private static final int GPS_STATUS_SESSION_BEGIN = 1;
114 private static final int GPS_STATUS_SESSION_END = 2;
115 private static final int GPS_STATUS_ENGINE_ON = 3;
116 private static final int GPS_STATUS_ENGINE_OFF = 4;
117
Mike Lockwoode3635c92009-05-11 08:38:02 -0400118 // these need to match GpsApgsStatusValue defines in gps.h
119 /** AGPS status event values. */
120 private static final int GPS_REQUEST_AGPS_DATA_CONN = 1;
121 private static final int GPS_RELEASE_AGPS_DATA_CONN = 2;
122 private static final int GPS_AGPS_DATA_CONNECTED = 3;
123 private static final int GPS_AGPS_DATA_CONN_DONE = 4;
124 private static final int GPS_AGPS_DATA_CONN_FAILED = 5;
Mike Lockwood58bda982009-04-14 16:25:07 -0400125
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800126 // these need to match GpsLocationFlags enum in gps.h
127 private static final int LOCATION_INVALID = 0;
128 private static final int LOCATION_HAS_LAT_LONG = 1;
129 private static final int LOCATION_HAS_ALTITUDE = 2;
130 private static final int LOCATION_HAS_SPEED = 4;
131 private static final int LOCATION_HAS_BEARING = 8;
132 private static final int LOCATION_HAS_ACCURACY = 16;
Mike Lockwoode3635c92009-05-11 08:38:02 -0400133
134// IMPORTANT - the GPS_DELETE_* symbols here must match constants in gps.h
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800135 private static final int GPS_DELETE_EPHEMERIS = 0x0001;
136 private static final int GPS_DELETE_ALMANAC = 0x0002;
137 private static final int GPS_DELETE_POSITION = 0x0004;
138 private static final int GPS_DELETE_TIME = 0x0008;
139 private static final int GPS_DELETE_IONO = 0x0010;
140 private static final int GPS_DELETE_UTC = 0x0020;
141 private static final int GPS_DELETE_HEALTH = 0x0040;
142 private static final int GPS_DELETE_SVDIR = 0x0080;
143 private static final int GPS_DELETE_SVSTEER = 0x0100;
144 private static final int GPS_DELETE_SADATA = 0x0200;
145 private static final int GPS_DELETE_RTI = 0x0400;
146 private static final int GPS_DELETE_CELLDB_INFO = 0x8000;
147 private static final int GPS_DELETE_ALL = 0xFFFF;
148
Mike Lockwood04598b62010-04-14 17:17:24 -0400149 // The GPS_CAPABILITY_* flags must match the values in gps.h
150 private static final int GPS_CAPABILITY_SCHEDULING = 0x0000001;
151 private static final int GPS_CAPABILITY_MSB = 0x0000002;
152 private static final int GPS_CAPABILITY_MSA = 0x0000004;
153 private static final int GPS_CAPABILITY_SINGLE_SHOT = 0x0000008;
Mike Lockwood9b9fb5c2011-06-29 15:09:40 -0400154 private static final int GPS_CAPABILITY_ON_DEMAND_TIME = 0x0000010;
Mike Lockwood04598b62010-04-14 17:17:24 -0400155
Mike Lockwoode3635c92009-05-11 08:38:02 -0400156 // these need to match AGpsType enum in gps.h
157 private static final int AGPS_TYPE_SUPL = 1;
158 private static final int AGPS_TYPE_C2K = 2;
159
160 // for mAGpsDataConnectionState
161 private static final int AGPS_DATA_CONNECTION_CLOSED = 0;
162 private static final int AGPS_DATA_CONNECTION_OPENING = 1;
163 private static final int AGPS_DATA_CONNECTION_OPEN = 2;
Mike Lockwood58bda982009-04-14 16:25:07 -0400164
Mike Lockwood62a8fc12010-03-22 14:23:26 -0400165 // Handler messages
166 private static final int CHECK_LOCATION = 1;
167 private static final int ENABLE = 2;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700168 private static final int SET_REQUEST = 3;
Mike Lockwood62a8fc12010-03-22 14:23:26 -0400169 private static final int UPDATE_NETWORK_STATE = 4;
170 private static final int INJECT_NTP_TIME = 5;
171 private static final int DOWNLOAD_XTRA_DATA = 6;
172 private static final int UPDATE_LOCATION = 7;
173 private static final int ADD_LISTENER = 8;
174 private static final int REMOVE_LISTENER = 9;
Kevin Tang40e1baf2012-01-10 14:32:44 -0800175 private static final int INJECT_NTP_TIME_FINISHED = 10;
176 private static final int DOWNLOAD_XTRA_DATA_FINISHED = 11;
Mike Lockwood62a8fc12010-03-22 14:23:26 -0400177
Miguel Torroja1e84da82010-07-27 07:02:24 +0200178 // Request setid
179 private static final int AGPS_RIL_REQUEST_SETID_IMSI = 1;
180 private static final int AGPS_RIL_REQUEST_SETID_MSISDN = 2;
181
182 // Request ref location
183 private static final int AGPS_RIL_REQUEST_REFLOC_CELLID = 1;
184 private static final int AGPS_RIL_REQUEST_REFLOC_MAC = 2;
185
186 // ref. location info
187 private static final int AGPS_REF_LOCATION_TYPE_GSM_CELLID = 1;
188 private static final int AGPS_REF_LOCATION_TYPE_UMTS_CELLID = 2;
189 private static final int AGPS_REG_LOCATION_TYPE_MAC = 3;
190
191 // set id info
192 private static final int AGPS_SETID_TYPE_NONE = 0;
193 private static final int AGPS_SETID_TYPE_IMSI = 1;
194 private static final int AGPS_SETID_TYPE_MSISDN = 2;
195
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800196 private static final String PROPERTIES_FILE = "/etc/gps.conf";
197
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700198 /** simpler wrapper for ProviderRequest + Worksource */
199 private static class GpsRequest {
200 public ProviderRequest request;
201 public WorkSource source;
202 public GpsRequest(ProviderRequest request, WorkSource source) {
203 this.request = request;
204 this.source = source;
205 }
206 }
207
208 private Object mLock = new Object();
209
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800210 private int mLocationFlags = LOCATION_INVALID;
211
212 // current status
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400213 private int mStatus = LocationProvider.TEMPORARILY_UNAVAILABLE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800214
215 // time for last status update
216 private long mStatusUpdateTime = SystemClock.elapsedRealtime();
Mike Lockwoodd53ba012010-04-15 20:41:26 -0400217
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800218 // turn off GPS fix icon if we haven't received a fix in 10 seconds
Mike Lockwood04598b62010-04-14 17:17:24 -0400219 private static final long RECENT_FIX_TIMEOUT = 10 * 1000;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800220
Mike Lockwood0632ca72009-05-14 15:51:03 -0400221 // stop trying if we do not receive a fix within 60 seconds
Mike Lockwood04598b62010-04-14 17:17:24 -0400222 private static final int NO_FIX_TIMEOUT = 60 * 1000;
Mike Lockwood0632ca72009-05-14 15:51:03 -0400223
Nick Pellyb041f232012-05-07 17:12:25 -0700224 // if the fix interval is below this we leave GPS on,
225 // if above then we cycle the GPS driver.
226 // Typical hot TTTF is ~5 seconds, so 10 seconds seems sane.
227 private static final int GPS_POLLING_THRESHOLD_INTERVAL = 10 * 1000;
228
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700229 // how often to request NTP time, in milliseconds
230 // current setting 24 hours
231 private static final long NTP_INTERVAL = 24*60*60*1000;
232 // how long to wait if we have a network error in NTP or XTRA downloading
233 // current setting - 5 minutes
234 private static final long RETRY_INTERVAL = 5*60*1000;
235
236 // true if we are enabled, protected by this
237 private boolean mEnabled;
238
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800239 // true if we have network connectivity
240 private boolean mNetworkAvailable;
241
Kevin Tang40e1baf2012-01-10 14:32:44 -0800242 // states for injecting ntp and downloading xtra data
243 private static final int STATE_PENDING_NETWORK = 0;
244 private static final int STATE_DOWNLOADING = 1;
245 private static final int STATE_IDLE = 2;
246
Mike Lockwood62a8fc12010-03-22 14:23:26 -0400247 // flags to trigger NTP or XTRA data download when network becomes available
248 // initialized to true so we do NTP and XTRA when the network comes up after booting
Kevin Tang40e1baf2012-01-10 14:32:44 -0800249 private int mInjectNtpTimePending = STATE_PENDING_NETWORK;
250 private int mDownloadXtraDataPending = STATE_PENDING_NETWORK;
Mike Lockwood62a8fc12010-03-22 14:23:26 -0400251
Mike Lockwood9b9fb5c2011-06-29 15:09:40 -0400252 // set to true if the GPS engine does not do on-demand NTP time requests
253 private boolean mPeriodicTimeInjection;
254
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800255 // true if GPS is navigating
256 private boolean mNavigating;
Mike Lockwoodcf1d8cb2010-01-20 10:14:54 -0500257
258 // true if GPS engine is on
259 private boolean mEngineOn;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700260
Mike Lockwood04598b62010-04-14 17:17:24 -0400261 // requested frequency of fixes, in milliseconds
262 private int mFixInterval = 1000;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800263
264 // true if we started navigation
265 private boolean mStarted;
266
Stan Chesnutt1d72d8c2013-04-15 19:18:02 -0700267 // true if single shot request is in progress
268 private boolean mSingleShot;
269
Mike Lockwood04598b62010-04-14 17:17:24 -0400270 // capabilities of the GPS engine
271 private int mEngineCapabilities;
272
Mike Lockwood1a1cd3a2010-08-17 07:42:54 -0400273 // true if XTRA is supported
274 private boolean mSupportsXtra;
275
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800276 // for calculating time to first fix
277 private long mFixRequestTime = 0;
278 // time to first fix for most recent session
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700279 private int mTimeToFirstFix = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800280 // time we received our last fix
281 private long mLastFixTime;
282
Mike Lockwood04598b62010-04-14 17:17:24 -0400283 private int mPositionMode;
284
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800285 // properties loaded from PROPERTIES_FILE
286 private Properties mProperties;
Mike Lockwood734d6032009-07-28 18:30:25 -0700287 private String mSuplServerHost;
288 private int mSuplServerPort;
289 private String mC2KServerHost;
290 private int mC2KServerPort;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800291
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400292 private final Context mContext;
Jeff Sharkey104344e2011-07-10 14:20:41 -0700293 private final NtpTrustedTime mNtpTime;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700294 private final ILocationManager mILocationManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800295 private Location mLocation = new Location(LocationManager.GPS_PROVIDER);
296 private Bundle mLocationExtras = new Bundle();
297 private ArrayList<Listener> mListeners = new ArrayList<Listener>();
Mike Lockwood62a8fc12010-03-22 14:23:26 -0400298
Victoria Lease5c24fd02012-10-01 11:00:50 -0700299 // Handler for processing events
Mike Lockwood62a8fc12010-03-22 14:23:26 -0400300 private Handler mHandler;
The Android Open Source Project10592532009-03-18 17:39:46 -0700301
Mike Lockwoode3635c92009-05-11 08:38:02 -0400302 private String mAGpsApn;
303 private int mAGpsDataConnectionState;
Stephen Li8efd74d2011-03-01 20:56:00 -0800304 private int mAGpsDataConnectionIpAddr;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400305 private final ConnectivityManager mConnMgr;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700306 private final GpsNetInitiatedHandler mNIHandler;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400307
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400308 // Wakelocks
309 private final static String WAKELOCK_KEY = "GpsLocationProvider";
310 private final PowerManager.WakeLock mWakeLock;
311
Mike Lockwood29c84342009-05-06 14:01:15 -0400312 // Alarms
313 private final static String ALARM_WAKEUP = "com.android.internal.location.ALARM_WAKEUP";
Mike Lockwood0632ca72009-05-14 15:51:03 -0400314 private final static String ALARM_TIMEOUT = "com.android.internal.location.ALARM_TIMEOUT";
Mike Lockwood29c84342009-05-06 14:01:15 -0400315 private final AlarmManager mAlarmManager;
316 private final PendingIntent mWakeupIntent;
Mike Lockwood0632ca72009-05-14 15:51:03 -0400317 private final PendingIntent mTimeoutIntent;
Mike Lockwood29c84342009-05-06 14:01:15 -0400318
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800319 private final IAppOpsService mAppOpsService;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400320 private final IBatteryStats mBatteryStats;
The Android Open Source Project10592532009-03-18 17:39:46 -0700321
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700322 // only modified on handler thread
Dianne Hackborn002a54e2013-01-10 17:34:55 -0800323 private WorkSource mClientSource = new WorkSource();
Mike Lockwoodf1218be2010-01-29 09:20:06 -0500324
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -0700325 private GeofenceHardwareImpl mGeofenceHardwareImpl;
326
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400327 private final IGpsStatusProvider mGpsStatusProvider = new IGpsStatusProvider.Stub() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700328 @Override
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400329 public void addGpsStatusListener(IGpsStatusListener listener) throws RemoteException {
330 if (listener == null) {
331 throw new NullPointerException("listener is null in addGpsStatusListener");
332 }
333
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700334 synchronized (mListeners) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400335 IBinder binder = listener.asBinder();
336 int size = mListeners.size();
337 for (int i = 0; i < size; i++) {
338 Listener test = mListeners.get(i);
339 if (binder.equals(test.mListener.asBinder())) {
340 // listener already added
341 return;
342 }
343 }
344
345 Listener l = new Listener(listener);
346 binder.linkToDeath(l, 0);
347 mListeners.add(l);
348 }
349 }
350
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700351 @Override
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400352 public void removeGpsStatusListener(IGpsStatusListener listener) {
353 if (listener == null) {
354 throw new NullPointerException("listener is null in addGpsStatusListener");
355 }
356
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700357 synchronized (mListeners) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400358 IBinder binder = listener.asBinder();
359 Listener l = null;
360 int size = mListeners.size();
361 for (int i = 0; i < size && l == null; i++) {
362 Listener test = mListeners.get(i);
363 if (binder.equals(test.mListener.asBinder())) {
364 l = test;
365 }
366 }
367
368 if (l != null) {
369 mListeners.remove(l);
370 binder.unlinkToDeath(l, 0);
371 }
372 }
373 }
374 };
375
376 public IGpsStatusProvider getGpsStatusProvider() {
377 return mGpsStatusProvider;
378 }
379
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -0700380 public IGpsGeofenceHardware getGpsGeofenceProxy() {
381 return mGpsGeofenceBinder;
382 }
383
Mike Lockwood29c84342009-05-06 14:01:15 -0400384 private final BroadcastReceiver mBroadcastReciever = new BroadcastReceiver() {
The Android Open Source Project10592532009-03-18 17:39:46 -0700385 @Override public void onReceive(Context context, Intent intent) {
386 String action = intent.getAction();
387
Mike Lockwood29c84342009-05-06 14:01:15 -0400388 if (action.equals(ALARM_WAKEUP)) {
389 if (DEBUG) Log.d(TAG, "ALARM_WAKEUP");
Stan Chesnutt1d72d8c2013-04-15 19:18:02 -0700390 startNavigating(false);
Mike Lockwood0632ca72009-05-14 15:51:03 -0400391 } else if (action.equals(ALARM_TIMEOUT)) {
392 if (DEBUG) Log.d(TAG, "ALARM_TIMEOUT");
393 hibernate();
Miguel Torroja1e84da82010-07-27 07:02:24 +0200394 } else if (action.equals(Intents.DATA_SMS_RECEIVED_ACTION)) {
395 checkSmsSuplInit(intent);
396 } else if (action.equals(Intents.WAP_PUSH_RECEIVED_ACTION)) {
397 checkWapSuplInit(intent);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700398 } else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
399 int networkState;
400 if (intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false)) {
401 networkState = LocationProvider.TEMPORARILY_UNAVAILABLE;
402 } else {
403 networkState = LocationProvider.AVAILABLE;
404 }
405
406 // retrieve NetworkInfo result for this UID
407 NetworkInfo info =
408 intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
409 ConnectivityManager connManager = (ConnectivityManager)
410 mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
411 info = connManager.getNetworkInfo(info.getType());
412
413 updateNetworkState(networkState, info);
Miguel Torroja1e84da82010-07-27 07:02:24 +0200414 }
The Android Open Source Project10592532009-03-18 17:39:46 -0700415 }
Mike Lockwood29c84342009-05-06 14:01:15 -0400416 };
The Android Open Source Project10592532009-03-18 17:39:46 -0700417
Miguel Torroja1e84da82010-07-27 07:02:24 +0200418 private void checkSmsSuplInit(Intent intent) {
419 SmsMessage[] messages = Intents.getMessagesFromIntent(intent);
420 for (int i=0; i <messages.length; i++) {
421 byte[] supl_init = messages[i].getUserData();
422 native_agps_ni_message(supl_init,supl_init.length);
423 }
424 }
425
426 private void checkWapSuplInit(Intent intent) {
427 byte[] supl_init = (byte[]) intent.getExtra("data");
428 native_agps_ni_message(supl_init,supl_init.length);
429 }
430
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800431 public static boolean isSupported() {
432 return native_is_supported();
433 }
434
Victoria Lease5cd731a2012-12-19 15:04:21 -0800435 public GpsLocationProvider(Context context, ILocationManager ilocationManager,
436 Looper looper) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800437 mContext = context;
Jeff Sharkey104344e2011-07-10 14:20:41 -0700438 mNtpTime = NtpTrustedTime.getInstance(context);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700439 mILocationManager = ilocationManager;
Mike Lockwood79e642e2010-03-17 23:19:25 -0400440 mNIHandler = new GpsNetInitiatedHandler(context);
Mike Lockwood63598a02010-02-24 11:52:59 -0500441
442 mLocation.setExtras(mLocationExtras);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800443
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400444 // Create a wake lock
445 PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
446 mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700447 mWakeLock.setReferenceCounted(true);
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400448
Mike Lockwood29c84342009-05-06 14:01:15 -0400449 mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
450 mWakeupIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_WAKEUP), 0);
Mike Lockwood0632ca72009-05-14 15:51:03 -0400451 mTimeoutIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_TIMEOUT), 0);
Mike Lockwood29c84342009-05-06 14:01:15 -0400452
Mike Lockwood58bda982009-04-14 16:25:07 -0400453 mConnMgr = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
454
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800455 // App ops service to keep track of who is accessing the GPS
456 mAppOpsService = IAppOpsService.Stub.asInterface(ServiceManager.getService(
457 Context.APP_OPS_SERVICE));
458
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400459 // Battery statistics service to be notified when GPS turns on or off
Dianne Hackborn91268cf2013-06-13 19:06:50 -0700460 mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService(
461 BatteryStats.SERVICE_NAME));
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400462
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800463 mProperties = new Properties();
464 try {
465 File file = new File(PROPERTIES_FILE);
466 FileInputStream stream = new FileInputStream(file);
467 mProperties.load(stream);
468 stream.close();
Mike Lockwoode3635c92009-05-11 08:38:02 -0400469
Mike Lockwood734d6032009-07-28 18:30:25 -0700470 mSuplServerHost = mProperties.getProperty("SUPL_HOST");
Mike Lockwoode3635c92009-05-11 08:38:02 -0400471 String portString = mProperties.getProperty("SUPL_PORT");
Mike Lockwood734d6032009-07-28 18:30:25 -0700472 if (mSuplServerHost != null && portString != null) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700473 try {
Mike Lockwood734d6032009-07-28 18:30:25 -0700474 mSuplServerPort = Integer.parseInt(portString);
The Android Open Source Project10592532009-03-18 17:39:46 -0700475 } catch (NumberFormatException e) {
Mike Lockwoode3635c92009-05-11 08:38:02 -0400476 Log.e(TAG, "unable to parse SUPL_PORT: " + portString);
477 }
478 }
479
Mike Lockwood734d6032009-07-28 18:30:25 -0700480 mC2KServerHost = mProperties.getProperty("C2K_HOST");
Mike Lockwoode3635c92009-05-11 08:38:02 -0400481 portString = mProperties.getProperty("C2K_PORT");
Mike Lockwood734d6032009-07-28 18:30:25 -0700482 if (mC2KServerHost != null && portString != null) {
Mike Lockwoode3635c92009-05-11 08:38:02 -0400483 try {
Mike Lockwood734d6032009-07-28 18:30:25 -0700484 mC2KServerPort = Integer.parseInt(portString);
Mike Lockwoode3635c92009-05-11 08:38:02 -0400485 } catch (NumberFormatException e) {
486 Log.e(TAG, "unable to parse C2K_PORT: " + portString);
The Android Open Source Project10592532009-03-18 17:39:46 -0700487 }
488 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800489 } catch (IOException e) {
490 Log.w(TAG, "Could not open GPS configuration file " + PROPERTIES_FILE);
491 }
Mike Lockwood62a8fc12010-03-22 14:23:26 -0400492
Victoria Lease5c24fd02012-10-01 11:00:50 -0700493 // construct handler, listen for events
Victoria Lease5cd731a2012-12-19 15:04:21 -0800494 mHandler = new ProviderHandler(looper);
Victoria Lease5c24fd02012-10-01 11:00:50 -0700495 listenForBroadcasts();
496
497 // also listen for PASSIVE_PROVIDER updates
498 mHandler.post(new Runnable() {
499 @Override
500 public void run() {
501 LocationManager locManager =
502 (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
503 locManager.requestLocationUpdates(LocationManager.PASSIVE_PROVIDER,
504 0, 0, new NetworkLocationListener(), mHandler.getLooper());
Mike Lockwood89096312010-03-24 10:14:55 -0400505 }
Victoria Lease5c24fd02012-10-01 11:00:50 -0700506 });
Mike Lockwood62a8fc12010-03-22 14:23:26 -0400507 }
508
Victoria Lease5c24fd02012-10-01 11:00:50 -0700509 private void listenForBroadcasts() {
Mike Lockwood62a8fc12010-03-22 14:23:26 -0400510 IntentFilter intentFilter = new IntentFilter();
Victoria Lease5c24fd02012-10-01 11:00:50 -0700511 intentFilter.addAction(Intents.DATA_SMS_RECEIVED_ACTION);
512 intentFilter.addDataScheme("sms");
513 intentFilter.addDataAuthority("localhost","7275");
514 mContext.registerReceiver(mBroadcastReciever, intentFilter, null, mHandler);
515
516 intentFilter = new IntentFilter();
517 intentFilter.addAction(Intents.WAP_PUSH_RECEIVED_ACTION);
518 try {
519 intentFilter.addDataType("application/vnd.omaloc-supl-init");
520 } catch (IntentFilter.MalformedMimeTypeException e) {
521 Log.w(TAG, "Malformed SUPL init mime type");
522 }
523 mContext.registerReceiver(mBroadcastReciever, intentFilter, null, mHandler);
524
525 intentFilter = new IntentFilter();
Mike Lockwood62a8fc12010-03-22 14:23:26 -0400526 intentFilter.addAction(ALARM_WAKEUP);
527 intentFilter.addAction(ALARM_TIMEOUT);
Brian Muramatsub94b41f2012-08-21 16:30:57 -0700528 intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
Victoria Lease5c24fd02012-10-01 11:00:50 -0700529 mContext.registerReceiver(mBroadcastReciever, intentFilter, null, mHandler);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800530 }
531
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800532 /**
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500533 * Returns the name of this provider.
534 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700535 @Override
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500536 public String getName() {
537 return LocationManager.GPS_PROVIDER;
538 }
539
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700540 @Override
541 public ProviderProperties getProperties() {
542 return PROPERTIES;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800543 }
544
Mike Lockwood03d24672009-10-08 15:45:03 -0400545 public void updateNetworkState(int state, NetworkInfo info) {
Mike Lockwood98e48692010-04-07 16:32:51 -0400546 sendMessage(UPDATE_NETWORK_STATE, state, info);
Mike Lockwood62a8fc12010-03-22 14:23:26 -0400547 }
548
549 private void handleUpdateNetworkState(int state, NetworkInfo info) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800550 mNetworkAvailable = (state == LocationProvider.AVAILABLE);
551
Joe Onoratof5d95cb2010-01-07 21:48:32 -0500552 if (DEBUG) {
Mike Lockwood03d24672009-10-08 15:45:03 -0400553 Log.d(TAG, "updateNetworkState " + (mNetworkAvailable ? "available" : "unavailable")
554 + " info: " + info);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800555 }
Mike Lockwood03d24672009-10-08 15:45:03 -0400556
Mike Lockwood50130bb2010-10-11 06:22:50 -0400557 if (info != null) {
Jeff Brownbf6f6f92012-09-25 15:03:20 -0700558 boolean dataEnabled = Settings.Global.getInt(mContext.getContentResolver(),
559 Settings.Global.MOBILE_DATA, 1) == 1;
Kevin Tanga5fe6b22011-06-05 14:25:16 -0700560 boolean networkAvailable = info.isAvailable() && dataEnabled;
561 String defaultApn = getSelectedApn();
562 if (defaultApn == null) {
563 defaultApn = "dummy-apn";
564 }
565
Mike Lockwood50130bb2010-10-11 06:22:50 -0400566 native_update_network_state(info.isConnected(), info.getType(),
Kevin Tanga5fe6b22011-06-05 14:25:16 -0700567 info.isRoaming(), networkAvailable,
568 info.getExtraInfo(), defaultApn);
Mike Lockwood50130bb2010-10-11 06:22:50 -0400569 }
570
Mike Lockwood03d24672009-10-08 15:45:03 -0400571 if (info != null && info.getType() == ConnectivityManager.TYPE_MOBILE_SUPL
572 && mAGpsDataConnectionState == AGPS_DATA_CONNECTION_OPENING) {
573 String apnName = info.getExtraInfo();
Stephen Li83b69712011-01-25 18:47:28 -0800574 if (mNetworkAvailable) {
575 if (apnName == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700576 /* Assign a dummy value in the case of C2K as otherwise we will have a runtime
Stephen Li83b69712011-01-25 18:47:28 -0800577 exception in the following call to native_agps_data_conn_open*/
578 apnName = "dummy-apn";
579 }
Mike Lockwood03d24672009-10-08 15:45:03 -0400580 mAGpsApn = apnName;
Stephen Li8efd74d2011-03-01 20:56:00 -0800581 if (DEBUG) Log.d(TAG, "mAGpsDataConnectionIpAddr " + mAGpsDataConnectionIpAddr);
582 if (mAGpsDataConnectionIpAddr != 0xffffffff) {
583 boolean route_result;
584 if (DEBUG) Log.d(TAG, "call requestRouteToHost");
585 route_result = mConnMgr.requestRouteToHost(ConnectivityManager.TYPE_MOBILE_SUPL,
586 mAGpsDataConnectionIpAddr);
587 if (route_result == false) Log.d(TAG, "call requestRouteToHost failed");
588 }
Mike Lockwood03d24672009-10-08 15:45:03 -0400589 if (DEBUG) Log.d(TAG, "call native_agps_data_conn_open");
590 native_agps_data_conn_open(apnName);
591 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPEN;
592 } else {
593 if (DEBUG) Log.d(TAG, "call native_agps_data_conn_failed");
594 mAGpsApn = null;
595 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_CLOSED;
596 native_agps_data_conn_failed();
597 }
598 }
599
Mike Lockwood62a8fc12010-03-22 14:23:26 -0400600 if (mNetworkAvailable) {
Kevin Tang40e1baf2012-01-10 14:32:44 -0800601 if (mInjectNtpTimePending == STATE_PENDING_NETWORK) {
Mike Lockwood98e48692010-04-07 16:32:51 -0400602 sendMessage(INJECT_NTP_TIME, 0, null);
Mike Lockwood62a8fc12010-03-22 14:23:26 -0400603 }
Kevin Tang40e1baf2012-01-10 14:32:44 -0800604 if (mDownloadXtraDataPending == STATE_PENDING_NETWORK) {
Mike Lockwood98e48692010-04-07 16:32:51 -0400605 sendMessage(DOWNLOAD_XTRA_DATA, 0, null);
Mike Lockwood62a8fc12010-03-22 14:23:26 -0400606 }
607 }
608 }
609
610 private void handleInjectNtpTime() {
Kevin Tang40e1baf2012-01-10 14:32:44 -0800611 if (mInjectNtpTimePending == STATE_DOWNLOADING) {
612 // already downloading data
Mike Lockwood62a8fc12010-03-22 14:23:26 -0400613 return;
614 }
Kevin Tang40e1baf2012-01-10 14:32:44 -0800615 if (!mNetworkAvailable) {
616 // try again when network is up
617 mInjectNtpTimePending = STATE_PENDING_NETWORK;
618 return;
Jeff Sharkey104344e2011-07-10 14:20:41 -0700619 }
Kevin Tang40e1baf2012-01-10 14:32:44 -0800620 mInjectNtpTimePending = STATE_DOWNLOADING;
Jeff Sharkey104344e2011-07-10 14:20:41 -0700621
Jeff Brown028872f2012-08-25 13:07:01 -0700622 // hold wake lock while task runs
623 mWakeLock.acquire();
Kevin Tang40e1baf2012-01-10 14:32:44 -0800624 AsyncTask.THREAD_POOL_EXECUTOR.execute(new Runnable() {
625 @Override
626 public void run() {
627 long delay;
Mike Lockwood62a8fc12010-03-22 14:23:26 -0400628
Kevin Tang40e1baf2012-01-10 14:32:44 -0800629 // force refresh NTP cache when outdated
630 if (mNtpTime.getCacheAge() >= NTP_INTERVAL) {
631 mNtpTime.forceRefresh();
632 }
Mike Lockwood62a8fc12010-03-22 14:23:26 -0400633
Kevin Tang40e1baf2012-01-10 14:32:44 -0800634 // only update when NTP time is fresh
635 if (mNtpTime.getCacheAge() < NTP_INTERVAL) {
636 long time = mNtpTime.getCachedNtpTime();
637 long timeReference = mNtpTime.getCachedNtpTimeReference();
638 long certainty = mNtpTime.getCacheCertainty();
639 long now = System.currentTimeMillis();
Mike Lockwood62a8fc12010-03-22 14:23:26 -0400640
Kevin Tang40e1baf2012-01-10 14:32:44 -0800641 Log.d(TAG, "NTP server returned: "
642 + time + " (" + new Date(time)
643 + ") reference: " + timeReference
644 + " certainty: " + certainty
645 + " system time offset: " + (time - now));
646
647 native_inject_time(time, timeReference, (int) certainty);
648 delay = NTP_INTERVAL;
649 } else {
650 if (DEBUG) Log.d(TAG, "requestTime failed");
651 delay = RETRY_INTERVAL;
652 }
653
Jeff Brown028872f2012-08-25 13:07:01 -0700654 sendMessage(INJECT_NTP_TIME_FINISHED, 0, null);
Kevin Tang40e1baf2012-01-10 14:32:44 -0800655
656 if (mPeriodicTimeInjection) {
657 // send delayed message for next NTP injection
658 // since this is delayed and not urgent we do not hold a wake lock here
Jeff Brown028872f2012-08-25 13:07:01 -0700659 mHandler.sendEmptyMessageDelayed(INJECT_NTP_TIME, delay);
Kevin Tang40e1baf2012-01-10 14:32:44 -0800660 }
Jeff Brown028872f2012-08-25 13:07:01 -0700661
662 // release wake lock held by task
663 mWakeLock.release();
Kevin Tang40e1baf2012-01-10 14:32:44 -0800664 }
665 });
Mike Lockwood62a8fc12010-03-22 14:23:26 -0400666 }
667
668 private void handleDownloadXtraData() {
Kevin Tang40e1baf2012-01-10 14:32:44 -0800669 if (mDownloadXtraDataPending == STATE_DOWNLOADING) {
670 // already downloading data
Mike Lockwood62a8fc12010-03-22 14:23:26 -0400671 return;
672 }
Kevin Tang40e1baf2012-01-10 14:32:44 -0800673 if (!mNetworkAvailable) {
674 // try again when network is up
675 mDownloadXtraDataPending = STATE_PENDING_NETWORK;
676 return;
Mike Lockwood62a8fc12010-03-22 14:23:26 -0400677 }
Kevin Tang40e1baf2012-01-10 14:32:44 -0800678 mDownloadXtraDataPending = STATE_DOWNLOADING;
679
Jeff Brown028872f2012-08-25 13:07:01 -0700680 // hold wake lock while task runs
681 mWakeLock.acquire();
Kevin Tang40e1baf2012-01-10 14:32:44 -0800682 AsyncTask.THREAD_POOL_EXECUTOR.execute(new Runnable() {
683 @Override
684 public void run() {
685 GpsXtraDownloader xtraDownloader = new GpsXtraDownloader(mContext, mProperties);
686 byte[] data = xtraDownloader.downloadXtraData();
687 if (data != null) {
688 if (DEBUG) {
689 Log.d(TAG, "calling native_inject_xtra_data");
690 }
691 native_inject_xtra_data(data, data.length);
692 }
693
Jeff Brown028872f2012-08-25 13:07:01 -0700694 sendMessage(DOWNLOAD_XTRA_DATA_FINISHED, 0, null);
Kevin Tang40e1baf2012-01-10 14:32:44 -0800695
696 if (data == null) {
697 // try again later
698 // since this is delayed and not urgent we do not hold a wake lock here
Jeff Brown028872f2012-08-25 13:07:01 -0700699 mHandler.sendEmptyMessageDelayed(DOWNLOAD_XTRA_DATA, RETRY_INTERVAL);
Kevin Tang40e1baf2012-01-10 14:32:44 -0800700 }
Kevin Tang40e1baf2012-01-10 14:32:44 -0800701
Jeff Brown028872f2012-08-25 13:07:01 -0700702 // release wake lock held by task
703 mWakeLock.release();
704 }
Kevin Tang40e1baf2012-01-10 14:32:44 -0800705 });
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800706 }
707
Mike Lockwood62a8fc12010-03-22 14:23:26 -0400708 private void handleUpdateLocation(Location location) {
Mike Lockwoodd26ce0d2009-06-11 12:25:46 -0400709 if (location.hasAccuracy()) {
710 native_inject_location(location.getLatitude(), location.getLongitude(),
711 location.getAccuracy());
712 }
Mike Lockwoodfd6e5f02009-05-21 11:28:20 -0400713 }
714
715 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800716 * Enables this provider. When enabled, calls to getStatus()
Mike Lockwood4e50b782009-04-03 08:24:43 -0700717 * must be handled. Hardware may be started up
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800718 * when the provider is enabled.
719 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700720 @Override
Mike Lockwood62a8fc12010-03-22 14:23:26 -0400721 public void enable() {
Laurent Tu7b5aeca2013-01-24 15:10:24 -0800722 synchronized (mLock) {
723 if (mEnabled) return;
724 mEnabled = true;
725 }
726
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700727 sendMessage(ENABLE, 1, null);
Mike Lockwood62a8fc12010-03-22 14:23:26 -0400728 }
729
730 private void handleEnable() {
731 if (DEBUG) Log.d(TAG, "handleEnable");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800732
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700733 boolean enabled = native_init();
734
735 if (enabled) {
Mike Lockwood1a1cd3a2010-08-17 07:42:54 -0400736 mSupportsXtra = native_supports_xtra();
Mike Lockwood734d6032009-07-28 18:30:25 -0700737 if (mSuplServerHost != null) {
738 native_set_agps_server(AGPS_TYPE_SUPL, mSuplServerHost, mSuplServerPort);
739 }
740 if (mC2KServerHost != null) {
741 native_set_agps_server(AGPS_TYPE_C2K, mC2KServerHost, mC2KServerPort);
742 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800743 } else {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700744 synchronized (mLock) {
745 mEnabled = false;
746 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800747 Log.w(TAG, "Failed to enable location provider");
748 }
749 }
750
751 /**
752 * Disables this provider. When disabled, calls to getStatus()
Mike Lockwood4e50b782009-04-03 08:24:43 -0700753 * need not be handled. Hardware may be shut
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800754 * down while the provider is disabled.
755 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700756 @Override
Mike Lockwood62a8fc12010-03-22 14:23:26 -0400757 public void disable() {
Laurent Tu7b5aeca2013-01-24 15:10:24 -0800758 synchronized (mLock) {
759 if (!mEnabled) return;
760 mEnabled = false;
761 }
762
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700763 sendMessage(ENABLE, 0, null);
Mike Lockwood62a8fc12010-03-22 14:23:26 -0400764 }
765
766 private void handleDisable() {
Mike Lockwood89096312010-03-24 10:14:55 -0400767 if (DEBUG) Log.d(TAG, "handleDisable");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800768
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800769 stopNavigating();
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700770 mAlarmManager.cancel(mWakeupIntent);
771 mAlarmManager.cancel(mTimeoutIntent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800772
Mike Lockwoodcf1d8cb2010-01-20 10:14:54 -0500773 // do this before releasing wakelock
774 native_cleanup();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800775 }
776
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700777 @Override
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500778 public boolean isEnabled() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700779 synchronized (mLock) {
780 return mEnabled;
781 }
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500782 }
783
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700784 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800785 public int getStatus(Bundle extras) {
786 if (extras != null) {
787 extras.putInt("satellites", mSvCount);
788 }
789 return mStatus;
790 }
791
792 private void updateStatus(int status, int svCount) {
793 if (status != mStatus || svCount != mSvCount) {
794 mStatus = status;
795 mSvCount = svCount;
796 mLocationExtras.putInt("satellites", svCount);
797 mStatusUpdateTime = SystemClock.elapsedRealtime();
798 }
799 }
800
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700801 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800802 public long getStatusUpdateTime() {
803 return mStatusUpdateTime;
804 }
805
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700806 @Override
807 public void setRequest(ProviderRequest request, WorkSource source) {
808 sendMessage(SET_REQUEST, 0, new GpsRequest(request, source));
Mike Lockwood62a8fc12010-03-22 14:23:26 -0400809 }
810
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700811 private void handleSetRequest(ProviderRequest request, WorkSource source) {
Stan Chesnutt1d72d8c2013-04-15 19:18:02 -0700812 boolean singleShot = false;
813
814 // see if the request is for a single update
815 if (request.locationRequests != null && request.locationRequests.size() > 0) {
816 // if any request has zero or more than one updates
817 // requested, then this is not single-shot mode
818 singleShot = true;
819
820 for (LocationRequest lr : request.locationRequests) {
821 if (lr.getNumUpdates() != 1) {
822 singleShot = false;
823 }
824 }
825 }
826
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700827 if (DEBUG) Log.d(TAG, "setRequest " + request);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700828 if (request.reportLocation) {
829 // update client uids
Dianne Hackborn002a54e2013-01-10 17:34:55 -0800830 updateClientUids(source);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800831
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700832 mFixInterval = (int) request.interval;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700833
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700834 // check for overflow
835 if (mFixInterval != request.interval) {
836 Log.w(TAG, "interval overflow: " + request.interval);
837 mFixInterval = Integer.MAX_VALUE;
838 }
Mike Lockwood03ca2162010-04-01 08:10:09 -0700839
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700840 // apply request to GPS engine
Mike Lockwood04598b62010-04-14 17:17:24 -0400841 if (mStarted && hasCapability(GPS_CAPABILITY_SCHEDULING)) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700842 // change period
Mike Lockwood04598b62010-04-14 17:17:24 -0400843 if (!native_set_position_mode(mPositionMode, GPS_POSITION_RECURRENCE_PERIODIC,
844 mFixInterval, 0, 0)) {
845 Log.e(TAG, "set_position_mode failed in setMinTime()");
846 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700847 } else if (!mStarted) {
848 // start GPS
Stan Chesnutt1d72d8c2013-04-15 19:18:02 -0700849 startNavigating(singleShot);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800850 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700851 } else {
Dianne Hackborn002a54e2013-01-10 17:34:55 -0800852 updateClientUids(new WorkSource());
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700853
854 stopNavigating();
855 mAlarmManager.cancel(mWakeupIntent);
856 mAlarmManager.cancel(mTimeoutIntent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800857 }
858 }
859
860 private final class Listener implements IBinder.DeathRecipient {
861 final IGpsStatusListener mListener;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700862
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800863 Listener(IGpsStatusListener listener) {
864 mListener = listener;
865 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700866
867 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800868 public void binderDied() {
Joe Onoratof5d95cb2010-01-07 21:48:32 -0500869 if (DEBUG) Log.d(TAG, "GPS status listener died");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800870
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700871 synchronized (mListeners) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800872 mListeners.remove(this);
873 }
Suchi Amalapurapufff2fda2009-06-30 21:36:16 -0700874 if (mListener != null) {
875 mListener.asBinder().unlinkToDeath(this, 0);
876 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800877 }
878 }
879
Dianne Hackborn002a54e2013-01-10 17:34:55 -0800880 private void updateClientUids(WorkSource source) {
881 // Update work source.
882 WorkSource[] changes = mClientSource.setReturningDiffs(source);
Victoria Leaseea78b852013-01-15 10:39:28 -0800883 if (changes == null) {
884 return;
885 }
Dianne Hackborn002a54e2013-01-10 17:34:55 -0800886 WorkSource newWork = changes[0];
887 WorkSource goneWork = changes[1];
888
889 // Update sources that were not previously tracked.
890 if (newWork != null) {
891 int lastuid = -1;
892 for (int i=0; i<newWork.size(); i++) {
Dianne Hackborn2e418422009-06-22 20:00:17 -0700893 try {
Dianne Hackborn002a54e2013-01-10 17:34:55 -0800894 int uid = newWork.get(i);
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700895 mAppOpsService.startOperation(AppOpsManager.getToken(mAppOpsService),
896 AppOpsManager.OP_GPS, uid, newWork.getName(i));
Dianne Hackborn002a54e2013-01-10 17:34:55 -0800897 if (uid != lastuid) {
898 lastuid = uid;
899 mBatteryStats.noteStartGps(uid);
900 }
Dianne Hackborn2e418422009-06-22 20:00:17 -0700901 } catch (RemoteException e) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700902 Log.w(TAG, "RemoteException", e);
903 }
904 }
905 }
906
Dianne Hackborn002a54e2013-01-10 17:34:55 -0800907 // Update sources that are no longer tracked.
908 if (goneWork != null) {
909 int lastuid = -1;
910 for (int i=0; i<goneWork.size(); i++) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700911 try {
Dianne Hackborn002a54e2013-01-10 17:34:55 -0800912 int uid = goneWork.get(i);
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700913 mAppOpsService.finishOperation(AppOpsManager.getToken(mAppOpsService),
914 AppOpsManager.OP_GPS, uid, goneWork.getName(i));
Dianne Hackborn002a54e2013-01-10 17:34:55 -0800915 if (uid != lastuid) {
916 lastuid = uid;
917 mBatteryStats.noteStopGps(uid);
918 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700919 } catch (RemoteException e) {
920 Log.w(TAG, "RemoteException", e);
Dianne Hackborn2e418422009-06-22 20:00:17 -0700921 }
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400922 }
923 }
924 }
925
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700926 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800927 public boolean sendExtraCommand(String command, Bundle extras) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700928
Mike Lockwood63aa5a62010-04-14 19:21:31 -0400929 long identity = Binder.clearCallingIdentity();
930 boolean result = false;
931
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800932 if ("delete_aiding_data".equals(command)) {
Mike Lockwood63aa5a62010-04-14 19:21:31 -0400933 result = deleteAidingData(extras);
934 } else if ("force_time_injection".equals(command)) {
Mike Lockwood98e48692010-04-07 16:32:51 -0400935 sendMessage(INJECT_NTP_TIME, 0, null);
Mike Lockwood63aa5a62010-04-14 19:21:31 -0400936 result = true;
937 } else if ("force_xtra_injection".equals(command)) {
Mike Lockwood1a1cd3a2010-08-17 07:42:54 -0400938 if (mSupportsXtra) {
Mike Lockwood93bc44d2009-05-20 16:58:22 -0400939 xtraDownloadRequest();
Mike Lockwood63aa5a62010-04-14 19:21:31 -0400940 result = true;
Mike Lockwood93bc44d2009-05-20 16:58:22 -0400941 }
Mike Lockwood63aa5a62010-04-14 19:21:31 -0400942 } else {
943 Log.w(TAG, "sendExtraCommand: unknown command " + command);
Mike Lockwood93bc44d2009-05-20 16:58:22 -0400944 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700945
Mike Lockwood63aa5a62010-04-14 19:21:31 -0400946 Binder.restoreCallingIdentity(identity);
947 return result;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800948 }
949
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -0700950 private IGpsGeofenceHardware mGpsGeofenceBinder = new IGpsGeofenceHardware.Stub() {
951 public boolean isHardwareGeofenceSupported() {
952 return native_is_geofence_supported();
953 }
954
955 public boolean addCircularHardwareGeofence(int geofenceId, double latitude,
956 double longitude, double radius, int lastTransition, int monitorTransitions,
957 int notificationResponsiveness, int unknownTimer) {
958 return native_add_geofence(geofenceId, latitude, longitude, radius,
959 lastTransition, monitorTransitions, notificationResponsiveness, unknownTimer);
960 }
961
962 public boolean removeHardwareGeofence(int geofenceId) {
963 return native_remove_geofence(geofenceId);
964 }
965
966 public boolean pauseHardwareGeofence(int geofenceId) {
967 return native_pause_geofence(geofenceId);
968 }
969
970 public boolean resumeHardwareGeofence(int geofenceId, int monitorTransition) {
971 return native_resume_geofence(geofenceId, monitorTransition);
972 }
973 };
974
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800975 private boolean deleteAidingData(Bundle extras) {
976 int flags;
977
978 if (extras == null) {
979 flags = GPS_DELETE_ALL;
980 } else {
981 flags = 0;
982 if (extras.getBoolean("ephemeris")) flags |= GPS_DELETE_EPHEMERIS;
983 if (extras.getBoolean("almanac")) flags |= GPS_DELETE_ALMANAC;
984 if (extras.getBoolean("position")) flags |= GPS_DELETE_POSITION;
985 if (extras.getBoolean("time")) flags |= GPS_DELETE_TIME;
986 if (extras.getBoolean("iono")) flags |= GPS_DELETE_IONO;
987 if (extras.getBoolean("utc")) flags |= GPS_DELETE_UTC;
988 if (extras.getBoolean("health")) flags |= GPS_DELETE_HEALTH;
989 if (extras.getBoolean("svdir")) flags |= GPS_DELETE_SVDIR;
990 if (extras.getBoolean("svsteer")) flags |= GPS_DELETE_SVSTEER;
991 if (extras.getBoolean("sadata")) flags |= GPS_DELETE_SADATA;
992 if (extras.getBoolean("rti")) flags |= GPS_DELETE_RTI;
993 if (extras.getBoolean("celldb-info")) flags |= GPS_DELETE_CELLDB_INFO;
994 if (extras.getBoolean("all")) flags |= GPS_DELETE_ALL;
995 }
996
997 if (flags != 0) {
998 native_delete_aiding_data(flags);
999 return true;
1000 }
1001
1002 return false;
1003 }
1004
Stan Chesnutt1d72d8c2013-04-15 19:18:02 -07001005 private void startNavigating(boolean singleShot) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001006 if (!mStarted) {
Stan Chesnutt1d72d8c2013-04-15 19:18:02 -07001007 if (DEBUG) Log.d(TAG, "startNavigating, singleShot is " + singleShot);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001008 mTimeToFirstFix = 0;
1009 mLastFixTime = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001010 mStarted = true;
Stan Chesnutt1d72d8c2013-04-15 19:18:02 -07001011 mSingleShot = singleShot;
Mike Lockwood03ca2162010-04-01 08:10:09 -07001012 mPositionMode = GPS_POSITION_MODE_STANDALONE;
1013
Jeff Brownbf6f6f92012-09-25 15:03:20 -07001014 if (Settings.Global.getInt(mContext.getContentResolver(),
1015 Settings.Global.ASSISTED_GPS_ENABLED, 1) != 0) {
Stan Chesnutt1d72d8c2013-04-15 19:18:02 -07001016 if (singleShot && hasCapability(GPS_CAPABILITY_MSA)) {
1017 mPositionMode = GPS_POSITION_MODE_MS_ASSISTED;
1018 } else if (hasCapability(GPS_CAPABILITY_MSB)) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07001019 mPositionMode = GPS_POSITION_MODE_MS_BASED;
1020 }
Mike Lockwoodbcab8df2009-06-25 16:39:09 -04001021 }
1022
Stan Chesnutt1d72d8c2013-04-15 19:18:02 -07001023 if (DEBUG) {
1024 String mode;
1025
1026 switch(mPositionMode) {
1027 case GPS_POSITION_MODE_STANDALONE:
1028 mode = "standalone";
1029 break;
1030 case GPS_POSITION_MODE_MS_ASSISTED:
1031 mode = "MS_ASSISTED";
1032 break;
1033 case GPS_POSITION_MODE_MS_BASED:
1034 mode = "MS_BASED";
1035 break;
1036 default:
1037 mode = "unknown";
1038 break;
1039 }
1040 Log.d(TAG, "setting position_mode to " + mode);
1041 }
1042
Mike Lockwood04598b62010-04-14 17:17:24 -04001043 int interval = (hasCapability(GPS_CAPABILITY_SCHEDULING) ? mFixInterval : 1000);
1044 if (!native_set_position_mode(mPositionMode, GPS_POSITION_RECURRENCE_PERIODIC,
1045 interval, 0, 0)) {
1046 mStarted = false;
1047 Log.e(TAG, "set_position_mode failed in startNavigating()");
1048 return;
1049 }
1050 if (!native_start()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001051 mStarted = false;
1052 Log.e(TAG, "native_start failed in startNavigating()");
Mike Lockwood0632ca72009-05-14 15:51:03 -04001053 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001054 }
1055
1056 // reset SV count to zero
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001057 updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE, 0);
Mike Lockwood29c84342009-05-06 14:01:15 -04001058 mFixRequestTime = System.currentTimeMillis();
Mike Lockwood04598b62010-04-14 17:17:24 -04001059 if (!hasCapability(GPS_CAPABILITY_SCHEDULING)) {
1060 // set timer to give up if we do not receive a fix within NO_FIX_TIMEOUT
1061 // and our fix interval is not short
1062 if (mFixInterval >= NO_FIX_TIMEOUT) {
1063 mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
1064 SystemClock.elapsedRealtime() + NO_FIX_TIMEOUT, mTimeoutIntent);
1065 }
Mike Lockwood0632ca72009-05-14 15:51:03 -04001066 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001067 }
1068 }
1069
Mike Lockwood62a8fc12010-03-22 14:23:26 -04001070 private void stopNavigating() {
Mike Lockwood29c84342009-05-06 14:01:15 -04001071 if (DEBUG) Log.d(TAG, "stopNavigating");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001072 if (mStarted) {
1073 mStarted = false;
Stan Chesnutt1d72d8c2013-04-15 19:18:02 -07001074 mSingleShot = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001075 native_stop();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001076 mTimeToFirstFix = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001077 mLastFixTime = 0;
1078 mLocationFlags = LOCATION_INVALID;
1079
1080 // reset SV count to zero
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001081 updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001082 }
1083 }
1084
Mike Lockwood0632ca72009-05-14 15:51:03 -04001085 private void hibernate() {
1086 // stop GPS until our next fix interval arrives
1087 stopNavigating();
Mike Lockwood0632ca72009-05-14 15:51:03 -04001088 mAlarmManager.cancel(mTimeoutIntent);
1089 mAlarmManager.cancel(mWakeupIntent);
1090 long now = SystemClock.elapsedRealtime();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001091 mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, now + mFixInterval, mWakeupIntent);
Mike Lockwood04598b62010-04-14 17:17:24 -04001092 }
1093
1094 private boolean hasCapability(int capability) {
1095 return ((mEngineCapabilities & capability) != 0);
Mike Lockwood0632ca72009-05-14 15:51:03 -04001096 }
1097
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -07001098
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001099 /**
1100 * called from native code to update our position.
1101 */
1102 private void reportLocation(int flags, double latitude, double longitude, double altitude,
1103 float speed, float bearing, float accuracy, long timestamp) {
Mike Lockwood29c84342009-05-06 14:01:15 -04001104 if (VERBOSE) Log.v(TAG, "reportLocation lat: " + latitude + " long: " + longitude +
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001105 " timestamp: " + timestamp);
1106
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001107 synchronized (mLocation) {
1108 mLocationFlags = flags;
1109 if ((flags & LOCATION_HAS_LAT_LONG) == LOCATION_HAS_LAT_LONG) {
1110 mLocation.setLatitude(latitude);
1111 mLocation.setLongitude(longitude);
1112 mLocation.setTime(timestamp);
Nick Pelly2eeeec22012-07-18 13:13:37 -07001113 // It would be nice to push the elapsed real-time timestamp
1114 // further down the stack, but this is still useful
Philip Milne41180122012-09-26 11:29:25 -07001115 mLocation.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001116 }
1117 if ((flags & LOCATION_HAS_ALTITUDE) == LOCATION_HAS_ALTITUDE) {
1118 mLocation.setAltitude(altitude);
1119 } else {
1120 mLocation.removeAltitude();
1121 }
1122 if ((flags & LOCATION_HAS_SPEED) == LOCATION_HAS_SPEED) {
1123 mLocation.setSpeed(speed);
1124 } else {
1125 mLocation.removeSpeed();
1126 }
1127 if ((flags & LOCATION_HAS_BEARING) == LOCATION_HAS_BEARING) {
1128 mLocation.setBearing(bearing);
1129 } else {
1130 mLocation.removeBearing();
1131 }
1132 if ((flags & LOCATION_HAS_ACCURACY) == LOCATION_HAS_ACCURACY) {
1133 mLocation.setAccuracy(accuracy);
1134 } else {
1135 mLocation.removeAccuracy();
1136 }
Sean Barbeauced2b2c2011-12-19 04:43:07 -05001137 mLocation.setExtras(mLocationExtras);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001138
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001139 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001140 mILocationManager.reportLocation(mLocation, false);
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001141 } catch (RemoteException e) {
1142 Log.e(TAG, "RemoteException calling reportLocation");
1143 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001144 }
1145
Hakan Gustavssonfa94ff02010-02-23 09:12:38 +01001146 mLastFixTime = System.currentTimeMillis();
1147 // report time to first fix
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001148 if (mTimeToFirstFix == 0 && (flags & LOCATION_HAS_LAT_LONG) == LOCATION_HAS_LAT_LONG) {
1149 mTimeToFirstFix = (int)(mLastFixTime - mFixRequestTime);
1150 if (DEBUG) Log.d(TAG, "TTFF: " + mTimeToFirstFix);
Hakan Gustavssonfa94ff02010-02-23 09:12:38 +01001151
1152 // notify status listeners
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001153 synchronized (mListeners) {
Hakan Gustavssonfa94ff02010-02-23 09:12:38 +01001154 int size = mListeners.size();
1155 for (int i = 0; i < size; i++) {
1156 Listener listener = mListeners.get(i);
1157 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001158 listener.mListener.onFirstFix(mTimeToFirstFix);
Hakan Gustavssonfa94ff02010-02-23 09:12:38 +01001159 } catch (RemoteException e) {
1160 Log.w(TAG, "RemoteException in stopNavigating");
1161 mListeners.remove(listener);
1162 // adjust for size of list changing
1163 size--;
1164 }
1165 }
1166 }
1167 }
1168
Stan Chesnutt1d72d8c2013-04-15 19:18:02 -07001169 if (mSingleShot) {
1170 stopNavigating();
1171 }
1172
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001173 if (mStarted && mStatus != LocationProvider.AVAILABLE) {
Mike Lockwoodd53ba012010-04-15 20:41:26 -04001174 // we want to time out if we do not receive a fix
Mike Lockwoodb7be5442010-02-24 14:34:50 -05001175 // within the time out and we are requesting infrequent fixes
Mike Lockwood04598b62010-04-14 17:17:24 -04001176 if (!hasCapability(GPS_CAPABILITY_SCHEDULING) && mFixInterval < NO_FIX_TIMEOUT) {
Mike Lockwoodb7be5442010-02-24 14:34:50 -05001177 mAlarmManager.cancel(mTimeoutIntent);
1178 }
1179
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001180 // send an intent to notify that the GPS is receiving fixes.
Mike Lockwood00b74272010-03-26 10:41:48 -04001181 Intent intent = new Intent(LocationManager.GPS_FIX_CHANGE_ACTION);
1182 intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, true);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001183 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001184 updateStatus(LocationProvider.AVAILABLE, mSvCount);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001185 }
Mike Lockwood29c84342009-05-06 14:01:15 -04001186
Nick Pellyb041f232012-05-07 17:12:25 -07001187 if (!hasCapability(GPS_CAPABILITY_SCHEDULING) && mStarted &&
1188 mFixInterval > GPS_POLLING_THRESHOLD_INTERVAL) {
Mike Lockwoodd53ba012010-04-15 20:41:26 -04001189 if (DEBUG) Log.d(TAG, "got fix, hibernating");
Mike Lockwood0632ca72009-05-14 15:51:03 -04001190 hibernate();
Mike Lockwood29c84342009-05-06 14:01:15 -04001191 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001192 }
1193
1194 /**
1195 * called from native code to update our status
1196 */
1197 private void reportStatus(int status) {
Mike Lockwoodb8d90332010-10-18 17:59:48 -04001198 if (DEBUG) Log.v(TAG, "reportStatus status: " + status);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001199
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001200 synchronized (mListeners) {
Dianne Hackborn2e418422009-06-22 20:00:17 -07001201 boolean wasNavigating = mNavigating;
Mike Lockwooddbd6fd82009-12-07 18:43:36 -05001202
Mike Lockwoodcf1d8cb2010-01-20 10:14:54 -05001203 switch (status) {
1204 case GPS_STATUS_SESSION_BEGIN:
1205 mNavigating = true;
Mike Lockwood271f9f12010-02-02 11:41:52 -05001206 mEngineOn = true;
Mike Lockwoodcf1d8cb2010-01-20 10:14:54 -05001207 break;
1208 case GPS_STATUS_SESSION_END:
1209 mNavigating = false;
1210 break;
1211 case GPS_STATUS_ENGINE_ON:
1212 mEngineOn = true;
1213 break;
1214 case GPS_STATUS_ENGINE_OFF:
1215 mEngineOn = false;
Mike Lockwood271f9f12010-02-02 11:41:52 -05001216 mNavigating = false;
Mike Lockwoodcf1d8cb2010-01-20 10:14:54 -05001217 break;
1218 }
1219
Mike Lockwooddbd6fd82009-12-07 18:43:36 -05001220 if (wasNavigating != mNavigating) {
1221 int size = mListeners.size();
1222 for (int i = 0; i < size; i++) {
1223 Listener listener = mListeners.get(i);
1224 try {
1225 if (mNavigating) {
1226 listener.mListener.onGpsStarted();
1227 } else {
1228 listener.mListener.onGpsStopped();
1229 }
1230 } catch (RemoteException e) {
1231 Log.w(TAG, "RemoteException in reportStatus");
1232 mListeners.remove(listener);
1233 // adjust for size of list changing
1234 size--;
1235 }
1236 }
1237
Mike Lockwooddbd6fd82009-12-07 18:43:36 -05001238 // send an intent to notify that the GPS has been enabled or disabled.
Mike Lockwood00b74272010-03-26 10:41:48 -04001239 Intent intent = new Intent(LocationManager.GPS_ENABLED_CHANGE_ACTION);
1240 intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, mNavigating);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001241 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001242 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001243 }
1244 }
1245
1246 /**
1247 * called from native code to update SV info
1248 */
1249 private void reportSvStatus() {
1250
1251 int svCount = native_read_sv_status(mSvs, mSnrs, mSvElevations, mSvAzimuths, mSvMasks);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001252
1253 synchronized (mListeners) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001254 int size = mListeners.size();
1255 for (int i = 0; i < size; i++) {
1256 Listener listener = mListeners.get(i);
1257 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001258 listener.mListener.onSvStatusChanged(svCount, mSvs, mSnrs,
1259 mSvElevations, mSvAzimuths, mSvMasks[EPHEMERIS_MASK],
1260 mSvMasks[ALMANAC_MASK], mSvMasks[USED_FOR_FIX_MASK]);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001261 } catch (RemoteException e) {
1262 Log.w(TAG, "RemoteException in reportSvInfo");
1263 mListeners.remove(listener);
1264 // adjust for size of list changing
1265 size--;
1266 }
1267 }
1268 }
1269
Mike Lockwood29c84342009-05-06 14:01:15 -04001270 if (VERBOSE) {
1271 Log.v(TAG, "SV count: " + svCount +
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001272 " ephemerisMask: " + Integer.toHexString(mSvMasks[EPHEMERIS_MASK]) +
1273 " almanacMask: " + Integer.toHexString(mSvMasks[ALMANAC_MASK]));
1274 for (int i = 0; i < svCount; i++) {
Mike Lockwood29c84342009-05-06 14:01:15 -04001275 Log.v(TAG, "sv: " + mSvs[i] +
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001276 " snr: " + mSnrs[i]/10 +
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001277 " elev: " + mSvElevations[i] +
1278 " azimuth: " + mSvAzimuths[i] +
1279 ((mSvMasks[EPHEMERIS_MASK] & (1 << (mSvs[i] - 1))) == 0 ? " " : " E") +
1280 ((mSvMasks[ALMANAC_MASK] & (1 << (mSvs[i] - 1))) == 0 ? " " : " A") +
1281 ((mSvMasks[USED_FOR_FIX_MASK] & (1 << (mSvs[i] - 1))) == 0 ? "" : "U"));
1282 }
1283 }
1284
Kevin.KY Tsai0881f4f2010-05-21 15:10:39 -04001285 // return number of sets used in fix instead of total
1286 updateStatus(mStatus, Integer.bitCount(mSvMasks[USED_FOR_FIX_MASK]));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001287
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001288 if (mNavigating && mStatus == LocationProvider.AVAILABLE && mLastFixTime > 0 &&
Mike Lockwood04598b62010-04-14 17:17:24 -04001289 System.currentTimeMillis() - mLastFixTime > RECENT_FIX_TIMEOUT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001290 // send an intent to notify that the GPS is no longer receiving fixes.
Mike Lockwood00b74272010-03-26 10:41:48 -04001291 Intent intent = new Intent(LocationManager.GPS_FIX_CHANGE_ACTION);
1292 intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, false);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001293 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001294 updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE, mSvCount);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001295 }
1296 }
Mike Lockwood58bda982009-04-14 16:25:07 -04001297
1298 /**
Mike Lockwoode3635c92009-05-11 08:38:02 -04001299 * called from native code to update AGPS status
Mike Lockwood58bda982009-04-14 16:25:07 -04001300 */
Stephen Li8efd74d2011-03-01 20:56:00 -08001301 private void reportAGpsStatus(int type, int status, int ipaddr) {
Mike Lockwood58bda982009-04-14 16:25:07 -04001302 switch (status) {
Mike Lockwoode3635c92009-05-11 08:38:02 -04001303 case GPS_REQUEST_AGPS_DATA_CONN:
Mike Lockwoodb6e5fa82010-10-09 20:10:46 -04001304 if (DEBUG) Log.d(TAG, "GPS_REQUEST_AGPS_DATA_CONN");
Mike Lockwood2acfd342010-09-22 12:13:39 -04001305 // Set mAGpsDataConnectionState before calling startUsingNetworkFeature
1306 // to avoid a race condition with handleUpdateNetworkState()
1307 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPENING;
1308 int result = mConnMgr.startUsingNetworkFeature(
Mike Lockwood58bda982009-04-14 16:25:07 -04001309 ConnectivityManager.TYPE_MOBILE, Phone.FEATURE_ENABLE_SUPL);
Stephen Li8efd74d2011-03-01 20:56:00 -08001310 mAGpsDataConnectionIpAddr = ipaddr;
Wink Savillea639b312012-07-10 12:37:54 -07001311 if (result == PhoneConstants.APN_ALREADY_ACTIVE) {
1312 if (DEBUG) Log.d(TAG, "PhoneConstants.APN_ALREADY_ACTIVE");
Mike Lockwoodb362a9a2009-06-22 16:20:39 -04001313 if (mAGpsApn != null) {
Stephen Li8efd74d2011-03-01 20:56:00 -08001314 Log.d(TAG, "mAGpsDataConnectionIpAddr " + mAGpsDataConnectionIpAddr);
1315 if (mAGpsDataConnectionIpAddr != 0xffffffff) {
1316 boolean route_result;
1317 if (DEBUG) Log.d(TAG, "call requestRouteToHost");
1318 route_result = mConnMgr.requestRouteToHost(
1319 ConnectivityManager.TYPE_MOBILE_SUPL,
1320 mAGpsDataConnectionIpAddr);
1321 if (route_result == false) Log.d(TAG, "call requestRouteToHost failed");
1322 }
Mike Lockwoodb362a9a2009-06-22 16:20:39 -04001323 native_agps_data_conn_open(mAGpsApn);
1324 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPEN;
1325 } else {
Wink Savillea639b312012-07-10 12:37:54 -07001326 Log.e(TAG, "mAGpsApn not set when receiving PhoneConstants.APN_ALREADY_ACTIVE");
Mike Lockwood2acfd342010-09-22 12:13:39 -04001327 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_CLOSED;
Mike Lockwoodb362a9a2009-06-22 16:20:39 -04001328 native_agps_data_conn_failed();
1329 }
Wink Savillea639b312012-07-10 12:37:54 -07001330 } else if (result == PhoneConstants.APN_REQUEST_STARTED) {
1331 if (DEBUG) Log.d(TAG, "PhoneConstants.APN_REQUEST_STARTED");
Mike Lockwood2acfd342010-09-22 12:13:39 -04001332 // Nothing to do here
Mike Lockwood58bda982009-04-14 16:25:07 -04001333 } else {
Stan Chesnutt1d72d8c2013-04-15 19:18:02 -07001334 if (DEBUG) Log.d(TAG, "startUsingNetworkFeature failed, value is " +
1335 result);
Mike Lockwood2acfd342010-09-22 12:13:39 -04001336 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_CLOSED;
Mike Lockwoode3635c92009-05-11 08:38:02 -04001337 native_agps_data_conn_failed();
Mike Lockwood58bda982009-04-14 16:25:07 -04001338 }
1339 break;
Mike Lockwoode3635c92009-05-11 08:38:02 -04001340 case GPS_RELEASE_AGPS_DATA_CONN:
Mike Lockwoodb6e5fa82010-10-09 20:10:46 -04001341 if (DEBUG) Log.d(TAG, "GPS_RELEASE_AGPS_DATA_CONN");
Mike Lockwoode3635c92009-05-11 08:38:02 -04001342 if (mAGpsDataConnectionState != AGPS_DATA_CONNECTION_CLOSED) {
Mike Lockwood58bda982009-04-14 16:25:07 -04001343 mConnMgr.stopUsingNetworkFeature(
1344 ConnectivityManager.TYPE_MOBILE, Phone.FEATURE_ENABLE_SUPL);
Mike Lockwoode3635c92009-05-11 08:38:02 -04001345 native_agps_data_conn_closed();
1346 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_CLOSED;
Mike Lockwood58bda982009-04-14 16:25:07 -04001347 }
1348 break;
Mike Lockwoode3635c92009-05-11 08:38:02 -04001349 case GPS_AGPS_DATA_CONNECTED:
Mike Lockwoodb6e5fa82010-10-09 20:10:46 -04001350 if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONNECTED");
Mike Lockwood58bda982009-04-14 16:25:07 -04001351 break;
Mike Lockwoode3635c92009-05-11 08:38:02 -04001352 case GPS_AGPS_DATA_CONN_DONE:
Mike Lockwoodb6e5fa82010-10-09 20:10:46 -04001353 if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONN_DONE");
Mike Lockwood58bda982009-04-14 16:25:07 -04001354 break;
Mike Lockwoode3635c92009-05-11 08:38:02 -04001355 case GPS_AGPS_DATA_CONN_FAILED:
Mike Lockwoodb6e5fa82010-10-09 20:10:46 -04001356 if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONN_FAILED");
Mike Lockwood58bda982009-04-14 16:25:07 -04001357 break;
1358 }
1359 }
1360
Mike Lockwoodb16e7802009-08-06 09:26:02 -04001361 /**
1362 * called from native code to report NMEA data received
1363 */
Mike Lockwoodf602d362010-06-20 14:28:16 -07001364 private void reportNmea(long timestamp) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001365 synchronized (mListeners) {
Mike Lockwoodb16e7802009-08-06 09:26:02 -04001366 int size = mListeners.size();
1367 if (size > 0) {
1368 // don't bother creating the String if we have no listeners
Mike Lockwoodf602d362010-06-20 14:28:16 -07001369 int length = native_read_nmea(mNmeaBuffer, mNmeaBuffer.length);
Mike Lockwoodb16e7802009-08-06 09:26:02 -04001370 String nmea = new String(mNmeaBuffer, 0, length);
1371
1372 for (int i = 0; i < size; i++) {
1373 Listener listener = mListeners.get(i);
1374 try {
1375 listener.mListener.onNmeaReceived(timestamp, nmea);
1376 } catch (RemoteException e) {
1377 Log.w(TAG, "RemoteException in reportNmea");
1378 mListeners.remove(listener);
1379 // adjust for size of list changing
1380 size--;
1381 }
1382 }
1383 }
1384 }
1385 }
1386
Mike Lockwood62a8fc12010-03-22 14:23:26 -04001387 /**
Mike Lockwood04598b62010-04-14 17:17:24 -04001388 * called from native code to inform us what the GPS engine capabilities are
1389 */
1390 private void setEngineCapabilities(int capabilities) {
1391 mEngineCapabilities = capabilities;
Mike Lockwood9b9fb5c2011-06-29 15:09:40 -04001392
1393 if (!hasCapability(GPS_CAPABILITY_ON_DEMAND_TIME) && !mPeriodicTimeInjection) {
1394 mPeriodicTimeInjection = true;
1395 requestUtcTime();
1396 }
Mike Lockwood04598b62010-04-14 17:17:24 -04001397 }
1398
1399 /**
Mike Lockwood62a8fc12010-03-22 14:23:26 -04001400 * called from native code to request XTRA data
1401 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001402 private void xtraDownloadRequest() {
Joe Onoratof5d95cb2010-01-07 21:48:32 -05001403 if (DEBUG) Log.d(TAG, "xtraDownloadRequest");
Mike Lockwood98e48692010-04-07 16:32:51 -04001404 sendMessage(DOWNLOAD_XTRA_DATA, 0, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001405 }
1406
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -07001407 /**
1408 * Called from native to report GPS Geofence transition
1409 * All geofence callbacks are called on the same thread
1410 */
1411 private void reportGeofenceTransition(int geofenceId, int flags, double latitude,
1412 double longitude, double altitude, float speed, float bearing, float accuracy,
1413 long timestamp, int transition, long transitionTimestamp) {
1414 if (mGeofenceHardwareImpl == null) {
1415 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
1416 }
1417 mGeofenceHardwareImpl.reportGpsGeofenceTransition(geofenceId, flags, latitude, longitude,
1418 altitude, speed, bearing, accuracy, timestamp, transition, transitionTimestamp);
1419 }
1420
1421 /**
1422 * called from native code to report GPS status change.
1423 */
1424 private void reportGeofenceStatus(int status, int flags, double latitude,
1425 double longitude, double altitude, float speed, float bearing, float accuracy,
1426 long timestamp) {
1427 if (mGeofenceHardwareImpl == null) {
1428 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
1429 }
1430 mGeofenceHardwareImpl.reportGpsGeofenceStatus(status, flags, latitude, longitude, altitude,
1431 speed, bearing, accuracy, timestamp);
1432 }
1433
1434 /**
1435 * called from native code - Geofence Add callback
1436 */
1437 private void reportGeofenceAddStatus(int geofenceId, int status) {
1438 if (mGeofenceHardwareImpl == null) {
1439 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
1440 }
1441 mGeofenceHardwareImpl.reportGpsGeofenceAddStatus(geofenceId, status);
1442 }
1443
1444 /**
1445 * called from native code - Geofence Remove callback
1446 */
1447 private void reportGeofenceRemoveStatus(int geofenceId, int status) {
1448 if (mGeofenceHardwareImpl == null) {
1449 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
1450 }
1451 mGeofenceHardwareImpl.reportGpsGeofenceRemoveStatus(geofenceId, status);
1452 }
1453
1454 /**
1455 * called from native code - Geofence Pause callback
1456 */
1457 private void reportGeofencePauseStatus(int geofenceId, int status) {
1458 if (mGeofenceHardwareImpl == null) {
1459 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
1460 }
1461 mGeofenceHardwareImpl.reportGpsGeofencePauseStatus(geofenceId, status);
1462 }
1463
1464 /**
1465 * called from native code - Geofence Resume callback
1466 */
1467 private void reportGeofenceResumeStatus(int geofenceId, int status) {
1468 if (mGeofenceHardwareImpl == null) {
1469 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
1470 }
1471 mGeofenceHardwareImpl.reportGpsGeofenceResumeStatus(geofenceId, status);
1472 }
1473
Danke Xie22d1f9f2009-08-18 18:28:45 -04001474 //=============================================================
1475 // NI Client support
Miguel Torroja1e84da82010-07-27 07:02:24 +02001476 //=============================================================
Danke Xie22d1f9f2009-08-18 18:28:45 -04001477 private final INetInitiatedListener mNetInitiatedListener = new INetInitiatedListener.Stub() {
Miguel Torroja1e84da82010-07-27 07:02:24 +02001478 // Sends a response for an NI reqeust to HAL.
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001479 @Override
Miguel Torroja1e84da82010-07-27 07:02:24 +02001480 public boolean sendNiResponse(int notificationId, int userResponse)
1481 {
1482 // TODO Add Permission check
Danke Xie22d1f9f2009-08-18 18:28:45 -04001483
Miguel Torroja1e84da82010-07-27 07:02:24 +02001484 if (DEBUG) Log.d(TAG, "sendNiResponse, notifId: " + notificationId +
1485 ", response: " + userResponse);
1486 native_send_ni_response(notificationId, userResponse);
1487 return true;
1488 }
Danke Xie22d1f9f2009-08-18 18:28:45 -04001489 };
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001490
Danke Xie22d1f9f2009-08-18 18:28:45 -04001491 public INetInitiatedListener getNetInitiatedListener() {
1492 return mNetInitiatedListener;
1493 }
1494
1495 // Called by JNI function to report an NI request.
Miguel Torroja1e84da82010-07-27 07:02:24 +02001496 public void reportNiNotification(
1497 int notificationId,
1498 int niType,
1499 int notifyFlags,
1500 int timeout,
1501 int defaultResponse,
1502 String requestorId,
1503 String text,
1504 int requestorIdEncoding,
1505 int textEncoding,
1506 String extras // Encoded extra data
Danke Xie22d1f9f2009-08-18 18:28:45 -04001507 )
Miguel Torroja1e84da82010-07-27 07:02:24 +02001508 {
1509 Log.i(TAG, "reportNiNotification: entered");
1510 Log.i(TAG, "notificationId: " + notificationId +
1511 ", niType: " + niType +
1512 ", notifyFlags: " + notifyFlags +
1513 ", timeout: " + timeout +
1514 ", defaultResponse: " + defaultResponse);
1515
1516 Log.i(TAG, "requestorId: " + requestorId +
1517 ", text: " + text +
1518 ", requestorIdEncoding: " + requestorIdEncoding +
1519 ", textEncoding: " + textEncoding);
1520
1521 GpsNiNotification notification = new GpsNiNotification();
1522
1523 notification.notificationId = notificationId;
1524 notification.niType = niType;
1525 notification.needNotify = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_NEED_NOTIFY) != 0;
1526 notification.needVerify = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_NEED_VERIFY) != 0;
1527 notification.privacyOverride = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_PRIVACY_OVERRIDE) != 0;
1528 notification.timeout = timeout;
1529 notification.defaultResponse = defaultResponse;
1530 notification.requestorId = requestorId;
1531 notification.text = text;
1532 notification.requestorIdEncoding = requestorIdEncoding;
1533 notification.textEncoding = textEncoding;
1534
1535 // Process extras, assuming the format is
1536 // one of more lines of "key = value"
1537 Bundle bundle = new Bundle();
1538
1539 if (extras == null) extras = "";
1540 Properties extraProp = new Properties();
1541
1542 try {
Jeff Sharkey104344e2011-07-10 14:20:41 -07001543 extraProp.load(new StringReader(extras));
Miguel Torroja1e84da82010-07-27 07:02:24 +02001544 }
1545 catch (IOException e)
1546 {
1547 Log.e(TAG, "reportNiNotification cannot parse extras data: " + extras);
1548 }
1549
1550 for (Entry<Object, Object> ent : extraProp.entrySet())
1551 {
1552 bundle.putString((String) ent.getKey(), (String) ent.getValue());
1553 }
1554
1555 notification.extras = bundle;
1556
1557 mNIHandler.handleNiNotification(notification);
1558 }
1559
1560 /**
1561 * Called from native code to request set id info.
1562 * We should be careful about receiving null string from the TelephonyManager,
1563 * because sending null String to JNI function would cause a crash.
1564 */
1565
1566 private void requestSetID(int flags) {
1567 TelephonyManager phone = (TelephonyManager)
1568 mContext.getSystemService(Context.TELEPHONY_SERVICE);
1569 int type = AGPS_SETID_TYPE_NONE;
1570 String data = "";
1571
1572 if ((flags & AGPS_RIL_REQUEST_SETID_IMSI) == AGPS_RIL_REQUEST_SETID_IMSI) {
1573 String data_temp = phone.getSubscriberId();
1574 if (data_temp == null) {
1575 // This means the framework does not have the SIM card ready.
1576 } else {
1577 // This means the framework has the SIM card.
1578 data = data_temp;
1579 type = AGPS_SETID_TYPE_IMSI;
1580 }
1581 }
1582 else if ((flags & AGPS_RIL_REQUEST_SETID_MSISDN) == AGPS_RIL_REQUEST_SETID_MSISDN) {
1583 String data_temp = phone.getLine1Number();
1584 if (data_temp == null) {
1585 // This means the framework does not have the SIM card ready.
1586 } else {
1587 // This means the framework has the SIM card.
1588 data = data_temp;
1589 type = AGPS_SETID_TYPE_MSISDN;
1590 }
1591 }
1592 native_agps_set_id(type, data);
1593 }
1594
1595 /**
Mike Lockwood9b9fb5c2011-06-29 15:09:40 -04001596 * Called from native code to request utc time info
1597 */
1598
1599 private void requestUtcTime() {
1600 sendMessage(INJECT_NTP_TIME, 0, null);
1601 }
1602
1603 /**
Miguel Torroja1e84da82010-07-27 07:02:24 +02001604 * Called from native code to request reference location info
1605 */
1606
1607 private void requestRefLocation(int flags) {
1608 TelephonyManager phone = (TelephonyManager)
1609 mContext.getSystemService(Context.TELEPHONY_SERVICE);
Victoria Leased50d0c32012-10-29 13:16:17 -07001610 final int phoneType = phone.getPhoneType();
1611 if (phoneType == TelephonyManager.PHONE_TYPE_GSM) {
Miguel Torroja1e84da82010-07-27 07:02:24 +02001612 GsmCellLocation gsm_cell = (GsmCellLocation) phone.getCellLocation();
Victoria Leased50d0c32012-10-29 13:16:17 -07001613 if ((gsm_cell != null) && (phone.getNetworkOperator() != null)
1614 && (phone.getNetworkOperator().length() > 3)) {
Miguel Torroja1e84da82010-07-27 07:02:24 +02001615 int type;
1616 int mcc = Integer.parseInt(phone.getNetworkOperator().substring(0,3));
1617 int mnc = Integer.parseInt(phone.getNetworkOperator().substring(3));
Mike Lockwoodedc0f3872010-10-22 09:16:17 -04001618 int networkType = phone.getNetworkType();
1619 if (networkType == TelephonyManager.NETWORK_TYPE_UMTS
1620 || networkType == TelephonyManager.NETWORK_TYPE_HSDPA
1621 || networkType == TelephonyManager.NETWORK_TYPE_HSUPA
Arun Ravindran58d46122012-07-30 17:50:21 +03001622 || networkType == TelephonyManager.NETWORK_TYPE_HSPA
1623 || networkType == TelephonyManager.NETWORK_TYPE_HSPAP) {
Miguel Torroja1e84da82010-07-27 07:02:24 +02001624 type = AGPS_REF_LOCATION_TYPE_UMTS_CELLID;
Mike Lockwoodedc0f3872010-10-22 09:16:17 -04001625 } else {
Miguel Torroja1e84da82010-07-27 07:02:24 +02001626 type = AGPS_REF_LOCATION_TYPE_GSM_CELLID;
Mike Lockwoodedc0f3872010-10-22 09:16:17 -04001627 }
Miguel Torroja1e84da82010-07-27 07:02:24 +02001628 native_agps_set_ref_location_cellid(type, mcc, mnc,
1629 gsm_cell.getLac(), gsm_cell.getCid());
Mike Lockwoodedc0f3872010-10-22 09:16:17 -04001630 } else {
Miguel Torroja1e84da82010-07-27 07:02:24 +02001631 Log.e(TAG,"Error getting cell location info.");
Mike Lockwoodedc0f3872010-10-22 09:16:17 -04001632 }
Victoria Leased50d0c32012-10-29 13:16:17 -07001633 } else if (phoneType == TelephonyManager.PHONE_TYPE_CDMA) {
1634 Log.e(TAG, "CDMA not supported.");
Mike Lockwoodedc0f3872010-10-22 09:16:17 -04001635 }
Miguel Torroja1e84da82010-07-27 07:02:24 +02001636 }
Danke Xie22d1f9f2009-08-18 18:28:45 -04001637
Mike Lockwood98e48692010-04-07 16:32:51 -04001638 private void sendMessage(int message, int arg, Object obj) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001639 // hold a wake lock until this message is delivered
Jeff Brown028872f2012-08-25 13:07:01 -07001640 // note that this assumes the message will not be removed from the queue before
1641 // it is handled (otherwise the wake lock would be leaked).
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001642 mWakeLock.acquire();
1643 mHandler.obtainMessage(message, arg, 1, obj).sendToTarget();
Mike Lockwood98e48692010-04-07 16:32:51 -04001644 }
1645
Mike Lockwood62a8fc12010-03-22 14:23:26 -04001646 private final class ProviderHandler extends Handler {
Victoria Lease5cd731a2012-12-19 15:04:21 -08001647 public ProviderHandler(Looper looper) {
1648 super(looper, null, true /*async*/);
Jeff Brown028872f2012-08-25 13:07:01 -07001649 }
1650
Mike Lockwood62a8fc12010-03-22 14:23:26 -04001651 @Override
Mike Lockwood4a7b65e2010-10-25 16:35:55 -04001652 public void handleMessage(Message msg) {
Mike Lockwood98e48692010-04-07 16:32:51 -04001653 int message = msg.what;
1654 switch (message) {
Mike Lockwood62a8fc12010-03-22 14:23:26 -04001655 case ENABLE:
1656 if (msg.arg1 == 1) {
1657 handleEnable();
1658 } else {
1659 handleDisable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001660 }
Mike Lockwood62a8fc12010-03-22 14:23:26 -04001661 break;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001662 case SET_REQUEST:
1663 GpsRequest gpsRequest = (GpsRequest) msg.obj;
1664 handleSetRequest(gpsRequest.request, gpsRequest.source);
Mike Lockwood03ca2162010-04-01 08:10:09 -07001665 break;
Mike Lockwood62a8fc12010-03-22 14:23:26 -04001666 case UPDATE_NETWORK_STATE:
1667 handleUpdateNetworkState(msg.arg1, (NetworkInfo)msg.obj);
1668 break;
1669 case INJECT_NTP_TIME:
1670 handleInjectNtpTime();
1671 break;
1672 case DOWNLOAD_XTRA_DATA:
Mike Lockwood1a1cd3a2010-08-17 07:42:54 -04001673 if (mSupportsXtra) {
Mike Lockwood62a8fc12010-03-22 14:23:26 -04001674 handleDownloadXtraData();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001675 }
Mike Lockwood62a8fc12010-03-22 14:23:26 -04001676 break;
Kevin Tang40e1baf2012-01-10 14:32:44 -08001677 case INJECT_NTP_TIME_FINISHED:
1678 mInjectNtpTimePending = STATE_IDLE;
1679 break;
1680 case DOWNLOAD_XTRA_DATA_FINISHED:
1681 mDownloadXtraDataPending = STATE_IDLE;
1682 break;
Mike Lockwood62a8fc12010-03-22 14:23:26 -04001683 case UPDATE_LOCATION:
1684 handleUpdateLocation((Location)msg.obj);
1685 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001686 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001687 if (msg.arg2 == 1) {
1688 // wakelock was taken for this message, release it
1689 mWakeLock.release();
Mike Lockwood98e48692010-04-07 16:32:51 -04001690 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001691 }
Mike Lockwood62a8fc12010-03-22 14:23:26 -04001692 };
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001693
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001694 private final class NetworkLocationListener implements LocationListener {
1695 @Override
1696 public void onLocationChanged(Location location) {
1697 // this callback happens on mHandler looper
1698 if (LocationManager.NETWORK_PROVIDER.equals(location.getProvider())) {
1699 handleUpdateLocation(location);
1700 }
1701 }
1702 @Override
1703 public void onStatusChanged(String provider, int status, Bundle extras) { }
1704 @Override
1705 public void onProviderEnabled(String provider) { }
1706 @Override
1707 public void onProviderDisabled(String provider) { }
1708 }
1709
Kevin Tanga5fe6b22011-06-05 14:25:16 -07001710 private String getSelectedApn() {
1711 Uri uri = Uri.parse("content://telephony/carriers/preferapn");
1712 String apn = null;
1713
1714 Cursor cursor = mContext.getContentResolver().query(uri, new String[] {"apn"},
1715 null, null, Carriers.DEFAULT_SORT_ORDER);
1716
1717 if (null != cursor) {
1718 try {
1719 if (cursor.moveToFirst()) {
1720 apn = cursor.getString(0);
1721 }
1722 } finally {
1723 cursor.close();
1724 }
1725 }
1726 return apn;
1727 }
1728
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001729 @Override
1730 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1731 StringBuilder s = new StringBuilder();
1732 s.append(" mFixInterval=").append(mFixInterval).append("\n");
1733 s.append(" mEngineCapabilities=0x").append(Integer.toHexString(mEngineCapabilities)).append(" (");
1734 if (hasCapability(GPS_CAPABILITY_SCHEDULING)) s.append("SCHED ");
1735 if (hasCapability(GPS_CAPABILITY_MSB)) s.append("MSB ");
1736 if (hasCapability(GPS_CAPABILITY_MSA)) s.append("MSA ");
1737 if (hasCapability(GPS_CAPABILITY_SINGLE_SHOT)) s.append("SINGLE_SHOT ");
1738 if (hasCapability(GPS_CAPABILITY_ON_DEMAND_TIME)) s.append("ON_DEMAND_TIME ");
1739 s.append(")\n");
1740
1741 s.append(native_get_internal_state());
1742 pw.append(s);
1743 }
1744
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001745 // for GPS SV statistics
1746 private static final int MAX_SVS = 32;
1747 private static final int EPHEMERIS_MASK = 0;
1748 private static final int ALMANAC_MASK = 1;
1749 private static final int USED_FOR_FIX_MASK = 2;
1750
1751 // preallocated arrays, to avoid memory allocation in reportStatus()
1752 private int mSvs[] = new int[MAX_SVS];
1753 private float mSnrs[] = new float[MAX_SVS];
1754 private float mSvElevations[] = new float[MAX_SVS];
1755 private float mSvAzimuths[] = new float[MAX_SVS];
1756 private int mSvMasks[] = new int[3];
1757 private int mSvCount;
Mike Lockwoodb16e7802009-08-06 09:26:02 -04001758 // preallocated to avoid memory allocation in reportNmea()
1759 private byte[] mNmeaBuffer = new byte[120];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001760
1761 static { class_init_native(); }
1762 private static native void class_init_native();
1763 private static native boolean native_is_supported();
1764
1765 private native boolean native_init();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001766 private native void native_cleanup();
Mike Lockwood04598b62010-04-14 17:17:24 -04001767 private native boolean native_set_position_mode(int mode, int recurrence, int min_interval,
1768 int preferred_accuracy, int preferred_time);
1769 private native boolean native_start();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001770 private native boolean native_stop();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001771 private native void native_delete_aiding_data(int flags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001772 // returns number of SVs
1773 // mask[0] is ephemeris mask and mask[1] is almanac mask
1774 private native int native_read_sv_status(int[] svs, float[] snrs,
1775 float[] elevations, float[] azimuths, int[] masks);
Mike Lockwoodf602d362010-06-20 14:28:16 -07001776 private native int native_read_nmea(byte[] buffer, int bufferSize);
Mike Lockwoodd26ce0d2009-06-11 12:25:46 -04001777 private native void native_inject_location(double latitude, double longitude, float accuracy);
1778
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06001779 // XTRA Support
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001780 private native void native_inject_time(long time, long timeReference, int uncertainty);
1781 private native boolean native_supports_xtra();
1782 private native void native_inject_xtra_data(byte[] data, int length);
The Android Open Source Project10592532009-03-18 17:39:46 -07001783
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06001784 // DEBUG Support
1785 private native String native_get_internal_state();
1786
1787 // AGPS Support
Mike Lockwoode3635c92009-05-11 08:38:02 -04001788 private native void native_agps_data_conn_open(String apn);
1789 private native void native_agps_data_conn_closed();
1790 private native void native_agps_data_conn_failed();
Miguel Torroja1e84da82010-07-27 07:02:24 +02001791 private native void native_agps_ni_message(byte [] msg, int length);
Mike Lockwooda9e54612009-06-19 14:54:42 -04001792 private native void native_set_agps_server(int type, String hostname, int port);
Danke Xie22d1f9f2009-08-18 18:28:45 -04001793
1794 // Network-initiated (NI) Support
1795 private native void native_send_ni_response(int notificationId, int userResponse);
Miguel Torroja1e84da82010-07-27 07:02:24 +02001796
1797 // AGPS ril suport
1798 private native void native_agps_set_ref_location_cellid(int type, int mcc, int mnc,
1799 int lac, int cid);
1800 private native void native_agps_set_id(int type, String setid);
Mike Lockwood50130bb2010-10-11 06:22:50 -04001801
1802 private native void native_update_network_state(boolean connected, int type,
Kevin Tanga5fe6b22011-06-05 14:25:16 -07001803 boolean roaming, boolean available, String extraInfo, String defaultAPN);
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -07001804
1805 // Hardware Geofence support.
1806 private static native boolean native_is_geofence_supported();
1807 private static native boolean native_add_geofence(int geofenceId, double latitude,
1808 double longitude, double radius, int lastTransition,int monitorTransitions,
1809 int notificationResponsivenes, int unknownTimer);
1810 private static native boolean native_remove_geofence(int geofenceId);
1811 private static native boolean native_resume_geofence(int geofenceId, int transitions);
1812 private static native boolean native_pause_geofence(int geofenceId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001813}