blob: 8c88cabacd8985154d92d805376f641b080d3b42 [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;
Mike Lockwood63aa5a62010-04-14 19:21:31 -040044import android.os.Binder;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080045import android.os.Bundle;
Mike Lockwood62a8fc12010-03-22 14:23:26 -040046import android.os.Handler;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080047import android.os.IBinder;
Victoria Lease5cd731a2012-12-19 15:04:21 -080048import android.os.Looper;
Mike Lockwood62a8fc12010-03-22 14:23:26 -040049import android.os.Message;
Mike Lockwood0528b9b2009-05-07 10:12:54 -040050import android.os.PowerManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080051import android.os.RemoteException;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -040052import android.os.ServiceManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080053import android.os.SystemClock;
Dianne Hackborn5ac72a22012-08-29 18:32:08 -070054import android.os.UserHandle;
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -070055import android.os.WorkSource;
Mike Lockwoodbcab8df2009-06-25 16:39:09 -040056import android.provider.Settings;
Kevin Tanga5fe6b22011-06-05 14:25:16 -070057import android.provider.Telephony.Carriers;
Miguel Torroja1e84da82010-07-27 07:02:24 +020058import android.provider.Telephony.Sms.Intents;
Jake Hambyb49a73d2011-03-15 20:09:46 -070059import android.telephony.SmsMessage;
Miguel Torroja1e84da82010-07-27 07:02:24 +020060import android.telephony.TelephonyManager;
61import android.telephony.gsm.GsmCellLocation;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080062import android.util.Log;
Jeff Sharkey104344e2011-07-10 14:20:41 -070063import android.util.NtpTrustedTime;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080064
65import com.android.internal.app.IAppOpsService;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -040066import com.android.internal.app.IBatteryStats;
Danke Xie22d1f9f2009-08-18 18:28:45 -040067import com.android.internal.location.GpsNetInitiatedHandler;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070068import com.android.internal.location.ProviderProperties;
69import com.android.internal.location.ProviderRequest;
Danke Xie22d1f9f2009-08-18 18:28:45 -040070import com.android.internal.location.GpsNetInitiatedHandler.GpsNiNotification;
Jake Hambyb49a73d2011-03-15 20:09:46 -070071import com.android.internal.telephony.Phone;
Wink Savillea639b312012-07-10 12:37:54 -070072import com.android.internal.telephony.PhoneConstants;
The Android Open Source Project10592532009-03-18 17:39:46 -070073
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080074import java.io.File;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070075import java.io.FileDescriptor;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080076import java.io.FileInputStream;
77import java.io.IOException;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070078import java.io.PrintWriter;
Jeff Sharkey104344e2011-07-10 14:20:41 -070079import java.io.StringReader;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080080import java.util.ArrayList;
Mike Lockwoodf1218be2010-01-29 09:20:06 -050081import java.util.Date;
Danke Xie22d1f9f2009-08-18 18:28:45 -040082import java.util.Map.Entry;
Jake Hambyb49a73d2011-03-15 20:09:46 -070083import java.util.Properties;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080084
85/**
86 * A GPS implementation of LocationProvider used by LocationManager.
87 *
88 * {@hide}
89 */
Mike Lockwood89096312010-03-24 10:14:55 -040090public class GpsLocationProvider implements LocationProviderInterface {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080091
92 private static final String TAG = "GpsLocationProvider";
Mike Lockwood29c84342009-05-06 14:01:15 -040093
Brian Muramatsu1715cb32012-08-08 17:32:21 -070094 private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
95 private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
Mike Lockwood62a8fc12010-03-22 14:23:26 -040096
Nick Pelly6fa9ad42012-07-16 12:18:23 -070097 private static final ProviderProperties PROPERTIES = new ProviderProperties(
98 true, true, false, false, true, true, true,
99 Criteria.POWER_HIGH, Criteria.ACCURACY_FINE);
100
The Android Open Source Project10592532009-03-18 17:39:46 -0700101 // these need to match GpsPositionMode enum in gps.h
102 private static final int GPS_POSITION_MODE_STANDALONE = 0;
103 private static final int GPS_POSITION_MODE_MS_BASED = 1;
104 private static final int GPS_POSITION_MODE_MS_ASSISTED = 2;
105
Mike Lockwood04598b62010-04-14 17:17:24 -0400106 // these need to match GpsPositionRecurrence enum in gps.h
107 private static final int GPS_POSITION_RECURRENCE_PERIODIC = 0;
108 private static final int GPS_POSITION_RECURRENCE_SINGLE = 1;
109
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800110 // these need to match GpsStatusValue defines in gps.h
111 private static final int GPS_STATUS_NONE = 0;
112 private static final int GPS_STATUS_SESSION_BEGIN = 1;
113 private static final int GPS_STATUS_SESSION_END = 2;
114 private static final int GPS_STATUS_ENGINE_ON = 3;
115 private static final int GPS_STATUS_ENGINE_OFF = 4;
116
Mike Lockwoode3635c92009-05-11 08:38:02 -0400117 // these need to match GpsApgsStatusValue defines in gps.h
118 /** AGPS status event values. */
119 private static final int GPS_REQUEST_AGPS_DATA_CONN = 1;
120 private static final int GPS_RELEASE_AGPS_DATA_CONN = 2;
121 private static final int GPS_AGPS_DATA_CONNECTED = 3;
122 private static final int GPS_AGPS_DATA_CONN_DONE = 4;
123 private static final int GPS_AGPS_DATA_CONN_FAILED = 5;
Mike Lockwood58bda982009-04-14 16:25:07 -0400124
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800125 // these need to match GpsLocationFlags enum in gps.h
126 private static final int LOCATION_INVALID = 0;
127 private static final int LOCATION_HAS_LAT_LONG = 1;
128 private static final int LOCATION_HAS_ALTITUDE = 2;
129 private static final int LOCATION_HAS_SPEED = 4;
130 private static final int LOCATION_HAS_BEARING = 8;
131 private static final int LOCATION_HAS_ACCURACY = 16;
Mike Lockwoode3635c92009-05-11 08:38:02 -0400132
133// IMPORTANT - the GPS_DELETE_* symbols here must match constants in gps.h
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800134 private static final int GPS_DELETE_EPHEMERIS = 0x0001;
135 private static final int GPS_DELETE_ALMANAC = 0x0002;
136 private static final int GPS_DELETE_POSITION = 0x0004;
137 private static final int GPS_DELETE_TIME = 0x0008;
138 private static final int GPS_DELETE_IONO = 0x0010;
139 private static final int GPS_DELETE_UTC = 0x0020;
140 private static final int GPS_DELETE_HEALTH = 0x0040;
141 private static final int GPS_DELETE_SVDIR = 0x0080;
142 private static final int GPS_DELETE_SVSTEER = 0x0100;
143 private static final int GPS_DELETE_SADATA = 0x0200;
144 private static final int GPS_DELETE_RTI = 0x0400;
145 private static final int GPS_DELETE_CELLDB_INFO = 0x8000;
146 private static final int GPS_DELETE_ALL = 0xFFFF;
147
Mike Lockwood04598b62010-04-14 17:17:24 -0400148 // The GPS_CAPABILITY_* flags must match the values in gps.h
149 private static final int GPS_CAPABILITY_SCHEDULING = 0x0000001;
150 private static final int GPS_CAPABILITY_MSB = 0x0000002;
151 private static final int GPS_CAPABILITY_MSA = 0x0000004;
152 private static final int GPS_CAPABILITY_SINGLE_SHOT = 0x0000008;
Mike Lockwood9b9fb5c2011-06-29 15:09:40 -0400153 private static final int GPS_CAPABILITY_ON_DEMAND_TIME = 0x0000010;
Mike Lockwood04598b62010-04-14 17:17:24 -0400154
Mike Lockwoode3635c92009-05-11 08:38:02 -0400155 // these need to match AGpsType enum in gps.h
156 private static final int AGPS_TYPE_SUPL = 1;
157 private static final int AGPS_TYPE_C2K = 2;
158
159 // for mAGpsDataConnectionState
160 private static final int AGPS_DATA_CONNECTION_CLOSED = 0;
161 private static final int AGPS_DATA_CONNECTION_OPENING = 1;
162 private static final int AGPS_DATA_CONNECTION_OPEN = 2;
Mike Lockwood58bda982009-04-14 16:25:07 -0400163
Mike Lockwood62a8fc12010-03-22 14:23:26 -0400164 // Handler messages
165 private static final int CHECK_LOCATION = 1;
166 private static final int ENABLE = 2;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700167 private static final int SET_REQUEST = 3;
Mike Lockwood62a8fc12010-03-22 14:23:26 -0400168 private static final int UPDATE_NETWORK_STATE = 4;
169 private static final int INJECT_NTP_TIME = 5;
170 private static final int DOWNLOAD_XTRA_DATA = 6;
171 private static final int UPDATE_LOCATION = 7;
172 private static final int ADD_LISTENER = 8;
173 private static final int REMOVE_LISTENER = 9;
Kevin Tang40e1baf2012-01-10 14:32:44 -0800174 private static final int INJECT_NTP_TIME_FINISHED = 10;
175 private static final int DOWNLOAD_XTRA_DATA_FINISHED = 11;
Mike Lockwood62a8fc12010-03-22 14:23:26 -0400176
Miguel Torroja1e84da82010-07-27 07:02:24 +0200177 // Request setid
178 private static final int AGPS_RIL_REQUEST_SETID_IMSI = 1;
179 private static final int AGPS_RIL_REQUEST_SETID_MSISDN = 2;
180
181 // Request ref location
182 private static final int AGPS_RIL_REQUEST_REFLOC_CELLID = 1;
183 private static final int AGPS_RIL_REQUEST_REFLOC_MAC = 2;
184
185 // ref. location info
186 private static final int AGPS_REF_LOCATION_TYPE_GSM_CELLID = 1;
187 private static final int AGPS_REF_LOCATION_TYPE_UMTS_CELLID = 2;
188 private static final int AGPS_REG_LOCATION_TYPE_MAC = 3;
189
190 // set id info
191 private static final int AGPS_SETID_TYPE_NONE = 0;
192 private static final int AGPS_SETID_TYPE_IMSI = 1;
193 private static final int AGPS_SETID_TYPE_MSISDN = 2;
194
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800195 private static final String PROPERTIES_FILE = "/etc/gps.conf";
196
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700197 /** simpler wrapper for ProviderRequest + Worksource */
198 private static class GpsRequest {
199 public ProviderRequest request;
200 public WorkSource source;
201 public GpsRequest(ProviderRequest request, WorkSource source) {
202 this.request = request;
203 this.source = source;
204 }
205 }
206
207 private Object mLock = new Object();
208
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800209 private int mLocationFlags = LOCATION_INVALID;
210
211 // current status
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400212 private int mStatus = LocationProvider.TEMPORARILY_UNAVAILABLE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800213
214 // time for last status update
215 private long mStatusUpdateTime = SystemClock.elapsedRealtime();
Mike Lockwoodd53ba012010-04-15 20:41:26 -0400216
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800217 // turn off GPS fix icon if we haven't received a fix in 10 seconds
Mike Lockwood04598b62010-04-14 17:17:24 -0400218 private static final long RECENT_FIX_TIMEOUT = 10 * 1000;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800219
Mike Lockwood0632ca72009-05-14 15:51:03 -0400220 // stop trying if we do not receive a fix within 60 seconds
Mike Lockwood04598b62010-04-14 17:17:24 -0400221 private static final int NO_FIX_TIMEOUT = 60 * 1000;
Mike Lockwood0632ca72009-05-14 15:51:03 -0400222
Nick Pellyb041f232012-05-07 17:12:25 -0700223 // if the fix interval is below this we leave GPS on,
224 // if above then we cycle the GPS driver.
225 // Typical hot TTTF is ~5 seconds, so 10 seconds seems sane.
226 private static final int GPS_POLLING_THRESHOLD_INTERVAL = 10 * 1000;
227
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700228 // how often to request NTP time, in milliseconds
229 // current setting 24 hours
230 private static final long NTP_INTERVAL = 24*60*60*1000;
231 // how long to wait if we have a network error in NTP or XTRA downloading
232 // current setting - 5 minutes
233 private static final long RETRY_INTERVAL = 5*60*1000;
234
235 // true if we are enabled, protected by this
236 private boolean mEnabled;
237
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800238 // true if we have network connectivity
239 private boolean mNetworkAvailable;
240
Kevin Tang40e1baf2012-01-10 14:32:44 -0800241 // states for injecting ntp and downloading xtra data
242 private static final int STATE_PENDING_NETWORK = 0;
243 private static final int STATE_DOWNLOADING = 1;
244 private static final int STATE_IDLE = 2;
245
Mike Lockwood62a8fc12010-03-22 14:23:26 -0400246 // flags to trigger NTP or XTRA data download when network becomes available
247 // initialized to true so we do NTP and XTRA when the network comes up after booting
Kevin Tang40e1baf2012-01-10 14:32:44 -0800248 private int mInjectNtpTimePending = STATE_PENDING_NETWORK;
249 private int mDownloadXtraDataPending = STATE_PENDING_NETWORK;
Mike Lockwood62a8fc12010-03-22 14:23:26 -0400250
Mike Lockwood9b9fb5c2011-06-29 15:09:40 -0400251 // set to true if the GPS engine does not do on-demand NTP time requests
252 private boolean mPeriodicTimeInjection;
253
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800254 // true if GPS is navigating
255 private boolean mNavigating;
Mike Lockwoodcf1d8cb2010-01-20 10:14:54 -0500256
257 // true if GPS engine is on
258 private boolean mEngineOn;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700259
Mike Lockwood04598b62010-04-14 17:17:24 -0400260 // requested frequency of fixes, in milliseconds
261 private int mFixInterval = 1000;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800262
263 // true if we started navigation
264 private boolean mStarted;
265
Stan Chesnutt1d72d8c2013-04-15 19:18:02 -0700266 // true if single shot request is in progress
267 private boolean mSingleShot;
268
Mike Lockwood04598b62010-04-14 17:17:24 -0400269 // capabilities of the GPS engine
270 private int mEngineCapabilities;
271
Mike Lockwood1a1cd3a2010-08-17 07:42:54 -0400272 // true if XTRA is supported
273 private boolean mSupportsXtra;
274
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800275 // for calculating time to first fix
276 private long mFixRequestTime = 0;
277 // time to first fix for most recent session
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700278 private int mTimeToFirstFix = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800279 // time we received our last fix
280 private long mLastFixTime;
281
Mike Lockwood04598b62010-04-14 17:17:24 -0400282 private int mPositionMode;
283
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800284 // properties loaded from PROPERTIES_FILE
285 private Properties mProperties;
Mike Lockwood734d6032009-07-28 18:30:25 -0700286 private String mSuplServerHost;
287 private int mSuplServerPort;
288 private String mC2KServerHost;
289 private int mC2KServerPort;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800290
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400291 private final Context mContext;
Jeff Sharkey104344e2011-07-10 14:20:41 -0700292 private final NtpTrustedTime mNtpTime;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700293 private final ILocationManager mILocationManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800294 private Location mLocation = new Location(LocationManager.GPS_PROVIDER);
295 private Bundle mLocationExtras = new Bundle();
296 private ArrayList<Listener> mListeners = new ArrayList<Listener>();
Mike Lockwood62a8fc12010-03-22 14:23:26 -0400297
Victoria Lease5c24fd02012-10-01 11:00:50 -0700298 // Handler for processing events
Mike Lockwood62a8fc12010-03-22 14:23:26 -0400299 private Handler mHandler;
The Android Open Source Project10592532009-03-18 17:39:46 -0700300
Mike Lockwoode3635c92009-05-11 08:38:02 -0400301 private String mAGpsApn;
302 private int mAGpsDataConnectionState;
Stephen Li8efd74d2011-03-01 20:56:00 -0800303 private int mAGpsDataConnectionIpAddr;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400304 private final ConnectivityManager mConnMgr;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700305 private final GpsNetInitiatedHandler mNIHandler;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400306
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400307 // Wakelocks
308 private final static String WAKELOCK_KEY = "GpsLocationProvider";
309 private final PowerManager.WakeLock mWakeLock;
310
Mike Lockwood29c84342009-05-06 14:01:15 -0400311 // Alarms
312 private final static String ALARM_WAKEUP = "com.android.internal.location.ALARM_WAKEUP";
Mike Lockwood0632ca72009-05-14 15:51:03 -0400313 private final static String ALARM_TIMEOUT = "com.android.internal.location.ALARM_TIMEOUT";
Mike Lockwood29c84342009-05-06 14:01:15 -0400314 private final AlarmManager mAlarmManager;
315 private final PendingIntent mWakeupIntent;
Mike Lockwood0632ca72009-05-14 15:51:03 -0400316 private final PendingIntent mTimeoutIntent;
Mike Lockwood29c84342009-05-06 14:01:15 -0400317
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800318 private final IAppOpsService mAppOpsService;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400319 private final IBatteryStats mBatteryStats;
The Android Open Source Project10592532009-03-18 17:39:46 -0700320
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700321 // only modified on handler thread
Dianne Hackborn002a54e2013-01-10 17:34:55 -0800322 private WorkSource mClientSource = new WorkSource();
Mike Lockwoodf1218be2010-01-29 09:20:06 -0500323
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -0700324 private GeofenceHardwareImpl mGeofenceHardwareImpl;
325
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400326 private final IGpsStatusProvider mGpsStatusProvider = new IGpsStatusProvider.Stub() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700327 @Override
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400328 public void addGpsStatusListener(IGpsStatusListener listener) throws RemoteException {
329 if (listener == null) {
330 throw new NullPointerException("listener is null in addGpsStatusListener");
331 }
332
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700333 synchronized (mListeners) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400334 IBinder binder = listener.asBinder();
335 int size = mListeners.size();
336 for (int i = 0; i < size; i++) {
337 Listener test = mListeners.get(i);
338 if (binder.equals(test.mListener.asBinder())) {
339 // listener already added
340 return;
341 }
342 }
343
344 Listener l = new Listener(listener);
345 binder.linkToDeath(l, 0);
346 mListeners.add(l);
347 }
348 }
349
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700350 @Override
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400351 public void removeGpsStatusListener(IGpsStatusListener listener) {
352 if (listener == null) {
353 throw new NullPointerException("listener is null in addGpsStatusListener");
354 }
355
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700356 synchronized (mListeners) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400357 IBinder binder = listener.asBinder();
358 Listener l = null;
359 int size = mListeners.size();
360 for (int i = 0; i < size && l == null; i++) {
361 Listener test = mListeners.get(i);
362 if (binder.equals(test.mListener.asBinder())) {
363 l = test;
364 }
365 }
366
367 if (l != null) {
368 mListeners.remove(l);
369 binder.unlinkToDeath(l, 0);
370 }
371 }
372 }
373 };
374
375 public IGpsStatusProvider getGpsStatusProvider() {
376 return mGpsStatusProvider;
377 }
378
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -0700379 public IGpsGeofenceHardware getGpsGeofenceProxy() {
380 return mGpsGeofenceBinder;
381 }
382
Mike Lockwood29c84342009-05-06 14:01:15 -0400383 private final BroadcastReceiver mBroadcastReciever = new BroadcastReceiver() {
The Android Open Source Project10592532009-03-18 17:39:46 -0700384 @Override public void onReceive(Context context, Intent intent) {
385 String action = intent.getAction();
386
Mike Lockwood29c84342009-05-06 14:01:15 -0400387 if (action.equals(ALARM_WAKEUP)) {
388 if (DEBUG) Log.d(TAG, "ALARM_WAKEUP");
Stan Chesnutt1d72d8c2013-04-15 19:18:02 -0700389 startNavigating(false);
Mike Lockwood0632ca72009-05-14 15:51:03 -0400390 } else if (action.equals(ALARM_TIMEOUT)) {
391 if (DEBUG) Log.d(TAG, "ALARM_TIMEOUT");
392 hibernate();
Miguel Torroja1e84da82010-07-27 07:02:24 +0200393 } else if (action.equals(Intents.DATA_SMS_RECEIVED_ACTION)) {
394 checkSmsSuplInit(intent);
395 } else if (action.equals(Intents.WAP_PUSH_RECEIVED_ACTION)) {
396 checkWapSuplInit(intent);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700397 } else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
398 int networkState;
399 if (intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false)) {
400 networkState = LocationProvider.TEMPORARILY_UNAVAILABLE;
401 } else {
402 networkState = LocationProvider.AVAILABLE;
403 }
404
405 // retrieve NetworkInfo result for this UID
406 NetworkInfo info =
407 intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
408 ConnectivityManager connManager = (ConnectivityManager)
409 mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
410 info = connManager.getNetworkInfo(info.getType());
411
412 updateNetworkState(networkState, info);
Miguel Torroja1e84da82010-07-27 07:02:24 +0200413 }
The Android Open Source Project10592532009-03-18 17:39:46 -0700414 }
Mike Lockwood29c84342009-05-06 14:01:15 -0400415 };
The Android Open Source Project10592532009-03-18 17:39:46 -0700416
Miguel Torroja1e84da82010-07-27 07:02:24 +0200417 private void checkSmsSuplInit(Intent intent) {
418 SmsMessage[] messages = Intents.getMessagesFromIntent(intent);
419 for (int i=0; i <messages.length; i++) {
420 byte[] supl_init = messages[i].getUserData();
421 native_agps_ni_message(supl_init,supl_init.length);
422 }
423 }
424
425 private void checkWapSuplInit(Intent intent) {
426 byte[] supl_init = (byte[]) intent.getExtra("data");
427 native_agps_ni_message(supl_init,supl_init.length);
428 }
429
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800430 public static boolean isSupported() {
431 return native_is_supported();
432 }
433
Victoria Lease5cd731a2012-12-19 15:04:21 -0800434 public GpsLocationProvider(Context context, ILocationManager ilocationManager,
435 Looper looper) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800436 mContext = context;
Jeff Sharkey104344e2011-07-10 14:20:41 -0700437 mNtpTime = NtpTrustedTime.getInstance(context);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700438 mILocationManager = ilocationManager;
Mike Lockwood79e642e2010-03-17 23:19:25 -0400439 mNIHandler = new GpsNetInitiatedHandler(context);
Mike Lockwood63598a02010-02-24 11:52:59 -0500440
441 mLocation.setExtras(mLocationExtras);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800442
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400443 // Create a wake lock
444 PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
445 mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700446 mWakeLock.setReferenceCounted(true);
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400447
Mike Lockwood29c84342009-05-06 14:01:15 -0400448 mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
449 mWakeupIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_WAKEUP), 0);
Mike Lockwood0632ca72009-05-14 15:51:03 -0400450 mTimeoutIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_TIMEOUT), 0);
Mike Lockwood29c84342009-05-06 14:01:15 -0400451
Mike Lockwood58bda982009-04-14 16:25:07 -0400452 mConnMgr = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
453
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800454 // App ops service to keep track of who is accessing the GPS
455 mAppOpsService = IAppOpsService.Stub.asInterface(ServiceManager.getService(
456 Context.APP_OPS_SERVICE));
457
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400458 // Battery statistics service to be notified when GPS turns on or off
459 mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService("batteryinfo"));
460
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800461 mProperties = new Properties();
462 try {
463 File file = new File(PROPERTIES_FILE);
464 FileInputStream stream = new FileInputStream(file);
465 mProperties.load(stream);
466 stream.close();
Mike Lockwoode3635c92009-05-11 08:38:02 -0400467
Mike Lockwood734d6032009-07-28 18:30:25 -0700468 mSuplServerHost = mProperties.getProperty("SUPL_HOST");
Mike Lockwoode3635c92009-05-11 08:38:02 -0400469 String portString = mProperties.getProperty("SUPL_PORT");
Mike Lockwood734d6032009-07-28 18:30:25 -0700470 if (mSuplServerHost != null && portString != null) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700471 try {
Mike Lockwood734d6032009-07-28 18:30:25 -0700472 mSuplServerPort = Integer.parseInt(portString);
The Android Open Source Project10592532009-03-18 17:39:46 -0700473 } catch (NumberFormatException e) {
Mike Lockwoode3635c92009-05-11 08:38:02 -0400474 Log.e(TAG, "unable to parse SUPL_PORT: " + portString);
475 }
476 }
477
Mike Lockwood734d6032009-07-28 18:30:25 -0700478 mC2KServerHost = mProperties.getProperty("C2K_HOST");
Mike Lockwoode3635c92009-05-11 08:38:02 -0400479 portString = mProperties.getProperty("C2K_PORT");
Mike Lockwood734d6032009-07-28 18:30:25 -0700480 if (mC2KServerHost != null && portString != null) {
Mike Lockwoode3635c92009-05-11 08:38:02 -0400481 try {
Mike Lockwood734d6032009-07-28 18:30:25 -0700482 mC2KServerPort = Integer.parseInt(portString);
Mike Lockwoode3635c92009-05-11 08:38:02 -0400483 } catch (NumberFormatException e) {
484 Log.e(TAG, "unable to parse C2K_PORT: " + portString);
The Android Open Source Project10592532009-03-18 17:39:46 -0700485 }
486 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800487 } catch (IOException e) {
488 Log.w(TAG, "Could not open GPS configuration file " + PROPERTIES_FILE);
489 }
Mike Lockwood62a8fc12010-03-22 14:23:26 -0400490
Victoria Lease5c24fd02012-10-01 11:00:50 -0700491 // construct handler, listen for events
Victoria Lease5cd731a2012-12-19 15:04:21 -0800492 mHandler = new ProviderHandler(looper);
Victoria Lease5c24fd02012-10-01 11:00:50 -0700493 listenForBroadcasts();
494
495 // also listen for PASSIVE_PROVIDER updates
496 mHandler.post(new Runnable() {
497 @Override
498 public void run() {
499 LocationManager locManager =
500 (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
501 locManager.requestLocationUpdates(LocationManager.PASSIVE_PROVIDER,
502 0, 0, new NetworkLocationListener(), mHandler.getLooper());
Mike Lockwood89096312010-03-24 10:14:55 -0400503 }
Victoria Lease5c24fd02012-10-01 11:00:50 -0700504 });
Mike Lockwood62a8fc12010-03-22 14:23:26 -0400505 }
506
Victoria Lease5c24fd02012-10-01 11:00:50 -0700507 private void listenForBroadcasts() {
Mike Lockwood62a8fc12010-03-22 14:23:26 -0400508 IntentFilter intentFilter = new IntentFilter();
Victoria Lease5c24fd02012-10-01 11:00:50 -0700509 intentFilter.addAction(Intents.DATA_SMS_RECEIVED_ACTION);
510 intentFilter.addDataScheme("sms");
511 intentFilter.addDataAuthority("localhost","7275");
512 mContext.registerReceiver(mBroadcastReciever, intentFilter, null, mHandler);
513
514 intentFilter = new IntentFilter();
515 intentFilter.addAction(Intents.WAP_PUSH_RECEIVED_ACTION);
516 try {
517 intentFilter.addDataType("application/vnd.omaloc-supl-init");
518 } catch (IntentFilter.MalformedMimeTypeException e) {
519 Log.w(TAG, "Malformed SUPL init mime type");
520 }
521 mContext.registerReceiver(mBroadcastReciever, intentFilter, null, mHandler);
522
523 intentFilter = new IntentFilter();
Mike Lockwood62a8fc12010-03-22 14:23:26 -0400524 intentFilter.addAction(ALARM_WAKEUP);
525 intentFilter.addAction(ALARM_TIMEOUT);
Brian Muramatsub94b41f2012-08-21 16:30:57 -0700526 intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
Victoria Lease5c24fd02012-10-01 11:00:50 -0700527 mContext.registerReceiver(mBroadcastReciever, intentFilter, null, mHandler);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800528 }
529
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800530 /**
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500531 * Returns the name of this provider.
532 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700533 @Override
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500534 public String getName() {
535 return LocationManager.GPS_PROVIDER;
536 }
537
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700538 @Override
539 public ProviderProperties getProperties() {
540 return PROPERTIES;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800541 }
542
Mike Lockwood03d24672009-10-08 15:45:03 -0400543 public void updateNetworkState(int state, NetworkInfo info) {
Mike Lockwood98e48692010-04-07 16:32:51 -0400544 sendMessage(UPDATE_NETWORK_STATE, state, info);
Mike Lockwood62a8fc12010-03-22 14:23:26 -0400545 }
546
547 private void handleUpdateNetworkState(int state, NetworkInfo info) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800548 mNetworkAvailable = (state == LocationProvider.AVAILABLE);
549
Joe Onoratof5d95cb2010-01-07 21:48:32 -0500550 if (DEBUG) {
Mike Lockwood03d24672009-10-08 15:45:03 -0400551 Log.d(TAG, "updateNetworkState " + (mNetworkAvailable ? "available" : "unavailable")
552 + " info: " + info);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800553 }
Mike Lockwood03d24672009-10-08 15:45:03 -0400554
Mike Lockwood50130bb2010-10-11 06:22:50 -0400555 if (info != null) {
Jeff Brownbf6f6f92012-09-25 15:03:20 -0700556 boolean dataEnabled = Settings.Global.getInt(mContext.getContentResolver(),
557 Settings.Global.MOBILE_DATA, 1) == 1;
Kevin Tanga5fe6b22011-06-05 14:25:16 -0700558 boolean networkAvailable = info.isAvailable() && dataEnabled;
559 String defaultApn = getSelectedApn();
560 if (defaultApn == null) {
561 defaultApn = "dummy-apn";
562 }
563
Mike Lockwood50130bb2010-10-11 06:22:50 -0400564 native_update_network_state(info.isConnected(), info.getType(),
Kevin Tanga5fe6b22011-06-05 14:25:16 -0700565 info.isRoaming(), networkAvailable,
566 info.getExtraInfo(), defaultApn);
Mike Lockwood50130bb2010-10-11 06:22:50 -0400567 }
568
Mike Lockwood03d24672009-10-08 15:45:03 -0400569 if (info != null && info.getType() == ConnectivityManager.TYPE_MOBILE_SUPL
570 && mAGpsDataConnectionState == AGPS_DATA_CONNECTION_OPENING) {
571 String apnName = info.getExtraInfo();
Stephen Li83b69712011-01-25 18:47:28 -0800572 if (mNetworkAvailable) {
573 if (apnName == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700574 /* Assign a dummy value in the case of C2K as otherwise we will have a runtime
Stephen Li83b69712011-01-25 18:47:28 -0800575 exception in the following call to native_agps_data_conn_open*/
576 apnName = "dummy-apn";
577 }
Mike Lockwood03d24672009-10-08 15:45:03 -0400578 mAGpsApn = apnName;
Stephen Li8efd74d2011-03-01 20:56:00 -0800579 if (DEBUG) Log.d(TAG, "mAGpsDataConnectionIpAddr " + mAGpsDataConnectionIpAddr);
580 if (mAGpsDataConnectionIpAddr != 0xffffffff) {
581 boolean route_result;
582 if (DEBUG) Log.d(TAG, "call requestRouteToHost");
583 route_result = mConnMgr.requestRouteToHost(ConnectivityManager.TYPE_MOBILE_SUPL,
584 mAGpsDataConnectionIpAddr);
585 if (route_result == false) Log.d(TAG, "call requestRouteToHost failed");
586 }
Mike Lockwood03d24672009-10-08 15:45:03 -0400587 if (DEBUG) Log.d(TAG, "call native_agps_data_conn_open");
588 native_agps_data_conn_open(apnName);
589 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPEN;
590 } else {
591 if (DEBUG) Log.d(TAG, "call native_agps_data_conn_failed");
592 mAGpsApn = null;
593 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_CLOSED;
594 native_agps_data_conn_failed();
595 }
596 }
597
Mike Lockwood62a8fc12010-03-22 14:23:26 -0400598 if (mNetworkAvailable) {
Kevin Tang40e1baf2012-01-10 14:32:44 -0800599 if (mInjectNtpTimePending == STATE_PENDING_NETWORK) {
Mike Lockwood98e48692010-04-07 16:32:51 -0400600 sendMessage(INJECT_NTP_TIME, 0, null);
Mike Lockwood62a8fc12010-03-22 14:23:26 -0400601 }
Kevin Tang40e1baf2012-01-10 14:32:44 -0800602 if (mDownloadXtraDataPending == STATE_PENDING_NETWORK) {
Mike Lockwood98e48692010-04-07 16:32:51 -0400603 sendMessage(DOWNLOAD_XTRA_DATA, 0, null);
Mike Lockwood62a8fc12010-03-22 14:23:26 -0400604 }
605 }
606 }
607
608 private void handleInjectNtpTime() {
Kevin Tang40e1baf2012-01-10 14:32:44 -0800609 if (mInjectNtpTimePending == STATE_DOWNLOADING) {
610 // already downloading data
Mike Lockwood62a8fc12010-03-22 14:23:26 -0400611 return;
612 }
Kevin Tang40e1baf2012-01-10 14:32:44 -0800613 if (!mNetworkAvailable) {
614 // try again when network is up
615 mInjectNtpTimePending = STATE_PENDING_NETWORK;
616 return;
Jeff Sharkey104344e2011-07-10 14:20:41 -0700617 }
Kevin Tang40e1baf2012-01-10 14:32:44 -0800618 mInjectNtpTimePending = STATE_DOWNLOADING;
Jeff Sharkey104344e2011-07-10 14:20:41 -0700619
Jeff Brown028872f2012-08-25 13:07:01 -0700620 // hold wake lock while task runs
621 mWakeLock.acquire();
Kevin Tang40e1baf2012-01-10 14:32:44 -0800622 AsyncTask.THREAD_POOL_EXECUTOR.execute(new Runnable() {
623 @Override
624 public void run() {
625 long delay;
Mike Lockwood62a8fc12010-03-22 14:23:26 -0400626
Kevin Tang40e1baf2012-01-10 14:32:44 -0800627 // force refresh NTP cache when outdated
628 if (mNtpTime.getCacheAge() >= NTP_INTERVAL) {
629 mNtpTime.forceRefresh();
630 }
Mike Lockwood62a8fc12010-03-22 14:23:26 -0400631
Kevin Tang40e1baf2012-01-10 14:32:44 -0800632 // only update when NTP time is fresh
633 if (mNtpTime.getCacheAge() < NTP_INTERVAL) {
634 long time = mNtpTime.getCachedNtpTime();
635 long timeReference = mNtpTime.getCachedNtpTimeReference();
636 long certainty = mNtpTime.getCacheCertainty();
637 long now = System.currentTimeMillis();
Mike Lockwood62a8fc12010-03-22 14:23:26 -0400638
Kevin Tang40e1baf2012-01-10 14:32:44 -0800639 Log.d(TAG, "NTP server returned: "
640 + time + " (" + new Date(time)
641 + ") reference: " + timeReference
642 + " certainty: " + certainty
643 + " system time offset: " + (time - now));
644
645 native_inject_time(time, timeReference, (int) certainty);
646 delay = NTP_INTERVAL;
647 } else {
648 if (DEBUG) Log.d(TAG, "requestTime failed");
649 delay = RETRY_INTERVAL;
650 }
651
Jeff Brown028872f2012-08-25 13:07:01 -0700652 sendMessage(INJECT_NTP_TIME_FINISHED, 0, null);
Kevin Tang40e1baf2012-01-10 14:32:44 -0800653
654 if (mPeriodicTimeInjection) {
655 // send delayed message for next NTP injection
656 // since this is delayed and not urgent we do not hold a wake lock here
Jeff Brown028872f2012-08-25 13:07:01 -0700657 mHandler.sendEmptyMessageDelayed(INJECT_NTP_TIME, delay);
Kevin Tang40e1baf2012-01-10 14:32:44 -0800658 }
Jeff Brown028872f2012-08-25 13:07:01 -0700659
660 // release wake lock held by task
661 mWakeLock.release();
Kevin Tang40e1baf2012-01-10 14:32:44 -0800662 }
663 });
Mike Lockwood62a8fc12010-03-22 14:23:26 -0400664 }
665
666 private void handleDownloadXtraData() {
Kevin Tang40e1baf2012-01-10 14:32:44 -0800667 if (mDownloadXtraDataPending == STATE_DOWNLOADING) {
668 // already downloading data
Mike Lockwood62a8fc12010-03-22 14:23:26 -0400669 return;
670 }
Kevin Tang40e1baf2012-01-10 14:32:44 -0800671 if (!mNetworkAvailable) {
672 // try again when network is up
673 mDownloadXtraDataPending = STATE_PENDING_NETWORK;
674 return;
Mike Lockwood62a8fc12010-03-22 14:23:26 -0400675 }
Kevin Tang40e1baf2012-01-10 14:32:44 -0800676 mDownloadXtraDataPending = STATE_DOWNLOADING;
677
Jeff Brown028872f2012-08-25 13:07:01 -0700678 // hold wake lock while task runs
679 mWakeLock.acquire();
Kevin Tang40e1baf2012-01-10 14:32:44 -0800680 AsyncTask.THREAD_POOL_EXECUTOR.execute(new Runnable() {
681 @Override
682 public void run() {
683 GpsXtraDownloader xtraDownloader = new GpsXtraDownloader(mContext, mProperties);
684 byte[] data = xtraDownloader.downloadXtraData();
685 if (data != null) {
686 if (DEBUG) {
687 Log.d(TAG, "calling native_inject_xtra_data");
688 }
689 native_inject_xtra_data(data, data.length);
690 }
691
Jeff Brown028872f2012-08-25 13:07:01 -0700692 sendMessage(DOWNLOAD_XTRA_DATA_FINISHED, 0, null);
Kevin Tang40e1baf2012-01-10 14:32:44 -0800693
694 if (data == null) {
695 // try again later
696 // since this is delayed and not urgent we do not hold a wake lock here
Jeff Brown028872f2012-08-25 13:07:01 -0700697 mHandler.sendEmptyMessageDelayed(DOWNLOAD_XTRA_DATA, RETRY_INTERVAL);
Kevin Tang40e1baf2012-01-10 14:32:44 -0800698 }
Kevin Tang40e1baf2012-01-10 14:32:44 -0800699
Jeff Brown028872f2012-08-25 13:07:01 -0700700 // release wake lock held by task
701 mWakeLock.release();
702 }
Kevin Tang40e1baf2012-01-10 14:32:44 -0800703 });
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800704 }
705
Mike Lockwood62a8fc12010-03-22 14:23:26 -0400706 private void handleUpdateLocation(Location location) {
Mike Lockwoodd26ce0d2009-06-11 12:25:46 -0400707 if (location.hasAccuracy()) {
708 native_inject_location(location.getLatitude(), location.getLongitude(),
709 location.getAccuracy());
710 }
Mike Lockwoodfd6e5f02009-05-21 11:28:20 -0400711 }
712
713 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800714 * Enables this provider. When enabled, calls to getStatus()
Mike Lockwood4e50b782009-04-03 08:24:43 -0700715 * must be handled. Hardware may be started up
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800716 * when the provider is enabled.
717 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700718 @Override
Mike Lockwood62a8fc12010-03-22 14:23:26 -0400719 public void enable() {
Laurent Tu7b5aeca2013-01-24 15:10:24 -0800720 synchronized (mLock) {
721 if (mEnabled) return;
722 mEnabled = true;
723 }
724
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700725 sendMessage(ENABLE, 1, null);
Mike Lockwood62a8fc12010-03-22 14:23:26 -0400726 }
727
728 private void handleEnable() {
729 if (DEBUG) Log.d(TAG, "handleEnable");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800730
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700731 boolean enabled = native_init();
732
733 if (enabled) {
Mike Lockwood1a1cd3a2010-08-17 07:42:54 -0400734 mSupportsXtra = native_supports_xtra();
Mike Lockwood734d6032009-07-28 18:30:25 -0700735 if (mSuplServerHost != null) {
736 native_set_agps_server(AGPS_TYPE_SUPL, mSuplServerHost, mSuplServerPort);
737 }
738 if (mC2KServerHost != null) {
739 native_set_agps_server(AGPS_TYPE_C2K, mC2KServerHost, mC2KServerPort);
740 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800741 } else {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700742 synchronized (mLock) {
743 mEnabled = false;
744 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800745 Log.w(TAG, "Failed to enable location provider");
746 }
747 }
748
749 /**
750 * Disables this provider. When disabled, calls to getStatus()
Mike Lockwood4e50b782009-04-03 08:24:43 -0700751 * need not be handled. Hardware may be shut
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800752 * down while the provider is disabled.
753 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700754 @Override
Mike Lockwood62a8fc12010-03-22 14:23:26 -0400755 public void disable() {
Laurent Tu7b5aeca2013-01-24 15:10:24 -0800756 synchronized (mLock) {
757 if (!mEnabled) return;
758 mEnabled = false;
759 }
760
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700761 sendMessage(ENABLE, 0, null);
Mike Lockwood62a8fc12010-03-22 14:23:26 -0400762 }
763
764 private void handleDisable() {
Mike Lockwood89096312010-03-24 10:14:55 -0400765 if (DEBUG) Log.d(TAG, "handleDisable");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800766
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800767 stopNavigating();
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700768 mAlarmManager.cancel(mWakeupIntent);
769 mAlarmManager.cancel(mTimeoutIntent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800770
Mike Lockwoodcf1d8cb2010-01-20 10:14:54 -0500771 // do this before releasing wakelock
772 native_cleanup();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800773 }
774
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700775 @Override
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500776 public boolean isEnabled() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700777 synchronized (mLock) {
778 return mEnabled;
779 }
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500780 }
781
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700782 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800783 public int getStatus(Bundle extras) {
784 if (extras != null) {
785 extras.putInt("satellites", mSvCount);
786 }
787 return mStatus;
788 }
789
790 private void updateStatus(int status, int svCount) {
791 if (status != mStatus || svCount != mSvCount) {
792 mStatus = status;
793 mSvCount = svCount;
794 mLocationExtras.putInt("satellites", svCount);
795 mStatusUpdateTime = SystemClock.elapsedRealtime();
796 }
797 }
798
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700799 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800800 public long getStatusUpdateTime() {
801 return mStatusUpdateTime;
802 }
803
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700804 @Override
805 public void setRequest(ProviderRequest request, WorkSource source) {
806 sendMessage(SET_REQUEST, 0, new GpsRequest(request, source));
Mike Lockwood62a8fc12010-03-22 14:23:26 -0400807 }
808
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700809 private void handleSetRequest(ProviderRequest request, WorkSource source) {
Stan Chesnutt1d72d8c2013-04-15 19:18:02 -0700810 boolean singleShot = false;
811
812 // see if the request is for a single update
813 if (request.locationRequests != null && request.locationRequests.size() > 0) {
814 // if any request has zero or more than one updates
815 // requested, then this is not single-shot mode
816 singleShot = true;
817
818 for (LocationRequest lr : request.locationRequests) {
819 if (lr.getNumUpdates() != 1) {
820 singleShot = false;
821 }
822 }
823 }
824
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700825 if (DEBUG) Log.d(TAG, "setRequest " + request);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700826 if (request.reportLocation) {
827 // update client uids
Dianne Hackborn002a54e2013-01-10 17:34:55 -0800828 updateClientUids(source);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800829
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700830 mFixInterval = (int) request.interval;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700831
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700832 // check for overflow
833 if (mFixInterval != request.interval) {
834 Log.w(TAG, "interval overflow: " + request.interval);
835 mFixInterval = Integer.MAX_VALUE;
836 }
Mike Lockwood03ca2162010-04-01 08:10:09 -0700837
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700838 // apply request to GPS engine
Mike Lockwood04598b62010-04-14 17:17:24 -0400839 if (mStarted && hasCapability(GPS_CAPABILITY_SCHEDULING)) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700840 // change period
Mike Lockwood04598b62010-04-14 17:17:24 -0400841 if (!native_set_position_mode(mPositionMode, GPS_POSITION_RECURRENCE_PERIODIC,
842 mFixInterval, 0, 0)) {
843 Log.e(TAG, "set_position_mode failed in setMinTime()");
844 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700845 } else if (!mStarted) {
846 // start GPS
Stan Chesnutt1d72d8c2013-04-15 19:18:02 -0700847 startNavigating(singleShot);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800848 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700849 } else {
Dianne Hackborn002a54e2013-01-10 17:34:55 -0800850 updateClientUids(new WorkSource());
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700851
852 stopNavigating();
853 mAlarmManager.cancel(mWakeupIntent);
854 mAlarmManager.cancel(mTimeoutIntent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800855 }
856 }
857
858 private final class Listener implements IBinder.DeathRecipient {
859 final IGpsStatusListener mListener;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700860
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800861 Listener(IGpsStatusListener listener) {
862 mListener = listener;
863 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700864
865 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800866 public void binderDied() {
Joe Onoratof5d95cb2010-01-07 21:48:32 -0500867 if (DEBUG) Log.d(TAG, "GPS status listener died");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800868
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700869 synchronized (mListeners) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800870 mListeners.remove(this);
871 }
Suchi Amalapurapufff2fda2009-06-30 21:36:16 -0700872 if (mListener != null) {
873 mListener.asBinder().unlinkToDeath(this, 0);
874 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800875 }
876 }
877
Dianne Hackborn002a54e2013-01-10 17:34:55 -0800878 private void updateClientUids(WorkSource source) {
879 // Update work source.
880 WorkSource[] changes = mClientSource.setReturningDiffs(source);
Victoria Leaseea78b852013-01-15 10:39:28 -0800881 if (changes == null) {
882 return;
883 }
Dianne Hackborn002a54e2013-01-10 17:34:55 -0800884 WorkSource newWork = changes[0];
885 WorkSource goneWork = changes[1];
886
887 // Update sources that were not previously tracked.
888 if (newWork != null) {
889 int lastuid = -1;
890 for (int i=0; i<newWork.size(); i++) {
Dianne Hackborn2e418422009-06-22 20:00:17 -0700891 try {
Dianne Hackborn002a54e2013-01-10 17:34:55 -0800892 int uid = newWork.get(i);
893 mAppOpsService.startOperation(AppOpsManager.OP_GPS, uid, newWork.getName(i));
894 if (uid != lastuid) {
895 lastuid = uid;
896 mBatteryStats.noteStartGps(uid);
897 }
Dianne Hackborn2e418422009-06-22 20:00:17 -0700898 } catch (RemoteException e) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700899 Log.w(TAG, "RemoteException", e);
900 }
901 }
902 }
903
Dianne Hackborn002a54e2013-01-10 17:34:55 -0800904 // Update sources that are no longer tracked.
905 if (goneWork != null) {
906 int lastuid = -1;
907 for (int i=0; i<goneWork.size(); i++) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700908 try {
Dianne Hackborn002a54e2013-01-10 17:34:55 -0800909 int uid = goneWork.get(i);
910 mAppOpsService.finishOperation(AppOpsManager.OP_GPS, uid, goneWork.getName(i));
911 if (uid != lastuid) {
912 lastuid = uid;
913 mBatteryStats.noteStopGps(uid);
914 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700915 } catch (RemoteException e) {
916 Log.w(TAG, "RemoteException", e);
Dianne Hackborn2e418422009-06-22 20:00:17 -0700917 }
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400918 }
919 }
920 }
921
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700922 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800923 public boolean sendExtraCommand(String command, Bundle extras) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700924
Mike Lockwood63aa5a62010-04-14 19:21:31 -0400925 long identity = Binder.clearCallingIdentity();
926 boolean result = false;
927
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800928 if ("delete_aiding_data".equals(command)) {
Mike Lockwood63aa5a62010-04-14 19:21:31 -0400929 result = deleteAidingData(extras);
930 } else if ("force_time_injection".equals(command)) {
Mike Lockwood98e48692010-04-07 16:32:51 -0400931 sendMessage(INJECT_NTP_TIME, 0, null);
Mike Lockwood63aa5a62010-04-14 19:21:31 -0400932 result = true;
933 } else if ("force_xtra_injection".equals(command)) {
Mike Lockwood1a1cd3a2010-08-17 07:42:54 -0400934 if (mSupportsXtra) {
Mike Lockwood93bc44d2009-05-20 16:58:22 -0400935 xtraDownloadRequest();
Mike Lockwood63aa5a62010-04-14 19:21:31 -0400936 result = true;
Mike Lockwood93bc44d2009-05-20 16:58:22 -0400937 }
Mike Lockwood63aa5a62010-04-14 19:21:31 -0400938 } else {
939 Log.w(TAG, "sendExtraCommand: unknown command " + command);
Mike Lockwood93bc44d2009-05-20 16:58:22 -0400940 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700941
Mike Lockwood63aa5a62010-04-14 19:21:31 -0400942 Binder.restoreCallingIdentity(identity);
943 return result;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800944 }
945
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -0700946 private IGpsGeofenceHardware mGpsGeofenceBinder = new IGpsGeofenceHardware.Stub() {
947 public boolean isHardwareGeofenceSupported() {
948 return native_is_geofence_supported();
949 }
950
951 public boolean addCircularHardwareGeofence(int geofenceId, double latitude,
952 double longitude, double radius, int lastTransition, int monitorTransitions,
953 int notificationResponsiveness, int unknownTimer) {
954 return native_add_geofence(geofenceId, latitude, longitude, radius,
955 lastTransition, monitorTransitions, notificationResponsiveness, unknownTimer);
956 }
957
958 public boolean removeHardwareGeofence(int geofenceId) {
959 return native_remove_geofence(geofenceId);
960 }
961
962 public boolean pauseHardwareGeofence(int geofenceId) {
963 return native_pause_geofence(geofenceId);
964 }
965
966 public boolean resumeHardwareGeofence(int geofenceId, int monitorTransition) {
967 return native_resume_geofence(geofenceId, monitorTransition);
968 }
969 };
970
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800971 private boolean deleteAidingData(Bundle extras) {
972 int flags;
973
974 if (extras == null) {
975 flags = GPS_DELETE_ALL;
976 } else {
977 flags = 0;
978 if (extras.getBoolean("ephemeris")) flags |= GPS_DELETE_EPHEMERIS;
979 if (extras.getBoolean("almanac")) flags |= GPS_DELETE_ALMANAC;
980 if (extras.getBoolean("position")) flags |= GPS_DELETE_POSITION;
981 if (extras.getBoolean("time")) flags |= GPS_DELETE_TIME;
982 if (extras.getBoolean("iono")) flags |= GPS_DELETE_IONO;
983 if (extras.getBoolean("utc")) flags |= GPS_DELETE_UTC;
984 if (extras.getBoolean("health")) flags |= GPS_DELETE_HEALTH;
985 if (extras.getBoolean("svdir")) flags |= GPS_DELETE_SVDIR;
986 if (extras.getBoolean("svsteer")) flags |= GPS_DELETE_SVSTEER;
987 if (extras.getBoolean("sadata")) flags |= GPS_DELETE_SADATA;
988 if (extras.getBoolean("rti")) flags |= GPS_DELETE_RTI;
989 if (extras.getBoolean("celldb-info")) flags |= GPS_DELETE_CELLDB_INFO;
990 if (extras.getBoolean("all")) flags |= GPS_DELETE_ALL;
991 }
992
993 if (flags != 0) {
994 native_delete_aiding_data(flags);
995 return true;
996 }
997
998 return false;
999 }
1000
Stan Chesnutt1d72d8c2013-04-15 19:18:02 -07001001 private void startNavigating(boolean singleShot) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001002 if (!mStarted) {
Stan Chesnutt1d72d8c2013-04-15 19:18:02 -07001003 if (DEBUG) Log.d(TAG, "startNavigating, singleShot is " + singleShot);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001004 mTimeToFirstFix = 0;
1005 mLastFixTime = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001006 mStarted = true;
Stan Chesnutt1d72d8c2013-04-15 19:18:02 -07001007 mSingleShot = singleShot;
Mike Lockwood03ca2162010-04-01 08:10:09 -07001008 mPositionMode = GPS_POSITION_MODE_STANDALONE;
1009
Jeff Brownbf6f6f92012-09-25 15:03:20 -07001010 if (Settings.Global.getInt(mContext.getContentResolver(),
1011 Settings.Global.ASSISTED_GPS_ENABLED, 1) != 0) {
Stan Chesnutt1d72d8c2013-04-15 19:18:02 -07001012 if (singleShot && hasCapability(GPS_CAPABILITY_MSA)) {
1013 mPositionMode = GPS_POSITION_MODE_MS_ASSISTED;
1014 } else if (hasCapability(GPS_CAPABILITY_MSB)) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07001015 mPositionMode = GPS_POSITION_MODE_MS_BASED;
1016 }
Mike Lockwoodbcab8df2009-06-25 16:39:09 -04001017 }
1018
Stan Chesnutt1d72d8c2013-04-15 19:18:02 -07001019 if (DEBUG) {
1020 String mode;
1021
1022 switch(mPositionMode) {
1023 case GPS_POSITION_MODE_STANDALONE:
1024 mode = "standalone";
1025 break;
1026 case GPS_POSITION_MODE_MS_ASSISTED:
1027 mode = "MS_ASSISTED";
1028 break;
1029 case GPS_POSITION_MODE_MS_BASED:
1030 mode = "MS_BASED";
1031 break;
1032 default:
1033 mode = "unknown";
1034 break;
1035 }
1036 Log.d(TAG, "setting position_mode to " + mode);
1037 }
1038
Mike Lockwood04598b62010-04-14 17:17:24 -04001039 int interval = (hasCapability(GPS_CAPABILITY_SCHEDULING) ? mFixInterval : 1000);
1040 if (!native_set_position_mode(mPositionMode, GPS_POSITION_RECURRENCE_PERIODIC,
1041 interval, 0, 0)) {
1042 mStarted = false;
1043 Log.e(TAG, "set_position_mode failed in startNavigating()");
1044 return;
1045 }
1046 if (!native_start()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001047 mStarted = false;
1048 Log.e(TAG, "native_start failed in startNavigating()");
Mike Lockwood0632ca72009-05-14 15:51:03 -04001049 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001050 }
1051
1052 // reset SV count to zero
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001053 updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE, 0);
Mike Lockwood29c84342009-05-06 14:01:15 -04001054 mFixRequestTime = System.currentTimeMillis();
Mike Lockwood04598b62010-04-14 17:17:24 -04001055 if (!hasCapability(GPS_CAPABILITY_SCHEDULING)) {
1056 // set timer to give up if we do not receive a fix within NO_FIX_TIMEOUT
1057 // and our fix interval is not short
1058 if (mFixInterval >= NO_FIX_TIMEOUT) {
1059 mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
1060 SystemClock.elapsedRealtime() + NO_FIX_TIMEOUT, mTimeoutIntent);
1061 }
Mike Lockwood0632ca72009-05-14 15:51:03 -04001062 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001063 }
1064 }
1065
Mike Lockwood62a8fc12010-03-22 14:23:26 -04001066 private void stopNavigating() {
Mike Lockwood29c84342009-05-06 14:01:15 -04001067 if (DEBUG) Log.d(TAG, "stopNavigating");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001068 if (mStarted) {
1069 mStarted = false;
Stan Chesnutt1d72d8c2013-04-15 19:18:02 -07001070 mSingleShot = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001071 native_stop();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001072 mTimeToFirstFix = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001073 mLastFixTime = 0;
1074 mLocationFlags = LOCATION_INVALID;
1075
1076 // reset SV count to zero
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001077 updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001078 }
1079 }
1080
Mike Lockwood0632ca72009-05-14 15:51:03 -04001081 private void hibernate() {
1082 // stop GPS until our next fix interval arrives
1083 stopNavigating();
Mike Lockwood0632ca72009-05-14 15:51:03 -04001084 mAlarmManager.cancel(mTimeoutIntent);
1085 mAlarmManager.cancel(mWakeupIntent);
1086 long now = SystemClock.elapsedRealtime();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001087 mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, now + mFixInterval, mWakeupIntent);
Mike Lockwood04598b62010-04-14 17:17:24 -04001088 }
1089
1090 private boolean hasCapability(int capability) {
1091 return ((mEngineCapabilities & capability) != 0);
Mike Lockwood0632ca72009-05-14 15:51:03 -04001092 }
1093
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -07001094
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001095 /**
1096 * called from native code to update our position.
1097 */
1098 private void reportLocation(int flags, double latitude, double longitude, double altitude,
1099 float speed, float bearing, float accuracy, long timestamp) {
Mike Lockwood29c84342009-05-06 14:01:15 -04001100 if (VERBOSE) Log.v(TAG, "reportLocation lat: " + latitude + " long: " + longitude +
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001101 " timestamp: " + timestamp);
1102
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001103 synchronized (mLocation) {
1104 mLocationFlags = flags;
1105 if ((flags & LOCATION_HAS_LAT_LONG) == LOCATION_HAS_LAT_LONG) {
1106 mLocation.setLatitude(latitude);
1107 mLocation.setLongitude(longitude);
1108 mLocation.setTime(timestamp);
Nick Pelly2eeeec22012-07-18 13:13:37 -07001109 // It would be nice to push the elapsed real-time timestamp
1110 // further down the stack, but this is still useful
Philip Milne41180122012-09-26 11:29:25 -07001111 mLocation.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001112 }
1113 if ((flags & LOCATION_HAS_ALTITUDE) == LOCATION_HAS_ALTITUDE) {
1114 mLocation.setAltitude(altitude);
1115 } else {
1116 mLocation.removeAltitude();
1117 }
1118 if ((flags & LOCATION_HAS_SPEED) == LOCATION_HAS_SPEED) {
1119 mLocation.setSpeed(speed);
1120 } else {
1121 mLocation.removeSpeed();
1122 }
1123 if ((flags & LOCATION_HAS_BEARING) == LOCATION_HAS_BEARING) {
1124 mLocation.setBearing(bearing);
1125 } else {
1126 mLocation.removeBearing();
1127 }
1128 if ((flags & LOCATION_HAS_ACCURACY) == LOCATION_HAS_ACCURACY) {
1129 mLocation.setAccuracy(accuracy);
1130 } else {
1131 mLocation.removeAccuracy();
1132 }
Sean Barbeauced2b2c2011-12-19 04:43:07 -05001133 mLocation.setExtras(mLocationExtras);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001134
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001135 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001136 mILocationManager.reportLocation(mLocation, false);
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001137 } catch (RemoteException e) {
1138 Log.e(TAG, "RemoteException calling reportLocation");
1139 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001140 }
1141
Hakan Gustavssonfa94ff02010-02-23 09:12:38 +01001142 mLastFixTime = System.currentTimeMillis();
1143 // report time to first fix
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001144 if (mTimeToFirstFix == 0 && (flags & LOCATION_HAS_LAT_LONG) == LOCATION_HAS_LAT_LONG) {
1145 mTimeToFirstFix = (int)(mLastFixTime - mFixRequestTime);
1146 if (DEBUG) Log.d(TAG, "TTFF: " + mTimeToFirstFix);
Hakan Gustavssonfa94ff02010-02-23 09:12:38 +01001147
1148 // notify status listeners
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001149 synchronized (mListeners) {
Hakan Gustavssonfa94ff02010-02-23 09:12:38 +01001150 int size = mListeners.size();
1151 for (int i = 0; i < size; i++) {
1152 Listener listener = mListeners.get(i);
1153 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001154 listener.mListener.onFirstFix(mTimeToFirstFix);
Hakan Gustavssonfa94ff02010-02-23 09:12:38 +01001155 } catch (RemoteException e) {
1156 Log.w(TAG, "RemoteException in stopNavigating");
1157 mListeners.remove(listener);
1158 // adjust for size of list changing
1159 size--;
1160 }
1161 }
1162 }
1163 }
1164
Stan Chesnutt1d72d8c2013-04-15 19:18:02 -07001165 if (mSingleShot) {
1166 stopNavigating();
1167 }
1168
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001169 if (mStarted && mStatus != LocationProvider.AVAILABLE) {
Mike Lockwoodd53ba012010-04-15 20:41:26 -04001170 // we want to time out if we do not receive a fix
Mike Lockwoodb7be5442010-02-24 14:34:50 -05001171 // within the time out and we are requesting infrequent fixes
Mike Lockwood04598b62010-04-14 17:17:24 -04001172 if (!hasCapability(GPS_CAPABILITY_SCHEDULING) && mFixInterval < NO_FIX_TIMEOUT) {
Mike Lockwoodb7be5442010-02-24 14:34:50 -05001173 mAlarmManager.cancel(mTimeoutIntent);
1174 }
1175
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001176 // send an intent to notify that the GPS is receiving fixes.
Mike Lockwood00b74272010-03-26 10:41:48 -04001177 Intent intent = new Intent(LocationManager.GPS_FIX_CHANGE_ACTION);
1178 intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, true);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001179 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001180 updateStatus(LocationProvider.AVAILABLE, mSvCount);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001181 }
Mike Lockwood29c84342009-05-06 14:01:15 -04001182
Nick Pellyb041f232012-05-07 17:12:25 -07001183 if (!hasCapability(GPS_CAPABILITY_SCHEDULING) && mStarted &&
1184 mFixInterval > GPS_POLLING_THRESHOLD_INTERVAL) {
Mike Lockwoodd53ba012010-04-15 20:41:26 -04001185 if (DEBUG) Log.d(TAG, "got fix, hibernating");
Mike Lockwood0632ca72009-05-14 15:51:03 -04001186 hibernate();
Mike Lockwood29c84342009-05-06 14:01:15 -04001187 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001188 }
1189
1190 /**
1191 * called from native code to update our status
1192 */
1193 private void reportStatus(int status) {
Mike Lockwoodb8d90332010-10-18 17:59:48 -04001194 if (DEBUG) Log.v(TAG, "reportStatus status: " + status);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001195
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001196 synchronized (mListeners) {
Dianne Hackborn2e418422009-06-22 20:00:17 -07001197 boolean wasNavigating = mNavigating;
Mike Lockwooddbd6fd82009-12-07 18:43:36 -05001198
Mike Lockwoodcf1d8cb2010-01-20 10:14:54 -05001199 switch (status) {
1200 case GPS_STATUS_SESSION_BEGIN:
1201 mNavigating = true;
Mike Lockwood271f9f12010-02-02 11:41:52 -05001202 mEngineOn = true;
Mike Lockwoodcf1d8cb2010-01-20 10:14:54 -05001203 break;
1204 case GPS_STATUS_SESSION_END:
1205 mNavigating = false;
1206 break;
1207 case GPS_STATUS_ENGINE_ON:
1208 mEngineOn = true;
1209 break;
1210 case GPS_STATUS_ENGINE_OFF:
1211 mEngineOn = false;
Mike Lockwood271f9f12010-02-02 11:41:52 -05001212 mNavigating = false;
Mike Lockwoodcf1d8cb2010-01-20 10:14:54 -05001213 break;
1214 }
1215
Mike Lockwooddbd6fd82009-12-07 18:43:36 -05001216 if (wasNavigating != mNavigating) {
1217 int size = mListeners.size();
1218 for (int i = 0; i < size; i++) {
1219 Listener listener = mListeners.get(i);
1220 try {
1221 if (mNavigating) {
1222 listener.mListener.onGpsStarted();
1223 } else {
1224 listener.mListener.onGpsStopped();
1225 }
1226 } catch (RemoteException e) {
1227 Log.w(TAG, "RemoteException in reportStatus");
1228 mListeners.remove(listener);
1229 // adjust for size of list changing
1230 size--;
1231 }
1232 }
1233
Mike Lockwooddbd6fd82009-12-07 18:43:36 -05001234 // send an intent to notify that the GPS has been enabled or disabled.
Mike Lockwood00b74272010-03-26 10:41:48 -04001235 Intent intent = new Intent(LocationManager.GPS_ENABLED_CHANGE_ACTION);
1236 intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, mNavigating);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001237 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001238 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001239 }
1240 }
1241
1242 /**
1243 * called from native code to update SV info
1244 */
1245 private void reportSvStatus() {
1246
1247 int svCount = native_read_sv_status(mSvs, mSnrs, mSvElevations, mSvAzimuths, mSvMasks);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001248
1249 synchronized (mListeners) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001250 int size = mListeners.size();
1251 for (int i = 0; i < size; i++) {
1252 Listener listener = mListeners.get(i);
1253 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001254 listener.mListener.onSvStatusChanged(svCount, mSvs, mSnrs,
1255 mSvElevations, mSvAzimuths, mSvMasks[EPHEMERIS_MASK],
1256 mSvMasks[ALMANAC_MASK], mSvMasks[USED_FOR_FIX_MASK]);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001257 } catch (RemoteException e) {
1258 Log.w(TAG, "RemoteException in reportSvInfo");
1259 mListeners.remove(listener);
1260 // adjust for size of list changing
1261 size--;
1262 }
1263 }
1264 }
1265
Mike Lockwood29c84342009-05-06 14:01:15 -04001266 if (VERBOSE) {
1267 Log.v(TAG, "SV count: " + svCount +
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001268 " ephemerisMask: " + Integer.toHexString(mSvMasks[EPHEMERIS_MASK]) +
1269 " almanacMask: " + Integer.toHexString(mSvMasks[ALMANAC_MASK]));
1270 for (int i = 0; i < svCount; i++) {
Mike Lockwood29c84342009-05-06 14:01:15 -04001271 Log.v(TAG, "sv: " + mSvs[i] +
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001272 " snr: " + mSnrs[i]/10 +
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001273 " elev: " + mSvElevations[i] +
1274 " azimuth: " + mSvAzimuths[i] +
1275 ((mSvMasks[EPHEMERIS_MASK] & (1 << (mSvs[i] - 1))) == 0 ? " " : " E") +
1276 ((mSvMasks[ALMANAC_MASK] & (1 << (mSvs[i] - 1))) == 0 ? " " : " A") +
1277 ((mSvMasks[USED_FOR_FIX_MASK] & (1 << (mSvs[i] - 1))) == 0 ? "" : "U"));
1278 }
1279 }
1280
Kevin.KY Tsai0881f4f2010-05-21 15:10:39 -04001281 // return number of sets used in fix instead of total
1282 updateStatus(mStatus, Integer.bitCount(mSvMasks[USED_FOR_FIX_MASK]));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001283
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001284 if (mNavigating && mStatus == LocationProvider.AVAILABLE && mLastFixTime > 0 &&
Mike Lockwood04598b62010-04-14 17:17:24 -04001285 System.currentTimeMillis() - mLastFixTime > RECENT_FIX_TIMEOUT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001286 // send an intent to notify that the GPS is no longer receiving fixes.
Mike Lockwood00b74272010-03-26 10:41:48 -04001287 Intent intent = new Intent(LocationManager.GPS_FIX_CHANGE_ACTION);
1288 intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, false);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001289 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001290 updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE, mSvCount);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001291 }
1292 }
Mike Lockwood58bda982009-04-14 16:25:07 -04001293
1294 /**
Mike Lockwoode3635c92009-05-11 08:38:02 -04001295 * called from native code to update AGPS status
Mike Lockwood58bda982009-04-14 16:25:07 -04001296 */
Stephen Li8efd74d2011-03-01 20:56:00 -08001297 private void reportAGpsStatus(int type, int status, int ipaddr) {
Mike Lockwood58bda982009-04-14 16:25:07 -04001298 switch (status) {
Mike Lockwoode3635c92009-05-11 08:38:02 -04001299 case GPS_REQUEST_AGPS_DATA_CONN:
Mike Lockwoodb6e5fa82010-10-09 20:10:46 -04001300 if (DEBUG) Log.d(TAG, "GPS_REQUEST_AGPS_DATA_CONN");
Mike Lockwood2acfd342010-09-22 12:13:39 -04001301 // Set mAGpsDataConnectionState before calling startUsingNetworkFeature
1302 // to avoid a race condition with handleUpdateNetworkState()
1303 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPENING;
1304 int result = mConnMgr.startUsingNetworkFeature(
Mike Lockwood58bda982009-04-14 16:25:07 -04001305 ConnectivityManager.TYPE_MOBILE, Phone.FEATURE_ENABLE_SUPL);
Stephen Li8efd74d2011-03-01 20:56:00 -08001306 mAGpsDataConnectionIpAddr = ipaddr;
Wink Savillea639b312012-07-10 12:37:54 -07001307 if (result == PhoneConstants.APN_ALREADY_ACTIVE) {
1308 if (DEBUG) Log.d(TAG, "PhoneConstants.APN_ALREADY_ACTIVE");
Mike Lockwoodb362a9a2009-06-22 16:20:39 -04001309 if (mAGpsApn != null) {
Stephen Li8efd74d2011-03-01 20:56:00 -08001310 Log.d(TAG, "mAGpsDataConnectionIpAddr " + mAGpsDataConnectionIpAddr);
1311 if (mAGpsDataConnectionIpAddr != 0xffffffff) {
1312 boolean route_result;
1313 if (DEBUG) Log.d(TAG, "call requestRouteToHost");
1314 route_result = mConnMgr.requestRouteToHost(
1315 ConnectivityManager.TYPE_MOBILE_SUPL,
1316 mAGpsDataConnectionIpAddr);
1317 if (route_result == false) Log.d(TAG, "call requestRouteToHost failed");
1318 }
Mike Lockwoodb362a9a2009-06-22 16:20:39 -04001319 native_agps_data_conn_open(mAGpsApn);
1320 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPEN;
1321 } else {
Wink Savillea639b312012-07-10 12:37:54 -07001322 Log.e(TAG, "mAGpsApn not set when receiving PhoneConstants.APN_ALREADY_ACTIVE");
Mike Lockwood2acfd342010-09-22 12:13:39 -04001323 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_CLOSED;
Mike Lockwoodb362a9a2009-06-22 16:20:39 -04001324 native_agps_data_conn_failed();
1325 }
Wink Savillea639b312012-07-10 12:37:54 -07001326 } else if (result == PhoneConstants.APN_REQUEST_STARTED) {
1327 if (DEBUG) Log.d(TAG, "PhoneConstants.APN_REQUEST_STARTED");
Mike Lockwood2acfd342010-09-22 12:13:39 -04001328 // Nothing to do here
Mike Lockwood58bda982009-04-14 16:25:07 -04001329 } else {
Stan Chesnutt1d72d8c2013-04-15 19:18:02 -07001330 if (DEBUG) Log.d(TAG, "startUsingNetworkFeature failed, value is " +
1331 result);
Mike Lockwood2acfd342010-09-22 12:13:39 -04001332 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_CLOSED;
Mike Lockwoode3635c92009-05-11 08:38:02 -04001333 native_agps_data_conn_failed();
Mike Lockwood58bda982009-04-14 16:25:07 -04001334 }
1335 break;
Mike Lockwoode3635c92009-05-11 08:38:02 -04001336 case GPS_RELEASE_AGPS_DATA_CONN:
Mike Lockwoodb6e5fa82010-10-09 20:10:46 -04001337 if (DEBUG) Log.d(TAG, "GPS_RELEASE_AGPS_DATA_CONN");
Mike Lockwoode3635c92009-05-11 08:38:02 -04001338 if (mAGpsDataConnectionState != AGPS_DATA_CONNECTION_CLOSED) {
Mike Lockwood58bda982009-04-14 16:25:07 -04001339 mConnMgr.stopUsingNetworkFeature(
1340 ConnectivityManager.TYPE_MOBILE, Phone.FEATURE_ENABLE_SUPL);
Mike Lockwoode3635c92009-05-11 08:38:02 -04001341 native_agps_data_conn_closed();
1342 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_CLOSED;
Mike Lockwood58bda982009-04-14 16:25:07 -04001343 }
1344 break;
Mike Lockwoode3635c92009-05-11 08:38:02 -04001345 case GPS_AGPS_DATA_CONNECTED:
Mike Lockwoodb6e5fa82010-10-09 20:10:46 -04001346 if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONNECTED");
Mike Lockwood58bda982009-04-14 16:25:07 -04001347 break;
Mike Lockwoode3635c92009-05-11 08:38:02 -04001348 case GPS_AGPS_DATA_CONN_DONE:
Mike Lockwoodb6e5fa82010-10-09 20:10:46 -04001349 if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONN_DONE");
Mike Lockwood58bda982009-04-14 16:25:07 -04001350 break;
Mike Lockwoode3635c92009-05-11 08:38:02 -04001351 case GPS_AGPS_DATA_CONN_FAILED:
Mike Lockwoodb6e5fa82010-10-09 20:10:46 -04001352 if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONN_FAILED");
Mike Lockwood58bda982009-04-14 16:25:07 -04001353 break;
1354 }
1355 }
1356
Mike Lockwoodb16e7802009-08-06 09:26:02 -04001357 /**
1358 * called from native code to report NMEA data received
1359 */
Mike Lockwoodf602d362010-06-20 14:28:16 -07001360 private void reportNmea(long timestamp) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001361 synchronized (mListeners) {
Mike Lockwoodb16e7802009-08-06 09:26:02 -04001362 int size = mListeners.size();
1363 if (size > 0) {
1364 // don't bother creating the String if we have no listeners
Mike Lockwoodf602d362010-06-20 14:28:16 -07001365 int length = native_read_nmea(mNmeaBuffer, mNmeaBuffer.length);
Mike Lockwoodb16e7802009-08-06 09:26:02 -04001366 String nmea = new String(mNmeaBuffer, 0, length);
1367
1368 for (int i = 0; i < size; i++) {
1369 Listener listener = mListeners.get(i);
1370 try {
1371 listener.mListener.onNmeaReceived(timestamp, nmea);
1372 } catch (RemoteException e) {
1373 Log.w(TAG, "RemoteException in reportNmea");
1374 mListeners.remove(listener);
1375 // adjust for size of list changing
1376 size--;
1377 }
1378 }
1379 }
1380 }
1381 }
1382
Mike Lockwood62a8fc12010-03-22 14:23:26 -04001383 /**
Mike Lockwood04598b62010-04-14 17:17:24 -04001384 * called from native code to inform us what the GPS engine capabilities are
1385 */
1386 private void setEngineCapabilities(int capabilities) {
1387 mEngineCapabilities = capabilities;
Mike Lockwood9b9fb5c2011-06-29 15:09:40 -04001388
1389 if (!hasCapability(GPS_CAPABILITY_ON_DEMAND_TIME) && !mPeriodicTimeInjection) {
1390 mPeriodicTimeInjection = true;
1391 requestUtcTime();
1392 }
Mike Lockwood04598b62010-04-14 17:17:24 -04001393 }
1394
1395 /**
Mike Lockwood62a8fc12010-03-22 14:23:26 -04001396 * called from native code to request XTRA data
1397 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001398 private void xtraDownloadRequest() {
Joe Onoratof5d95cb2010-01-07 21:48:32 -05001399 if (DEBUG) Log.d(TAG, "xtraDownloadRequest");
Mike Lockwood98e48692010-04-07 16:32:51 -04001400 sendMessage(DOWNLOAD_XTRA_DATA, 0, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001401 }
1402
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -07001403 /**
1404 * Called from native to report GPS Geofence transition
1405 * All geofence callbacks are called on the same thread
1406 */
1407 private void reportGeofenceTransition(int geofenceId, int flags, double latitude,
1408 double longitude, double altitude, float speed, float bearing, float accuracy,
1409 long timestamp, int transition, long transitionTimestamp) {
1410 if (mGeofenceHardwareImpl == null) {
1411 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
1412 }
1413 mGeofenceHardwareImpl.reportGpsGeofenceTransition(geofenceId, flags, latitude, longitude,
1414 altitude, speed, bearing, accuracy, timestamp, transition, transitionTimestamp);
1415 }
1416
1417 /**
1418 * called from native code to report GPS status change.
1419 */
1420 private void reportGeofenceStatus(int status, int flags, double latitude,
1421 double longitude, double altitude, float speed, float bearing, float accuracy,
1422 long timestamp) {
1423 if (mGeofenceHardwareImpl == null) {
1424 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
1425 }
1426 mGeofenceHardwareImpl.reportGpsGeofenceStatus(status, flags, latitude, longitude, altitude,
1427 speed, bearing, accuracy, timestamp);
1428 }
1429
1430 /**
1431 * called from native code - Geofence Add callback
1432 */
1433 private void reportGeofenceAddStatus(int geofenceId, int status) {
1434 if (mGeofenceHardwareImpl == null) {
1435 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
1436 }
1437 mGeofenceHardwareImpl.reportGpsGeofenceAddStatus(geofenceId, status);
1438 }
1439
1440 /**
1441 * called from native code - Geofence Remove callback
1442 */
1443 private void reportGeofenceRemoveStatus(int geofenceId, int status) {
1444 if (mGeofenceHardwareImpl == null) {
1445 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
1446 }
1447 mGeofenceHardwareImpl.reportGpsGeofenceRemoveStatus(geofenceId, status);
1448 }
1449
1450 /**
1451 * called from native code - Geofence Pause callback
1452 */
1453 private void reportGeofencePauseStatus(int geofenceId, int status) {
1454 if (mGeofenceHardwareImpl == null) {
1455 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
1456 }
1457 mGeofenceHardwareImpl.reportGpsGeofencePauseStatus(geofenceId, status);
1458 }
1459
1460 /**
1461 * called from native code - Geofence Resume callback
1462 */
1463 private void reportGeofenceResumeStatus(int geofenceId, int status) {
1464 if (mGeofenceHardwareImpl == null) {
1465 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
1466 }
1467 mGeofenceHardwareImpl.reportGpsGeofenceResumeStatus(geofenceId, status);
1468 }
1469
Danke Xie22d1f9f2009-08-18 18:28:45 -04001470 //=============================================================
1471 // NI Client support
Miguel Torroja1e84da82010-07-27 07:02:24 +02001472 //=============================================================
Danke Xie22d1f9f2009-08-18 18:28:45 -04001473 private final INetInitiatedListener mNetInitiatedListener = new INetInitiatedListener.Stub() {
Miguel Torroja1e84da82010-07-27 07:02:24 +02001474 // Sends a response for an NI reqeust to HAL.
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001475 @Override
Miguel Torroja1e84da82010-07-27 07:02:24 +02001476 public boolean sendNiResponse(int notificationId, int userResponse)
1477 {
1478 // TODO Add Permission check
Danke Xie22d1f9f2009-08-18 18:28:45 -04001479
Miguel Torroja1e84da82010-07-27 07:02:24 +02001480 if (DEBUG) Log.d(TAG, "sendNiResponse, notifId: " + notificationId +
1481 ", response: " + userResponse);
1482 native_send_ni_response(notificationId, userResponse);
1483 return true;
1484 }
Danke Xie22d1f9f2009-08-18 18:28:45 -04001485 };
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001486
Danke Xie22d1f9f2009-08-18 18:28:45 -04001487 public INetInitiatedListener getNetInitiatedListener() {
1488 return mNetInitiatedListener;
1489 }
1490
1491 // Called by JNI function to report an NI request.
Miguel Torroja1e84da82010-07-27 07:02:24 +02001492 public void reportNiNotification(
1493 int notificationId,
1494 int niType,
1495 int notifyFlags,
1496 int timeout,
1497 int defaultResponse,
1498 String requestorId,
1499 String text,
1500 int requestorIdEncoding,
1501 int textEncoding,
1502 String extras // Encoded extra data
Danke Xie22d1f9f2009-08-18 18:28:45 -04001503 )
Miguel Torroja1e84da82010-07-27 07:02:24 +02001504 {
1505 Log.i(TAG, "reportNiNotification: entered");
1506 Log.i(TAG, "notificationId: " + notificationId +
1507 ", niType: " + niType +
1508 ", notifyFlags: " + notifyFlags +
1509 ", timeout: " + timeout +
1510 ", defaultResponse: " + defaultResponse);
1511
1512 Log.i(TAG, "requestorId: " + requestorId +
1513 ", text: " + text +
1514 ", requestorIdEncoding: " + requestorIdEncoding +
1515 ", textEncoding: " + textEncoding);
1516
1517 GpsNiNotification notification = new GpsNiNotification();
1518
1519 notification.notificationId = notificationId;
1520 notification.niType = niType;
1521 notification.needNotify = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_NEED_NOTIFY) != 0;
1522 notification.needVerify = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_NEED_VERIFY) != 0;
1523 notification.privacyOverride = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_PRIVACY_OVERRIDE) != 0;
1524 notification.timeout = timeout;
1525 notification.defaultResponse = defaultResponse;
1526 notification.requestorId = requestorId;
1527 notification.text = text;
1528 notification.requestorIdEncoding = requestorIdEncoding;
1529 notification.textEncoding = textEncoding;
1530
1531 // Process extras, assuming the format is
1532 // one of more lines of "key = value"
1533 Bundle bundle = new Bundle();
1534
1535 if (extras == null) extras = "";
1536 Properties extraProp = new Properties();
1537
1538 try {
Jeff Sharkey104344e2011-07-10 14:20:41 -07001539 extraProp.load(new StringReader(extras));
Miguel Torroja1e84da82010-07-27 07:02:24 +02001540 }
1541 catch (IOException e)
1542 {
1543 Log.e(TAG, "reportNiNotification cannot parse extras data: " + extras);
1544 }
1545
1546 for (Entry<Object, Object> ent : extraProp.entrySet())
1547 {
1548 bundle.putString((String) ent.getKey(), (String) ent.getValue());
1549 }
1550
1551 notification.extras = bundle;
1552
1553 mNIHandler.handleNiNotification(notification);
1554 }
1555
1556 /**
1557 * Called from native code to request set id info.
1558 * We should be careful about receiving null string from the TelephonyManager,
1559 * because sending null String to JNI function would cause a crash.
1560 */
1561
1562 private void requestSetID(int flags) {
1563 TelephonyManager phone = (TelephonyManager)
1564 mContext.getSystemService(Context.TELEPHONY_SERVICE);
1565 int type = AGPS_SETID_TYPE_NONE;
1566 String data = "";
1567
1568 if ((flags & AGPS_RIL_REQUEST_SETID_IMSI) == AGPS_RIL_REQUEST_SETID_IMSI) {
1569 String data_temp = phone.getSubscriberId();
1570 if (data_temp == null) {
1571 // This means the framework does not have the SIM card ready.
1572 } else {
1573 // This means the framework has the SIM card.
1574 data = data_temp;
1575 type = AGPS_SETID_TYPE_IMSI;
1576 }
1577 }
1578 else if ((flags & AGPS_RIL_REQUEST_SETID_MSISDN) == AGPS_RIL_REQUEST_SETID_MSISDN) {
1579 String data_temp = phone.getLine1Number();
1580 if (data_temp == null) {
1581 // This means the framework does not have the SIM card ready.
1582 } else {
1583 // This means the framework has the SIM card.
1584 data = data_temp;
1585 type = AGPS_SETID_TYPE_MSISDN;
1586 }
1587 }
1588 native_agps_set_id(type, data);
1589 }
1590
1591 /**
Mike Lockwood9b9fb5c2011-06-29 15:09:40 -04001592 * Called from native code to request utc time info
1593 */
1594
1595 private void requestUtcTime() {
1596 sendMessage(INJECT_NTP_TIME, 0, null);
1597 }
1598
1599 /**
Miguel Torroja1e84da82010-07-27 07:02:24 +02001600 * Called from native code to request reference location info
1601 */
1602
1603 private void requestRefLocation(int flags) {
1604 TelephonyManager phone = (TelephonyManager)
1605 mContext.getSystemService(Context.TELEPHONY_SERVICE);
Victoria Leased50d0c32012-10-29 13:16:17 -07001606 final int phoneType = phone.getPhoneType();
1607 if (phoneType == TelephonyManager.PHONE_TYPE_GSM) {
Miguel Torroja1e84da82010-07-27 07:02:24 +02001608 GsmCellLocation gsm_cell = (GsmCellLocation) phone.getCellLocation();
Victoria Leased50d0c32012-10-29 13:16:17 -07001609 if ((gsm_cell != null) && (phone.getNetworkOperator() != null)
1610 && (phone.getNetworkOperator().length() > 3)) {
Miguel Torroja1e84da82010-07-27 07:02:24 +02001611 int type;
1612 int mcc = Integer.parseInt(phone.getNetworkOperator().substring(0,3));
1613 int mnc = Integer.parseInt(phone.getNetworkOperator().substring(3));
Mike Lockwoodedc0f3872010-10-22 09:16:17 -04001614 int networkType = phone.getNetworkType();
1615 if (networkType == TelephonyManager.NETWORK_TYPE_UMTS
1616 || networkType == TelephonyManager.NETWORK_TYPE_HSDPA
1617 || networkType == TelephonyManager.NETWORK_TYPE_HSUPA
Arun Ravindran58d46122012-07-30 17:50:21 +03001618 || networkType == TelephonyManager.NETWORK_TYPE_HSPA
1619 || networkType == TelephonyManager.NETWORK_TYPE_HSPAP) {
Miguel Torroja1e84da82010-07-27 07:02:24 +02001620 type = AGPS_REF_LOCATION_TYPE_UMTS_CELLID;
Mike Lockwoodedc0f3872010-10-22 09:16:17 -04001621 } else {
Miguel Torroja1e84da82010-07-27 07:02:24 +02001622 type = AGPS_REF_LOCATION_TYPE_GSM_CELLID;
Mike Lockwoodedc0f3872010-10-22 09:16:17 -04001623 }
Miguel Torroja1e84da82010-07-27 07:02:24 +02001624 native_agps_set_ref_location_cellid(type, mcc, mnc,
1625 gsm_cell.getLac(), gsm_cell.getCid());
Mike Lockwoodedc0f3872010-10-22 09:16:17 -04001626 } else {
Miguel Torroja1e84da82010-07-27 07:02:24 +02001627 Log.e(TAG,"Error getting cell location info.");
Mike Lockwoodedc0f3872010-10-22 09:16:17 -04001628 }
Victoria Leased50d0c32012-10-29 13:16:17 -07001629 } else if (phoneType == TelephonyManager.PHONE_TYPE_CDMA) {
1630 Log.e(TAG, "CDMA not supported.");
Mike Lockwoodedc0f3872010-10-22 09:16:17 -04001631 }
Miguel Torroja1e84da82010-07-27 07:02:24 +02001632 }
Danke Xie22d1f9f2009-08-18 18:28:45 -04001633
Mike Lockwood98e48692010-04-07 16:32:51 -04001634 private void sendMessage(int message, int arg, Object obj) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001635 // hold a wake lock until this message is delivered
Jeff Brown028872f2012-08-25 13:07:01 -07001636 // note that this assumes the message will not be removed from the queue before
1637 // it is handled (otherwise the wake lock would be leaked).
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001638 mWakeLock.acquire();
1639 mHandler.obtainMessage(message, arg, 1, obj).sendToTarget();
Mike Lockwood98e48692010-04-07 16:32:51 -04001640 }
1641
Mike Lockwood62a8fc12010-03-22 14:23:26 -04001642 private final class ProviderHandler extends Handler {
Victoria Lease5cd731a2012-12-19 15:04:21 -08001643 public ProviderHandler(Looper looper) {
1644 super(looper, null, true /*async*/);
Jeff Brown028872f2012-08-25 13:07:01 -07001645 }
1646
Mike Lockwood62a8fc12010-03-22 14:23:26 -04001647 @Override
Mike Lockwood4a7b65e2010-10-25 16:35:55 -04001648 public void handleMessage(Message msg) {
Mike Lockwood98e48692010-04-07 16:32:51 -04001649 int message = msg.what;
1650 switch (message) {
Mike Lockwood62a8fc12010-03-22 14:23:26 -04001651 case ENABLE:
1652 if (msg.arg1 == 1) {
1653 handleEnable();
1654 } else {
1655 handleDisable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001656 }
Mike Lockwood62a8fc12010-03-22 14:23:26 -04001657 break;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001658 case SET_REQUEST:
1659 GpsRequest gpsRequest = (GpsRequest) msg.obj;
1660 handleSetRequest(gpsRequest.request, gpsRequest.source);
Mike Lockwood03ca2162010-04-01 08:10:09 -07001661 break;
Mike Lockwood62a8fc12010-03-22 14:23:26 -04001662 case UPDATE_NETWORK_STATE:
1663 handleUpdateNetworkState(msg.arg1, (NetworkInfo)msg.obj);
1664 break;
1665 case INJECT_NTP_TIME:
1666 handleInjectNtpTime();
1667 break;
1668 case DOWNLOAD_XTRA_DATA:
Mike Lockwood1a1cd3a2010-08-17 07:42:54 -04001669 if (mSupportsXtra) {
Mike Lockwood62a8fc12010-03-22 14:23:26 -04001670 handleDownloadXtraData();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001671 }
Mike Lockwood62a8fc12010-03-22 14:23:26 -04001672 break;
Kevin Tang40e1baf2012-01-10 14:32:44 -08001673 case INJECT_NTP_TIME_FINISHED:
1674 mInjectNtpTimePending = STATE_IDLE;
1675 break;
1676 case DOWNLOAD_XTRA_DATA_FINISHED:
1677 mDownloadXtraDataPending = STATE_IDLE;
1678 break;
Mike Lockwood62a8fc12010-03-22 14:23:26 -04001679 case UPDATE_LOCATION:
1680 handleUpdateLocation((Location)msg.obj);
1681 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001682 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001683 if (msg.arg2 == 1) {
1684 // wakelock was taken for this message, release it
1685 mWakeLock.release();
Mike Lockwood98e48692010-04-07 16:32:51 -04001686 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001687 }
Mike Lockwood62a8fc12010-03-22 14:23:26 -04001688 };
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001689
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001690 private final class NetworkLocationListener implements LocationListener {
1691 @Override
1692 public void onLocationChanged(Location location) {
1693 // this callback happens on mHandler looper
1694 if (LocationManager.NETWORK_PROVIDER.equals(location.getProvider())) {
1695 handleUpdateLocation(location);
1696 }
1697 }
1698 @Override
1699 public void onStatusChanged(String provider, int status, Bundle extras) { }
1700 @Override
1701 public void onProviderEnabled(String provider) { }
1702 @Override
1703 public void onProviderDisabled(String provider) { }
1704 }
1705
Kevin Tanga5fe6b22011-06-05 14:25:16 -07001706 private String getSelectedApn() {
1707 Uri uri = Uri.parse("content://telephony/carriers/preferapn");
1708 String apn = null;
1709
1710 Cursor cursor = mContext.getContentResolver().query(uri, new String[] {"apn"},
1711 null, null, Carriers.DEFAULT_SORT_ORDER);
1712
1713 if (null != cursor) {
1714 try {
1715 if (cursor.moveToFirst()) {
1716 apn = cursor.getString(0);
1717 }
1718 } finally {
1719 cursor.close();
1720 }
1721 }
1722 return apn;
1723 }
1724
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001725 @Override
1726 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1727 StringBuilder s = new StringBuilder();
1728 s.append(" mFixInterval=").append(mFixInterval).append("\n");
1729 s.append(" mEngineCapabilities=0x").append(Integer.toHexString(mEngineCapabilities)).append(" (");
1730 if (hasCapability(GPS_CAPABILITY_SCHEDULING)) s.append("SCHED ");
1731 if (hasCapability(GPS_CAPABILITY_MSB)) s.append("MSB ");
1732 if (hasCapability(GPS_CAPABILITY_MSA)) s.append("MSA ");
1733 if (hasCapability(GPS_CAPABILITY_SINGLE_SHOT)) s.append("SINGLE_SHOT ");
1734 if (hasCapability(GPS_CAPABILITY_ON_DEMAND_TIME)) s.append("ON_DEMAND_TIME ");
1735 s.append(")\n");
1736
1737 s.append(native_get_internal_state());
1738 pw.append(s);
1739 }
1740
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001741 // for GPS SV statistics
1742 private static final int MAX_SVS = 32;
1743 private static final int EPHEMERIS_MASK = 0;
1744 private static final int ALMANAC_MASK = 1;
1745 private static final int USED_FOR_FIX_MASK = 2;
1746
1747 // preallocated arrays, to avoid memory allocation in reportStatus()
1748 private int mSvs[] = new int[MAX_SVS];
1749 private float mSnrs[] = new float[MAX_SVS];
1750 private float mSvElevations[] = new float[MAX_SVS];
1751 private float mSvAzimuths[] = new float[MAX_SVS];
1752 private int mSvMasks[] = new int[3];
1753 private int mSvCount;
Mike Lockwoodb16e7802009-08-06 09:26:02 -04001754 // preallocated to avoid memory allocation in reportNmea()
1755 private byte[] mNmeaBuffer = new byte[120];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001756
1757 static { class_init_native(); }
1758 private static native void class_init_native();
1759 private static native boolean native_is_supported();
1760
1761 private native boolean native_init();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001762 private native void native_cleanup();
Mike Lockwood04598b62010-04-14 17:17:24 -04001763 private native boolean native_set_position_mode(int mode, int recurrence, int min_interval,
1764 int preferred_accuracy, int preferred_time);
1765 private native boolean native_start();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001766 private native boolean native_stop();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001767 private native void native_delete_aiding_data(int flags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001768 // returns number of SVs
1769 // mask[0] is ephemeris mask and mask[1] is almanac mask
1770 private native int native_read_sv_status(int[] svs, float[] snrs,
1771 float[] elevations, float[] azimuths, int[] masks);
Mike Lockwoodf602d362010-06-20 14:28:16 -07001772 private native int native_read_nmea(byte[] buffer, int bufferSize);
Mike Lockwoodd26ce0d2009-06-11 12:25:46 -04001773 private native void native_inject_location(double latitude, double longitude, float accuracy);
1774
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06001775 // XTRA Support
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001776 private native void native_inject_time(long time, long timeReference, int uncertainty);
1777 private native boolean native_supports_xtra();
1778 private native void native_inject_xtra_data(byte[] data, int length);
The Android Open Source Project10592532009-03-18 17:39:46 -07001779
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06001780 // DEBUG Support
1781 private native String native_get_internal_state();
1782
1783 // AGPS Support
Mike Lockwoode3635c92009-05-11 08:38:02 -04001784 private native void native_agps_data_conn_open(String apn);
1785 private native void native_agps_data_conn_closed();
1786 private native void native_agps_data_conn_failed();
Miguel Torroja1e84da82010-07-27 07:02:24 +02001787 private native void native_agps_ni_message(byte [] msg, int length);
Mike Lockwooda9e54612009-06-19 14:54:42 -04001788 private native void native_set_agps_server(int type, String hostname, int port);
Danke Xie22d1f9f2009-08-18 18:28:45 -04001789
1790 // Network-initiated (NI) Support
1791 private native void native_send_ni_response(int notificationId, int userResponse);
Miguel Torroja1e84da82010-07-27 07:02:24 +02001792
1793 // AGPS ril suport
1794 private native void native_agps_set_ref_location_cellid(int type, int mcc, int mnc,
1795 int lac, int cid);
1796 private native void native_agps_set_id(int type, String setid);
Mike Lockwood50130bb2010-10-11 06:22:50 -04001797
1798 private native void native_update_network_state(boolean connected, int type,
Kevin Tanga5fe6b22011-06-05 14:25:16 -07001799 boolean roaming, boolean available, String extraInfo, String defaultAPN);
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -07001800
1801 // Hardware Geofence support.
1802 private static native boolean native_is_geofence_supported();
1803 private static native boolean native_add_geofence(int geofenceId, double latitude,
1804 double longitude, double radius, int lastTransition,int monitorTransitions,
1805 int notificationResponsivenes, int unknownTimer);
1806 private static native boolean native_remove_geofence(int geofenceId);
1807 private static native boolean native_resume_geofence(int geofenceId, int transitions);
1808 private static native boolean native_pause_geofence(int geofenceId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001809}