OSDN Git Service

DO NOT MERGE - SUPL ES Extension - Safer Init and Not After Boot
[android-x86/frameworks-base.git] / services / core / java / com / android / server / location / GnssLocationProvider.java
1 /*
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
17 package com.android.server.location;
18
19 import com.android.internal.app.IAppOpsService;
20 import com.android.internal.app.IBatteryStats;
21 import com.android.internal.location.GpsNetInitiatedHandler;
22 import com.android.internal.location.GpsNetInitiatedHandler.GpsNiNotification;
23 import com.android.internal.location.ProviderProperties;
24 import com.android.internal.location.ProviderRequest;
25
26 import android.app.AlarmManager;
27 import android.app.AppOpsManager;
28 import android.app.PendingIntent;
29 import android.content.BroadcastReceiver;
30 import android.content.Context;
31 import android.content.Intent;
32 import android.content.IntentFilter;
33 import android.database.Cursor;
34 import android.hardware.location.GeofenceHardware;
35 import android.hardware.location.GeofenceHardwareImpl;
36 import android.location.Criteria;
37 import android.location.FusedBatchOptions;
38 import android.location.GnssStatus;
39 import android.location.IGnssStatusListener;
40 import android.location.IGnssStatusProvider;
41 import android.location.GnssMeasurementsEvent;
42 import android.location.GnssNavigationMessage;
43 import android.location.IGpsGeofenceHardware;
44 import android.location.ILocationManager;
45 import android.location.INetInitiatedListener;
46 import android.location.Location;
47 import android.location.LocationListener;
48 import android.location.LocationManager;
49 import android.location.LocationProvider;
50 import android.location.LocationRequest;
51 import android.net.ConnectivityManager;
52 import android.net.Network;
53 import android.net.NetworkCapabilities;
54 import android.net.NetworkInfo;
55 import android.net.NetworkRequest;
56 import android.net.Uri;
57 import android.os.AsyncTask;
58 import android.os.BatteryStats;
59 import android.os.Binder;
60 import android.os.Bundle;
61 import android.os.Handler;
62 import android.os.Looper;
63 import android.os.Message;
64 import android.os.PowerManager;
65 import android.os.RemoteException;
66 import android.os.ServiceManager;
67 import android.os.SystemClock;
68 import android.os.SystemProperties;
69 import android.os.UserHandle;
70 import android.os.WorkSource;
71 import android.provider.Settings;
72 import android.provider.Telephony.Carriers;
73 import android.provider.Telephony.Sms.Intents;
74 import android.telephony.SmsMessage;
75 import android.telephony.SubscriptionManager;
76 import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
77 import android.telephony.TelephonyManager;
78 import android.telephony.gsm.GsmCellLocation;
79 import android.text.TextUtils;
80 import android.util.Log;
81 import android.util.NtpTrustedTime;
82
83 import java.io.ByteArrayOutputStream;
84 import java.io.File;
85 import java.io.FileDescriptor;
86 import java.io.FileInputStream;
87 import java.io.IOException;
88 import java.io.PrintWriter;
89 import java.io.StringReader;
90 import java.net.InetAddress;
91 import java.net.UnknownHostException;
92 import java.util.Arrays;
93 import java.util.Date;
94 import java.util.Map.Entry;
95 import java.util.Properties;
96
97 import libcore.io.IoUtils;
98
99 /**
100  * A GPS implementation of LocationProvider used by LocationManager.
101  *
102  * {@hide}
103  */
104 public class GnssLocationProvider implements LocationProviderInterface {
105
106     private static final String TAG = "GnssLocationProvider";
107
108     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
109     private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
110
111     private static final ProviderProperties PROPERTIES = new ProviderProperties(
112             true, true, false, false, true, true, true,
113             Criteria.POWER_HIGH, Criteria.ACCURACY_FINE);
114
115     // these need to match GpsPositionMode enum in gps.h
116     private static final int GPS_POSITION_MODE_STANDALONE = 0;
117     private static final int GPS_POSITION_MODE_MS_BASED = 1;
118     private static final int GPS_POSITION_MODE_MS_ASSISTED = 2;
119
120     // these need to match GpsPositionRecurrence enum in gps.h
121     private static final int GPS_POSITION_RECURRENCE_PERIODIC = 0;
122     private static final int GPS_POSITION_RECURRENCE_SINGLE = 1;
123
124     // these need to match GpsStatusValue defines in gps.h
125     private static final int GPS_STATUS_NONE = 0;
126     private static final int GPS_STATUS_SESSION_BEGIN = 1;
127     private static final int GPS_STATUS_SESSION_END = 2;
128     private static final int GPS_STATUS_ENGINE_ON = 3;
129     private static final int GPS_STATUS_ENGINE_OFF = 4;
130
131     // these need to match GpsApgsStatusValue defines in gps.h
132     /** AGPS status event values. */
133     private static final int GPS_REQUEST_AGPS_DATA_CONN = 1;
134     private static final int GPS_RELEASE_AGPS_DATA_CONN = 2;
135     private static final int GPS_AGPS_DATA_CONNECTED = 3;
136     private static final int GPS_AGPS_DATA_CONN_DONE = 4;
137     private static final int GPS_AGPS_DATA_CONN_FAILED = 5;
138
139     // these need to match GpsLocationFlags enum in gps.h
140     private static final int LOCATION_INVALID = 0;
141     private static final int LOCATION_HAS_LAT_LONG = 1;
142     private static final int LOCATION_HAS_ALTITUDE = 2;
143     private static final int LOCATION_HAS_SPEED = 4;
144     private static final int LOCATION_HAS_BEARING = 8;
145     private static final int LOCATION_HAS_ACCURACY = 16;
146
147     // IMPORTANT - the GPS_DELETE_* symbols here must match constants in gps.h
148     private static final int GPS_DELETE_EPHEMERIS = 0x0001;
149     private static final int GPS_DELETE_ALMANAC = 0x0002;
150     private static final int GPS_DELETE_POSITION = 0x0004;
151     private static final int GPS_DELETE_TIME = 0x0008;
152     private static final int GPS_DELETE_IONO = 0x0010;
153     private static final int GPS_DELETE_UTC = 0x0020;
154     private static final int GPS_DELETE_HEALTH = 0x0040;
155     private static final int GPS_DELETE_SVDIR = 0x0080;
156     private static final int GPS_DELETE_SVSTEER = 0x0100;
157     private static final int GPS_DELETE_SADATA = 0x0200;
158     private static final int GPS_DELETE_RTI = 0x0400;
159     private static final int GPS_DELETE_CELLDB_INFO = 0x8000;
160     private static final int GPS_DELETE_ALL = 0xFFFF;
161
162     // The GPS_CAPABILITY_* flags must match the values in gps.h
163     private static final int GPS_CAPABILITY_SCHEDULING = 0x0000001;
164     private static final int GPS_CAPABILITY_MSB = 0x0000002;
165     private static final int GPS_CAPABILITY_MSA = 0x0000004;
166     private static final int GPS_CAPABILITY_SINGLE_SHOT = 0x0000008;
167     private static final int GPS_CAPABILITY_ON_DEMAND_TIME = 0x0000010;
168     private static final int GPS_CAPABILITY_GEOFENCING = 0x0000020;
169     private static final int GPS_CAPABILITY_MEASUREMENTS = 0x0000040;
170     private static final int GPS_CAPABILITY_NAV_MESSAGES = 0x0000080;
171
172     // The AGPS SUPL mode
173     private static final int AGPS_SUPL_MODE_MSA = 0x02;
174     private static final int AGPS_SUPL_MODE_MSB = 0x01;
175
176     // these need to match AGpsType enum in gps.h
177     private static final int AGPS_TYPE_SUPL = 1;
178     private static final int AGPS_TYPE_C2K = 2;
179
180     // these must match the definitions in gps.h
181     private static final int APN_INVALID = 0;
182     private static final int APN_IPV4 = 1;
183     private static final int APN_IPV6 = 2;
184     private static final int APN_IPV4V6 = 3;
185
186     // for mAGpsDataConnectionState
187     private static final int AGPS_DATA_CONNECTION_CLOSED = 0;
188     private static final int AGPS_DATA_CONNECTION_OPENING = 1;
189     private static final int AGPS_DATA_CONNECTION_OPEN = 2;
190
191     // Handler messages
192     private static final int CHECK_LOCATION = 1;
193     private static final int ENABLE = 2;
194     private static final int SET_REQUEST = 3;
195     private static final int UPDATE_NETWORK_STATE = 4;
196     private static final int INJECT_NTP_TIME = 5;
197     private static final int DOWNLOAD_XTRA_DATA = 6;
198     private static final int UPDATE_LOCATION = 7;
199     private static final int ADD_LISTENER = 8;
200     private static final int REMOVE_LISTENER = 9;
201     private static final int INJECT_NTP_TIME_FINISHED = 10;
202     private static final int DOWNLOAD_XTRA_DATA_FINISHED = 11;
203     private static final int SUBSCRIPTION_OR_SIM_CHANGED = 12;
204     private static final int INITIALIZE_HANDLER = 13;
205     private static final int REQUEST_SUPL_CONNECTION = 14;
206     private static final int RELEASE_SUPL_CONNECTION = 15;
207
208     // Request setid
209     private static final int AGPS_RIL_REQUEST_SETID_IMSI = 1;
210     private static final int AGPS_RIL_REQUEST_SETID_MSISDN = 2;
211
212     // Request ref location
213     private static final int AGPS_RIL_REQUEST_REFLOC_CELLID = 1;
214     private static final int AGPS_RIL_REQUEST_REFLOC_MAC = 2;
215
216     // ref. location info
217     private static final int AGPS_REF_LOCATION_TYPE_GSM_CELLID = 1;
218     private static final int AGPS_REF_LOCATION_TYPE_UMTS_CELLID = 2;
219     private static final int AGPS_REG_LOCATION_TYPE_MAC        = 3;
220
221     // set id info
222     private static final int AGPS_SETID_TYPE_NONE = 0;
223     private static final int AGPS_SETID_TYPE_IMSI = 1;
224     private static final int AGPS_SETID_TYPE_MSISDN = 2;
225
226     private static final String PROPERTIES_FILE_PREFIX = "/etc/gps";
227     private static final String PROPERTIES_FILE_SUFFIX = ".conf";
228     private static final String DEFAULT_PROPERTIES_FILE = PROPERTIES_FILE_PREFIX + PROPERTIES_FILE_SUFFIX;
229
230     private static final int GPS_GEOFENCE_UNAVAILABLE = 1<<0L;
231     private static final int GPS_GEOFENCE_AVAILABLE = 1<<1L;
232
233     // GPS Geofence errors. Should match gps.h constants.
234     private static final int GPS_GEOFENCE_OPERATION_SUCCESS = 0;
235     private static final int GPS_GEOFENCE_ERROR_TOO_MANY_GEOFENCES = 100;
236     private static final int GPS_GEOFENCE_ERROR_ID_EXISTS  = -101;
237     private static final int GPS_GEOFENCE_ERROR_ID_UNKNOWN = -102;
238     private static final int GPS_GEOFENCE_ERROR_INVALID_TRANSITION = -103;
239     private static final int GPS_GEOFENCE_ERROR_GENERIC = -149;
240
241     // TCP/IP constants.
242     // Valid TCP/UDP port range is (0, 65535].
243     private static final int TCP_MIN_PORT = 0;
244     private static final int TCP_MAX_PORT = 0xffff;
245
246     // Value of batterySaverGpsMode such that GPS isn't affected by battery saver mode.
247     private static final int BATTERY_SAVER_MODE_NO_CHANGE = 0;
248     // Value of batterySaverGpsMode such that GPS is disabled when battery saver mode
249     // is enabled and the screen is off.
250     private static final int BATTERY_SAVER_MODE_DISABLED_WHEN_SCREEN_OFF = 1;
251     // Secure setting for GPS behavior when battery saver mode is on.
252     private static final String BATTERY_SAVER_GPS_MODE = "batterySaverGpsMode";
253
254     /** simpler wrapper for ProviderRequest + Worksource */
255     private static class GpsRequest {
256         public ProviderRequest request;
257         public WorkSource source;
258         public GpsRequest(ProviderRequest request, WorkSource source) {
259             this.request = request;
260             this.source = source;
261         }
262     }
263
264     private Object mLock = new Object();
265
266     private int mLocationFlags = LOCATION_INVALID;
267
268     // current status
269     private int mStatus = LocationProvider.TEMPORARILY_UNAVAILABLE;
270
271     // time for last status update
272     private long mStatusUpdateTime = SystemClock.elapsedRealtime();
273
274     // turn off GPS fix icon if we haven't received a fix in 10 seconds
275     private static final long RECENT_FIX_TIMEOUT = 10 * 1000;
276
277     // stop trying if we do not receive a fix within 60 seconds
278     private static final int NO_FIX_TIMEOUT = 60 * 1000;
279
280     // if the fix interval is below this we leave GPS on,
281     // if above then we cycle the GPS driver.
282     // Typical hot TTTF is ~5 seconds, so 10 seconds seems sane.
283     private static final int GPS_POLLING_THRESHOLD_INTERVAL = 10 * 1000;
284
285     // how often to request NTP time, in milliseconds
286     // current setting 24 hours
287     private static final long NTP_INTERVAL = 24*60*60*1000;
288     // how long to wait if we have a network error in NTP or XTRA downloading
289     // the initial value of the exponential backoff
290     // current setting - 5 minutes
291     private static final long RETRY_INTERVAL = 5*60*1000;
292     // how long to wait if we have a network error in NTP or XTRA downloading
293     // the max value of the exponential backoff
294     // current setting - 4 hours
295     private static final long MAX_RETRY_INTERVAL = 4*60*60*1000;
296
297     private BackOff mNtpBackOff = new BackOff(RETRY_INTERVAL, MAX_RETRY_INTERVAL);
298     private BackOff mXtraBackOff = new BackOff(RETRY_INTERVAL, MAX_RETRY_INTERVAL);
299
300     // true if we are enabled, protected by this
301     private boolean mEnabled;
302
303     // states for injecting ntp and downloading xtra data
304     private static final int STATE_PENDING_NETWORK = 0;
305     private static final int STATE_DOWNLOADING = 1;
306     private static final int STATE_IDLE = 2;
307
308     // flags to trigger NTP or XTRA data download when network becomes available
309     // initialized to true so we do NTP and XTRA when the network comes up after booting
310     private int mInjectNtpTimePending = STATE_PENDING_NETWORK;
311     private int mDownloadXtraDataPending = STATE_PENDING_NETWORK;
312
313     // set to true if the GPS engine requested on-demand NTP time requests
314     private boolean mOnDemandTimeInjection;
315
316     // true if GPS is navigating
317     private boolean mNavigating;
318
319     // true if GPS engine is on
320     private boolean mEngineOn;
321
322     // requested frequency of fixes, in milliseconds
323     private int mFixInterval = 1000;
324
325     // true if we started navigation
326     private boolean mStarted;
327
328     // true if single shot request is in progress
329     private boolean mSingleShot;
330
331     // capabilities of the GPS engine
332     private int mEngineCapabilities;
333
334     // true if XTRA is supported
335     private boolean mSupportsXtra;
336
337     // for calculating time to first fix
338     private long mFixRequestTime = 0;
339     // time to first fix for most recent session
340     private int mTimeToFirstFix = 0;
341     // time we received our last fix
342     private long mLastFixTime;
343
344     private int mPositionMode;
345
346     // Current request from underlying location clients.
347     private ProviderRequest mProviderRequest = null;
348     // Current list of underlying location clients.
349     private WorkSource mWorkSource = null;
350     // True if gps should be disabled (used to support battery saver mode in settings).
351     private boolean mDisableGps = false;
352
353     /**
354      * Properties loaded from PROPERTIES_FILE.
355      * It must be accessed only inside {@link #mHandler}.
356      */
357     private Properties mProperties;
358
359     private String mSuplServerHost;
360     private int mSuplServerPort = TCP_MIN_PORT;
361     private String mC2KServerHost;
362     private int mC2KServerPort;
363     private boolean mSuplEsEnabled = false;
364
365     private final Context mContext;
366     private final NtpTrustedTime mNtpTime;
367     private final ILocationManager mILocationManager;
368     private Location mLocation = new Location(LocationManager.GPS_PROVIDER);
369     private Bundle mLocationExtras = new Bundle();
370     private final GnssStatusListenerHelper mListenerHelper;
371     private final GnssMeasurementsProvider mGnssMeasurementsProvider;
372     private final GnssNavigationMessageProvider mGnssNavigationMessageProvider;
373
374     // Handler for processing events
375     private Handler mHandler;
376
377     /** It must be accessed only inside {@link #mHandler}. */
378     private int mAGpsDataConnectionState;
379     /** It must be accessed only inside {@link #mHandler}. */
380     private InetAddress mAGpsDataConnectionIpAddr;
381
382     private final ConnectivityManager mConnMgr;
383     private final GpsNetInitiatedHandler mNIHandler;
384
385     // Wakelocks
386     private final static String WAKELOCK_KEY = "GnssLocationProvider";
387     private final PowerManager.WakeLock mWakeLock;
388
389     // Alarms
390     private final static String ALARM_WAKEUP = "com.android.internal.location.ALARM_WAKEUP";
391     private final static String ALARM_TIMEOUT = "com.android.internal.location.ALARM_TIMEOUT";
392
393     // SIM/Carrier info.
394     private final static String SIM_STATE_CHANGED = "android.intent.action.SIM_STATE_CHANGED";
395
396     // Persist property for LPP_PROFILE
397     private final static String LPP_PROFILE = "persist.sys.gps.lpp";
398
399     // VZW PLMN info
400     private static final String[] VzwMccMncList = {"311480", "310004", "20404"};
401     // corresponding GID1 value, empty string means ignore gid1 match.
402     private static final String[] VzwGid1List = {"", "", "BAE0000000000000"};
403
404
405     private final PowerManager mPowerManager;
406     private final AlarmManager mAlarmManager;
407     private final PendingIntent mWakeupIntent;
408     private final PendingIntent mTimeoutIntent;
409
410     private final IAppOpsService mAppOpsService;
411     private final IBatteryStats mBatteryStats;
412
413     // only modified on handler thread
414     private WorkSource mClientSource = new WorkSource();
415
416     private GeofenceHardwareImpl mGeofenceHardwareImpl;
417
418     private int mYearOfHardware = 0;
419
420     // Set lower than the current ITAR limit of 600m/s to allow this to trigger even if GPS HAL
421     // stops output right at 600m/s, depriving this of the information of a device that reaches
422     // greater than 600m/s, and higher than the speed of sound to avoid impacting most use cases.
423     private static final float ITAR_SPEED_LIMIT_METERS_PER_SECOND = 400.0F;
424     private boolean mItarSpeedLimitExceeded = false;
425
426     private final IGnssStatusProvider mGnssStatusProvider = new IGnssStatusProvider.Stub() {
427         @Override
428         public void registerGnssStatusCallback(IGnssStatusListener callback) {
429             mListenerHelper.addListener(callback);
430         }
431
432         @Override
433         public void unregisterGnssStatusCallback(IGnssStatusListener callback) {
434             mListenerHelper.removeListener(callback);
435         }
436     };
437
438     public IGnssStatusProvider getGnssStatusProvider() {
439         return mGnssStatusProvider;
440     }
441
442     public IGpsGeofenceHardware getGpsGeofenceProxy() {
443         return mGpsGeofenceBinder;
444     }
445
446     public GnssMeasurementsProvider getGnssMeasurementsProvider() {
447         return mGnssMeasurementsProvider;
448     }
449
450     public GnssNavigationMessageProvider getGnssNavigationMessageProvider() {
451         return mGnssNavigationMessageProvider;
452     }
453
454     /**
455      * Callback used to listen for data connectivity changes.
456      */
457     private final ConnectivityManager.NetworkCallback mNetworkConnectivityCallback =
458             new ConnectivityManager.NetworkCallback() {
459         @Override
460         public void onAvailable(Network network) {
461             if (mInjectNtpTimePending == STATE_PENDING_NETWORK) {
462                 requestUtcTime();
463             }
464             if (mDownloadXtraDataPending == STATE_PENDING_NETWORK) {
465                 xtraDownloadRequest();
466             }
467         }
468     };
469
470     /**
471      * Callback used to listen for availability of a requested SUPL connection.
472      * It is kept as a separate instance from {@link #mNetworkConnectivityCallback} to be able to
473      * manage the registration/un-registration lifetimes separate.
474      */
475     private final ConnectivityManager.NetworkCallback mSuplConnectivityCallback =
476             new ConnectivityManager.NetworkCallback() {
477         @Override
478         public void onAvailable(Network network) {
479             sendMessage(UPDATE_NETWORK_STATE, 0 /*arg*/, network);
480         }
481
482         @Override
483         public void onLost(Network network) {
484             releaseSuplConnection(GPS_RELEASE_AGPS_DATA_CONN);
485         }
486
487         @Override
488         public void onUnavailable() {
489             // timeout, it was not possible to establish the required connection
490             releaseSuplConnection(GPS_AGPS_DATA_CONN_FAILED);
491         }
492     };
493
494     private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
495         @Override public void onReceive(Context context, Intent intent) {
496             String action = intent.getAction();
497             if (DEBUG) Log.d(TAG, "receive broadcast intent, action: " + action);
498             if (action == null) {
499                 return;
500             }
501
502             if (action.equals(ALARM_WAKEUP)) {
503                 startNavigating(false);
504             } else if (action.equals(ALARM_TIMEOUT)) {
505                 hibernate();
506             } else if (action.equals(Intents.DATA_SMS_RECEIVED_ACTION)) {
507                 checkSmsSuplInit(intent);
508             } else if (action.equals(Intents.WAP_PUSH_RECEIVED_ACTION)) {
509                 checkWapSuplInit(intent);
510             } else if (PowerManager.ACTION_POWER_SAVE_MODE_CHANGED.equals(action)
511                     || PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED.equals(action)
512                     || Intent.ACTION_SCREEN_OFF.equals(action)
513                     || Intent.ACTION_SCREEN_ON.equals(action)) {
514                 updateLowPowerMode();
515             } else if (action.equals(SIM_STATE_CHANGED)) {
516                 subscriptionOrSimChanged(context);
517             }
518         }
519     };
520
521     private final OnSubscriptionsChangedListener mOnSubscriptionsChangedListener =
522             new OnSubscriptionsChangedListener() {
523         @Override
524         public void onSubscriptionsChanged() {
525             sendMessage(SUBSCRIPTION_OR_SIM_CHANGED, 0, null);
526         }
527     };
528
529     private final boolean isVerizon(String mccMnc, String imsi, String groupId) {
530         if (DEBUG) Log.d(TAG, "simOperator: " + mccMnc);
531         if (!TextUtils.isEmpty(mccMnc) || !TextUtils.isEmpty(imsi)) {
532             for (int i = 0; i < VzwMccMncList.length; i++) {
533                 if ((!TextUtils.isEmpty(mccMnc) && mccMnc.equals(VzwMccMncList[i])) ||
534                         (!TextUtils.isEmpty(imsi) && imsi.startsWith(VzwMccMncList[i]))) {
535                     // check gid too if needed
536                     if (TextUtils.isEmpty(VzwGid1List[i]) || VzwGid1List[i].equals(groupId)) {
537                         if (DEBUG) Log.d(TAG, "Verizon UICC");
538                         return true;
539                     }
540                 }
541             }
542         }
543         return false;
544     }
545
546     private void subscriptionOrSimChanged(Context context) {
547         if (DEBUG) Log.d(TAG, "received SIM related action: ");
548         TelephonyManager phone = (TelephonyManager)
549                 mContext.getSystemService(Context.TELEPHONY_SERVICE);
550         String mccMnc = phone.getSimOperator();
551         String imsi = phone.getSubscriberId();
552         String groupId = phone.getGroupIdLevel1();
553         if (!TextUtils.isEmpty(mccMnc)) {
554             if (DEBUG) Log.d(TAG, "SIM MCC/MNC is available: " + mccMnc);
555             synchronized (mLock) {
556                 if (isVerizon(mccMnc, imsi, groupId)) {
557                         // load current properties for carrier VZW
558                         loadPropertiesFromResource(context, mProperties);
559                         String lpp_profile = mProperties.getProperty("LPP_PROFILE");
560                         // set the persist property LPP_PROFILE for VZW
561                         SystemProperties.set(LPP_PROFILE, lpp_profile);
562                 } else {
563                         // reset the persist property for Non VZW
564                         SystemProperties.set(LPP_PROFILE, "");
565                 }
566                 reloadGpsProperties(context, mProperties);
567                 mNIHandler.setSuplEsEnabled(mSuplEsEnabled);
568             }
569         } else {
570             if (DEBUG) Log.d(TAG, "SIM MCC/MNC is still not available");
571         }
572     }
573
574     private void checkSmsSuplInit(Intent intent) {
575         SmsMessage[] messages = Intents.getMessagesFromIntent(intent);
576         if (messages == null) {
577             Log.e(TAG, "Message does not exist in the intent.");
578             return;
579         }
580
581         for (SmsMessage message : messages) {
582             if (message != null && message.mWrappedSmsMessage != null) {
583                 byte[] suplInit = message.getUserData();
584                 if (suplInit != null) {
585                     native_agps_ni_message(suplInit, suplInit.length);
586                 }
587             }
588         }
589     }
590
591     private void checkWapSuplInit(Intent intent) {
592         byte[] suplInit = intent.getByteArrayExtra("data");
593         if (suplInit == null) {
594             return;
595         }
596         native_agps_ni_message(suplInit,suplInit.length);
597     }
598
599     private void updateLowPowerMode() {
600         // Disable GPS if we are in device idle mode.
601         boolean disableGps = mPowerManager.isDeviceIdleMode();
602         switch (Settings.Secure.getInt(mContext.getContentResolver(), BATTERY_SAVER_GPS_MODE,
603                 BATTERY_SAVER_MODE_DISABLED_WHEN_SCREEN_OFF)) {
604             case BATTERY_SAVER_MODE_DISABLED_WHEN_SCREEN_OFF:
605                 // If we are in battery saver mode and the screen is off, disable GPS.
606                 disableGps |= mPowerManager.isPowerSaveMode() && !mPowerManager.isInteractive();
607                 break;
608         }
609         if (disableGps != mDisableGps) {
610             mDisableGps = disableGps;
611             updateRequirements();
612         }
613     }
614
615     public static boolean isSupported() {
616         return native_is_supported();
617     }
618
619     private void reloadGpsProperties(Context context, Properties properties) {
620         if (DEBUG) Log.d(TAG, "Reset GPS properties, previous size = " + properties.size());
621         loadPropertiesFromResource(context, properties);
622
623         boolean isPropertiesLoadedFromFile = false;
624         final String gpsHardware = SystemProperties.get("ro.hardware.gps");
625
626         if (!TextUtils.isEmpty(gpsHardware)) {
627             final String propFilename =
628                     PROPERTIES_FILE_PREFIX + "." + gpsHardware + PROPERTIES_FILE_SUFFIX;
629             isPropertiesLoadedFromFile =
630                     loadPropertiesFromFile(propFilename, properties);
631         }
632         if (!isPropertiesLoadedFromFile) {
633             loadPropertiesFromFile(DEFAULT_PROPERTIES_FILE, properties);
634         }
635         if (DEBUG) Log.d(TAG, "GPS properties reloaded, size = " + properties.size());
636         String lpp_prof = SystemProperties.get(LPP_PROFILE);
637         if (!TextUtils.isEmpty(lpp_prof)) {
638                 // override default value of this if lpp_prof is not empty
639                 properties.setProperty("LPP_PROFILE", lpp_prof);
640         }
641         // TODO: we should get rid of C2K specific setting.
642         setSuplHostPort(properties.getProperty("SUPL_HOST"),
643                         properties.getProperty("SUPL_PORT"));
644         mC2KServerHost = properties.getProperty("C2K_HOST");
645         String portString = properties.getProperty("C2K_PORT");
646         if (mC2KServerHost != null && portString != null) {
647             try {
648                 mC2KServerPort = Integer.parseInt(portString);
649             } catch (NumberFormatException e) {
650                 Log.e(TAG, "unable to parse C2K_PORT: " + portString);
651             }
652         }
653
654         if (native_is_gnss_configuration_supported()) {
655             try {
656                 // Convert properties to string contents and send it to HAL.
657                 ByteArrayOutputStream baos = new ByteArrayOutputStream(4096);
658                 properties.store(baos, null);
659                 native_configuration_update(baos.toString());
660                 if (DEBUG) Log.d(TAG, "final config = " + baos.toString());
661             } catch (IOException ex) {
662                 Log.e(TAG, "failed to dump properties contents");
663             }
664         } else if (DEBUG) {
665             Log.d(TAG, "Skipped configuration update because GNSS configuration in GPS HAL is not"
666                     + " supported");
667         }
668
669         // SUPL_ES configuration.
670         String suplESProperty = mProperties.getProperty("SUPL_ES");
671         if (suplESProperty != null) {
672             try {
673                 mSuplEsEnabled = (Integer.parseInt(suplESProperty) == 1);
674             } catch (NumberFormatException e) {
675                 Log.e(TAG, "unable to parse SUPL_ES: " + suplESProperty);
676             }
677         }
678     }
679
680     private void loadPropertiesFromResource(Context context,
681                                             Properties properties) {
682         String[] configValues = context.getResources().getStringArray(
683                 com.android.internal.R.array.config_gpsParameters);
684         for (String item : configValues) {
685             if (DEBUG) Log.d(TAG, "GpsParamsResource: " + item);
686             // We need to support "KEY =", but not "=VALUE".
687             String[] split = item.split("=");
688             if (split.length == 2) {
689                 properties.setProperty(split[0].trim().toUpperCase(), split[1]);
690             } else {
691                 Log.w(TAG, "malformed contents: " + item);
692             }
693         }
694     }
695
696     private boolean loadPropertiesFromFile(String filename,
697                                            Properties properties) {
698         try {
699             File file = new File(filename);
700             FileInputStream stream = null;
701             try {
702                 stream = new FileInputStream(file);
703                 properties.load(stream);
704             } finally {
705                 IoUtils.closeQuietly(stream);
706             }
707
708         } catch (IOException e) {
709             Log.w(TAG, "Could not open GPS configuration file " + filename);
710             return false;
711         }
712         return true;
713     }
714
715     public GnssLocationProvider(Context context, ILocationManager ilocationManager,
716             Looper looper) {
717         mContext = context;
718         mNtpTime = NtpTrustedTime.getInstance(context);
719         mILocationManager = ilocationManager;
720
721         mLocation.setExtras(mLocationExtras);
722
723         // Create a wake lock
724         mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
725         mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
726         mWakeLock.setReferenceCounted(true);
727
728         mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
729         mWakeupIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_WAKEUP), 0);
730         mTimeoutIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_TIMEOUT), 0);
731
732         mConnMgr = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
733
734         // App ops service to keep track of who is accessing the GPS
735         mAppOpsService = IAppOpsService.Stub.asInterface(ServiceManager.getService(
736                 Context.APP_OPS_SERVICE));
737
738         // Battery statistics service to be notified when GPS turns on or off
739         mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService(
740                 BatteryStats.SERVICE_NAME));
741
742         // Construct internal handler
743         mHandler = new ProviderHandler(looper);
744
745         // Load GPS configuration and register listeners in the background:
746         // some operations, such as opening files and registering broadcast receivers, can take a
747         // relative long time, so the ctor() is kept to create objects needed by this instance,
748         // while IO initialization and registration is delegated to our internal handler
749         // this approach is just fine because events are posted to our handler anyway
750         mProperties = new Properties();
751         // Create a GPS net-initiated handler (also needed by handleInitialize)
752         mNIHandler = new GpsNetInitiatedHandler(context,
753                                                 mNetInitiatedListener,
754                                                 mSuplEsEnabled);
755         sendMessage(INITIALIZE_HANDLER, 0, null);
756
757         mListenerHelper = new GnssStatusListenerHelper(mHandler) {
758             @Override
759             protected boolean isAvailableInPlatform() {
760                 return isSupported();
761             }
762
763             @Override
764             protected boolean isGpsEnabled() {
765                 return isEnabled();
766             }
767         };
768
769         mGnssMeasurementsProvider = new GnssMeasurementsProvider(mHandler) {
770             @Override
771             public boolean isAvailableInPlatform() {
772                 return native_is_measurement_supported();
773             }
774
775             @Override
776             protected boolean registerWithService() {
777                 return native_start_measurement_collection();
778             }
779
780             @Override
781             protected void unregisterFromService() {
782                 native_stop_measurement_collection();
783             }
784
785             @Override
786             protected boolean isGpsEnabled() {
787                 return isEnabled();
788             }
789         };
790
791         mGnssNavigationMessageProvider = new GnssNavigationMessageProvider(mHandler) {
792             @Override
793             protected boolean isAvailableInPlatform() {
794                 return native_is_navigation_message_supported();
795             }
796
797             @Override
798             protected boolean registerWithService() {
799                 return native_start_navigation_message_collection();
800             }
801
802             @Override
803             protected void unregisterFromService() {
804                 native_stop_navigation_message_collection();
805             }
806
807             @Override
808             protected boolean isGpsEnabled() {
809                 return isEnabled();
810             }
811         };
812     }
813
814     /**
815      * Returns the name of this provider.
816      */
817     @Override
818     public String getName() {
819         return LocationManager.GPS_PROVIDER;
820     }
821
822     @Override
823     public ProviderProperties getProperties() {
824         return PROPERTIES;
825     }
826
827     private void handleUpdateNetworkState(Network network) {
828         // retrieve NetworkInfo for this UID
829         NetworkInfo info = mConnMgr.getNetworkInfo(network);
830         if (info == null) {
831             return;
832         }
833
834         boolean isConnected = info.isConnected();
835         if (DEBUG) {
836             String message = String.format(
837                     "UpdateNetworkState, state=%s, connected=%s, info=%s, capabilities=%S",
838                     agpsDataConnStateAsString(),
839                     isConnected,
840                     info,
841                     mConnMgr.getNetworkCapabilities(network));
842             Log.d(TAG, message);
843         }
844
845         if (native_is_agps_ril_supported()) {
846             boolean dataEnabled = TelephonyManager.getDefault().getDataEnabled();
847             boolean networkAvailable = info.isAvailable() && dataEnabled;
848             String defaultApn = getSelectedApn();
849             if (defaultApn == null) {
850                 defaultApn = "dummy-apn";
851             }
852
853             native_update_network_state(
854                     isConnected,
855                     info.getType(),
856                     info.isRoaming(),
857                     networkAvailable,
858                     info.getExtraInfo(),
859                     defaultApn);
860         } else if (DEBUG) {
861             Log.d(TAG, "Skipped network state update because GPS HAL AGPS-RIL is not  supported");
862         }
863
864         if (mAGpsDataConnectionState == AGPS_DATA_CONNECTION_OPENING) {
865             if (isConnected) {
866                 String apnName = info.getExtraInfo();
867                 if (apnName == null) {
868                     // assign a dummy value in the case of C2K as otherwise we will have a runtime
869                     // exception in the following call to native_agps_data_conn_open
870                     apnName = "dummy-apn";
871                 }
872                 int apnIpType = getApnIpType(apnName);
873                 setRouting();
874                 if (DEBUG) {
875                     String message = String.format(
876                             "native_agps_data_conn_open: mAgpsApn=%s, mApnIpType=%s",
877                             apnName,
878                             apnIpType);
879                     Log.d(TAG, message);
880                 }
881                 native_agps_data_conn_open(apnName, apnIpType);
882                 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPEN;
883             } else {
884                 handleReleaseSuplConnection(GPS_AGPS_DATA_CONN_FAILED);
885             }
886         }
887     }
888
889     private void handleRequestSuplConnection(InetAddress address) {
890         if (DEBUG) {
891             String message = String.format(
892                     "requestSuplConnection, state=%s, address=%s",
893                     agpsDataConnStateAsString(),
894                     address);
895             Log.d(TAG, message);
896         }
897
898         if (mAGpsDataConnectionState != AGPS_DATA_CONNECTION_CLOSED) {
899             return;
900         }
901         mAGpsDataConnectionIpAddr = address;
902         mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPENING;
903
904         NetworkRequest.Builder requestBuilder = new NetworkRequest.Builder();
905         requestBuilder.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
906         requestBuilder.addCapability(NetworkCapabilities.NET_CAPABILITY_SUPL);
907         NetworkRequest request = requestBuilder.build();
908         mConnMgr.requestNetwork(
909                 request,
910                 mSuplConnectivityCallback,
911                 ConnectivityManager.MAX_NETWORK_REQUEST_TIMEOUT_MS);
912     }
913
914     private void handleReleaseSuplConnection(int agpsDataConnStatus) {
915         if (DEBUG) {
916             String message = String.format(
917                     "releaseSuplConnection, state=%s, status=%s",
918                     agpsDataConnStateAsString(),
919                     agpsDataConnStatusAsString(agpsDataConnStatus));
920             Log.d(TAG, message);
921         }
922
923         if (mAGpsDataConnectionState == AGPS_DATA_CONNECTION_CLOSED) {
924             return;
925         }
926         mAGpsDataConnectionState = AGPS_DATA_CONNECTION_CLOSED;
927
928         mConnMgr.unregisterNetworkCallback(mSuplConnectivityCallback);
929         switch (agpsDataConnStatus) {
930             case GPS_AGPS_DATA_CONN_FAILED:
931                 native_agps_data_conn_failed();
932                 break;
933             case GPS_RELEASE_AGPS_DATA_CONN:
934                 native_agps_data_conn_closed();
935                 break;
936             default:
937                 Log.e(TAG, "Invalid status to release SUPL connection: " + agpsDataConnStatus);
938         }
939     }
940
941     private void handleInjectNtpTime() {
942         if (mInjectNtpTimePending == STATE_DOWNLOADING) {
943             // already downloading data
944             return;
945         }
946         if (!isDataNetworkConnected()) {
947             // try again when network is up
948             mInjectNtpTimePending = STATE_PENDING_NETWORK;
949             return;
950         }
951         mInjectNtpTimePending = STATE_DOWNLOADING;
952
953         // hold wake lock while task runs
954         mWakeLock.acquire();
955         Log.i(TAG, "WakeLock acquired by handleInjectNtpTime()");
956         AsyncTask.THREAD_POOL_EXECUTOR.execute(new Runnable() {
957             @Override
958             public void run() {
959                 long delay;
960
961                 // force refresh NTP cache when outdated
962                 boolean refreshSuccess = true;
963                 if (mNtpTime.getCacheAge() >= NTP_INTERVAL) {
964                     refreshSuccess = mNtpTime.forceRefresh();
965                 }
966
967                 // only update when NTP time is fresh
968                 if (mNtpTime.getCacheAge() < NTP_INTERVAL) {
969                     long time = mNtpTime.getCachedNtpTime();
970                     long timeReference = mNtpTime.getCachedNtpTimeReference();
971                     long certainty = mNtpTime.getCacheCertainty();
972                     long now = System.currentTimeMillis();
973
974                     if (DEBUG) {
975                         Log.d(TAG, "NTP server returned: "
976                                 + time + " (" + new Date(time)
977                                 + ") reference: " + timeReference
978                                 + " certainty: " + certainty
979                                 + " system time offset: " + (time - now));
980                     }
981
982                     native_inject_time(time, timeReference, (int) certainty);
983                     delay = NTP_INTERVAL;
984                     mNtpBackOff.reset();
985                 } else {
986                     Log.e(TAG, "requestTime failed");
987                     delay = mNtpBackOff.nextBackoffMillis();
988                 }
989
990                 sendMessage(INJECT_NTP_TIME_FINISHED, 0, null);
991
992                 if (DEBUG) {
993                     String message = String.format(
994                             "onDemandTimeInjection=%s, refreshSuccess=%s, delay=%s",
995                             mOnDemandTimeInjection,
996                             refreshSuccess,
997                             delay);
998                     Log.d(TAG, message);
999                 }
1000                 if (mOnDemandTimeInjection || !refreshSuccess) {
1001                     // send delayed message for next NTP injection
1002                     // since this is delayed and not urgent we do not hold a wake lock here
1003                     mHandler.sendEmptyMessageDelayed(INJECT_NTP_TIME, delay);
1004                 }
1005
1006                 // release wake lock held by task
1007                 mWakeLock.release();
1008                 Log.i(TAG, "WakeLock released by handleInjectNtpTime()");
1009             }
1010         });
1011     }
1012
1013     private void handleDownloadXtraData() {
1014         if (!mSupportsXtra) {
1015             // native code reports xtra not supported, don't try
1016             Log.d(TAG, "handleDownloadXtraData() called when Xtra not supported");
1017             return;
1018         }
1019         if (mDownloadXtraDataPending == STATE_DOWNLOADING) {
1020             // already downloading data
1021             return;
1022         }
1023         if (!isDataNetworkConnected()) {
1024             // try again when network is up
1025             mDownloadXtraDataPending = STATE_PENDING_NETWORK;
1026             return;
1027         }
1028         mDownloadXtraDataPending = STATE_DOWNLOADING;
1029
1030         // hold wake lock while task runs
1031         mWakeLock.acquire();
1032         Log.i(TAG, "WakeLock acquired by handleDownloadXtraData()");
1033         AsyncTask.THREAD_POOL_EXECUTOR.execute(new Runnable() {
1034             @Override
1035             public void run() {
1036                 GpsXtraDownloader xtraDownloader = new GpsXtraDownloader(mProperties);
1037                 byte[] data = xtraDownloader.downloadXtraData();
1038                 if (data != null) {
1039                     if (DEBUG) Log.d(TAG, "calling native_inject_xtra_data");
1040                     native_inject_xtra_data(data, data.length);
1041                     mXtraBackOff.reset();
1042                 }
1043
1044                 sendMessage(DOWNLOAD_XTRA_DATA_FINISHED, 0, null);
1045
1046                 if (data == null) {
1047                     // try again later
1048                     // since this is delayed and not urgent we do not hold a wake lock here
1049                     mHandler.sendEmptyMessageDelayed(DOWNLOAD_XTRA_DATA,
1050                             mXtraBackOff.nextBackoffMillis());
1051                 }
1052
1053                 // release wake lock held by task
1054                 mWakeLock.release();
1055                 Log.i(TAG, "WakeLock released by handleDownloadXtraData()");
1056             }
1057         });
1058     }
1059
1060     private void handleUpdateLocation(Location location) {
1061         if (location.hasAccuracy()) {
1062             native_inject_location(location.getLatitude(), location.getLongitude(),
1063                     location.getAccuracy());
1064         }
1065     }
1066
1067     /**
1068      * Enables this provider.  When enabled, calls to getStatus()
1069      * must be handled.  Hardware may be started up
1070      * when the provider is enabled.
1071      */
1072     @Override
1073     public void enable() {
1074         synchronized (mLock) {
1075             if (mEnabled) return;
1076             mEnabled = true;
1077         }
1078
1079         sendMessage(ENABLE, 1, null);
1080     }
1081
1082     private void setSuplHostPort(String hostString, String portString) {
1083         if (hostString != null) {
1084             mSuplServerHost = hostString;
1085         }
1086         if (portString != null) {
1087             try {
1088                 mSuplServerPort = Integer.parseInt(portString);
1089             } catch (NumberFormatException e) {
1090                 Log.e(TAG, "unable to parse SUPL_PORT: " + portString);
1091             }
1092         }
1093         if (mSuplServerHost != null
1094                 && mSuplServerPort > TCP_MIN_PORT
1095                 && mSuplServerPort <= TCP_MAX_PORT) {
1096             native_set_agps_server(AGPS_TYPE_SUPL, mSuplServerHost, mSuplServerPort);
1097         }
1098     }
1099
1100     /**
1101      * Checks what SUPL mode to use, according to the AGPS mode as well as the
1102      * allowed mode from properties.
1103      *
1104      * @param properties GPS properties
1105      * @param agpsEnabled whether AGPS is enabled by settings value
1106      * @param singleShot whether "singleshot" is needed
1107      * @return SUPL mode (MSA vs MSB vs STANDALONE)
1108      */
1109     private int getSuplMode(Properties properties, boolean agpsEnabled, boolean singleShot) {
1110         if (agpsEnabled) {
1111             String modeString = properties.getProperty("SUPL_MODE");
1112             int suplMode = 0;
1113             if (!TextUtils.isEmpty(modeString)) {
1114                 try {
1115                     suplMode = Integer.parseInt(modeString);
1116                 } catch (NumberFormatException e) {
1117                     Log.e(TAG, "unable to parse SUPL_MODE: " + modeString);
1118                     return GPS_POSITION_MODE_STANDALONE;
1119                 }
1120             }
1121             // MS-Based is the preferred mode for Assisted-GPS position computation, so we favor
1122             // such mode when it is available
1123             if (hasCapability(GPS_CAPABILITY_MSB) && (suplMode & AGPS_SUPL_MODE_MSB) != 0) {
1124                 return GPS_POSITION_MODE_MS_BASED;
1125             }
1126             // for now, just as the legacy code did, we fallback to MS-Assisted if it is available,
1127             // do fallback only for single-shot requests, because it is too expensive to do for
1128             // periodic requests as well
1129             if (singleShot
1130                     && hasCapability(GPS_CAPABILITY_MSA)
1131                     && (suplMode & AGPS_SUPL_MODE_MSA) != 0) {
1132                 return GPS_POSITION_MODE_MS_ASSISTED;
1133             }
1134         }
1135         return GPS_POSITION_MODE_STANDALONE;
1136     }
1137
1138     private void handleEnable() {
1139         if (DEBUG) Log.d(TAG, "handleEnable");
1140
1141         boolean enabled = native_init();
1142
1143         if (enabled) {
1144             mSupportsXtra = native_supports_xtra();
1145
1146             // TODO: remove the following native calls if we can make sure they are redundant.
1147             if (mSuplServerHost != null) {
1148                 native_set_agps_server(AGPS_TYPE_SUPL, mSuplServerHost, mSuplServerPort);
1149             }
1150             if (mC2KServerHost != null) {
1151                 native_set_agps_server(AGPS_TYPE_C2K, mC2KServerHost, mC2KServerPort);
1152             }
1153
1154             mGnssMeasurementsProvider.onGpsEnabledChanged();
1155             mGnssNavigationMessageProvider.onGpsEnabledChanged();
1156         } else {
1157             synchronized (mLock) {
1158                 mEnabled = false;
1159             }
1160             Log.w(TAG, "Failed to enable location provider");
1161         }
1162     }
1163
1164     /**
1165      * Disables this provider.  When disabled, calls to getStatus()
1166      * need not be handled.  Hardware may be shut
1167      * down while the provider is disabled.
1168      */
1169     @Override
1170     public void disable() {
1171         synchronized (mLock) {
1172             if (!mEnabled) return;
1173             mEnabled = false;
1174         }
1175
1176         sendMessage(ENABLE, 0, null);
1177     }
1178
1179     private void handleDisable() {
1180         if (DEBUG) Log.d(TAG, "handleDisable");
1181
1182         updateClientUids(new WorkSource());
1183         stopNavigating();
1184         mAlarmManager.cancel(mWakeupIntent);
1185         mAlarmManager.cancel(mTimeoutIntent);
1186
1187         // do this before releasing wakelock
1188         native_cleanup();
1189
1190         mGnssMeasurementsProvider.onGpsEnabledChanged();
1191         mGnssNavigationMessageProvider.onGpsEnabledChanged();
1192     }
1193
1194     @Override
1195     public boolean isEnabled() {
1196         synchronized (mLock) {
1197             return mEnabled;
1198         }
1199     }
1200
1201     @Override
1202     public int getStatus(Bundle extras) {
1203         if (extras != null) {
1204             extras.putInt("satellites", mSvCount);
1205         }
1206         return mStatus;
1207     }
1208
1209     private void updateStatus(int status, int svCount) {
1210         if (status != mStatus || svCount != mSvCount) {
1211             mStatus = status;
1212             mSvCount = svCount;
1213             mLocationExtras.putInt("satellites", svCount);
1214             mStatusUpdateTime = SystemClock.elapsedRealtime();
1215         }
1216     }
1217
1218     @Override
1219     public long getStatusUpdateTime() {
1220         return mStatusUpdateTime;
1221     }
1222
1223     @Override
1224     public void setRequest(ProviderRequest request, WorkSource source) {
1225         sendMessage(SET_REQUEST, 0, new GpsRequest(request, source));
1226     }
1227
1228     private void handleSetRequest(ProviderRequest request, WorkSource source) {
1229         mProviderRequest = request;
1230         mWorkSource = source;
1231         updateRequirements();
1232     }
1233
1234     // Called when the requirements for GPS may have changed
1235     private void updateRequirements() {
1236         if (mProviderRequest == null || mWorkSource == null) {
1237             return;
1238         }
1239
1240         boolean singleShot = false;
1241
1242         // see if the request is for a single update
1243         if (mProviderRequest.locationRequests != null
1244                 && mProviderRequest.locationRequests.size() > 0) {
1245             // if any request has zero or more than one updates
1246             // requested, then this is not single-shot mode
1247             singleShot = true;
1248
1249             for (LocationRequest lr : mProviderRequest.locationRequests) {
1250                 if (lr.getNumUpdates() != 1) {
1251                     singleShot = false;
1252                 }
1253             }
1254         }
1255
1256         if (DEBUG) Log.d(TAG, "setRequest " + mProviderRequest);
1257         if (mProviderRequest.reportLocation && !mDisableGps && isEnabled()) {
1258             // update client uids
1259             updateClientUids(mWorkSource);
1260
1261             mFixInterval = (int) mProviderRequest.interval;
1262
1263             // check for overflow
1264             if (mFixInterval != mProviderRequest.interval) {
1265                 Log.w(TAG, "interval overflow: " + mProviderRequest.interval);
1266                 mFixInterval = Integer.MAX_VALUE;
1267             }
1268
1269             // apply request to GPS engine
1270             if (mStarted && hasCapability(GPS_CAPABILITY_SCHEDULING)) {
1271                 // change period
1272                 if (!native_set_position_mode(mPositionMode, GPS_POSITION_RECURRENCE_PERIODIC,
1273                         mFixInterval, 0, 0)) {
1274                     Log.e(TAG, "set_position_mode failed in setMinTime()");
1275                 }
1276             } else if (!mStarted) {
1277                 // start GPS
1278                 startNavigating(singleShot);
1279             }
1280         } else {
1281             updateClientUids(new WorkSource());
1282
1283             stopNavigating();
1284             mAlarmManager.cancel(mWakeupIntent);
1285             mAlarmManager.cancel(mTimeoutIntent);
1286         }
1287     }
1288
1289     private void updateClientUids(WorkSource source) {
1290         // Update work source.
1291         WorkSource[] changes = mClientSource.setReturningDiffs(source);
1292         if (changes == null) {
1293             return;
1294         }
1295         WorkSource newWork = changes[0];
1296         WorkSource goneWork = changes[1];
1297
1298         // Update sources that were not previously tracked.
1299         if (newWork != null) {
1300             int lastuid = -1;
1301             for (int i=0; i<newWork.size(); i++) {
1302                 try {
1303                     int uid = newWork.get(i);
1304                     mAppOpsService.startOperation(AppOpsManager.getToken(mAppOpsService),
1305                             AppOpsManager.OP_GPS, uid, newWork.getName(i));
1306                     if (uid != lastuid) {
1307                         lastuid = uid;
1308                         mBatteryStats.noteStartGps(uid);
1309                     }
1310                 } catch (RemoteException e) {
1311                     Log.w(TAG, "RemoteException", e);
1312                 }
1313             }
1314         }
1315
1316         // Update sources that are no longer tracked.
1317         if (goneWork != null) {
1318             int lastuid = -1;
1319             for (int i=0; i<goneWork.size(); i++) {
1320                 try {
1321                     int uid = goneWork.get(i);
1322                     mAppOpsService.finishOperation(AppOpsManager.getToken(mAppOpsService),
1323                             AppOpsManager.OP_GPS, uid, goneWork.getName(i));
1324                     if (uid != lastuid) {
1325                         lastuid = uid;
1326                         mBatteryStats.noteStopGps(uid);
1327                     }
1328                 } catch (RemoteException e) {
1329                     Log.w(TAG, "RemoteException", e);
1330                 }
1331             }
1332         }
1333     }
1334
1335     @Override
1336     public boolean sendExtraCommand(String command, Bundle extras) {
1337
1338         long identity = Binder.clearCallingIdentity();
1339         boolean result = false;
1340
1341         if ("delete_aiding_data".equals(command)) {
1342             result = deleteAidingData(extras);
1343         } else if ("force_time_injection".equals(command)) {
1344             requestUtcTime();
1345             result = true;
1346         } else if ("force_xtra_injection".equals(command)) {
1347             if (mSupportsXtra) {
1348                 xtraDownloadRequest();
1349                 result = true;
1350             }
1351         } else {
1352             Log.w(TAG, "sendExtraCommand: unknown command " + command);
1353         }
1354
1355         Binder.restoreCallingIdentity(identity);
1356         return result;
1357     }
1358
1359     private IGpsGeofenceHardware mGpsGeofenceBinder = new IGpsGeofenceHardware.Stub() {
1360         public boolean isHardwareGeofenceSupported() {
1361             return native_is_geofence_supported();
1362         }
1363
1364         public boolean addCircularHardwareGeofence(int geofenceId, double latitude,
1365                 double longitude, double radius, int lastTransition, int monitorTransitions,
1366                 int notificationResponsiveness, int unknownTimer) {
1367             return native_add_geofence(geofenceId, latitude, longitude, radius,
1368                     lastTransition, monitorTransitions, notificationResponsiveness, unknownTimer);
1369         }
1370
1371         public boolean removeHardwareGeofence(int geofenceId) {
1372             return native_remove_geofence(geofenceId);
1373         }
1374
1375         public boolean pauseHardwareGeofence(int geofenceId) {
1376             return native_pause_geofence(geofenceId);
1377         }
1378
1379         public boolean resumeHardwareGeofence(int geofenceId, int monitorTransition) {
1380             return native_resume_geofence(geofenceId, monitorTransition);
1381         }
1382     };
1383
1384     private boolean deleteAidingData(Bundle extras) {
1385         int flags;
1386
1387         if (extras == null) {
1388             flags = GPS_DELETE_ALL;
1389         } else {
1390             flags = 0;
1391             if (extras.getBoolean("ephemeris")) flags |= GPS_DELETE_EPHEMERIS;
1392             if (extras.getBoolean("almanac")) flags |= GPS_DELETE_ALMANAC;
1393             if (extras.getBoolean("position")) flags |= GPS_DELETE_POSITION;
1394             if (extras.getBoolean("time")) flags |= GPS_DELETE_TIME;
1395             if (extras.getBoolean("iono")) flags |= GPS_DELETE_IONO;
1396             if (extras.getBoolean("utc")) flags |= GPS_DELETE_UTC;
1397             if (extras.getBoolean("health")) flags |= GPS_DELETE_HEALTH;
1398             if (extras.getBoolean("svdir")) flags |= GPS_DELETE_SVDIR;
1399             if (extras.getBoolean("svsteer")) flags |= GPS_DELETE_SVSTEER;
1400             if (extras.getBoolean("sadata")) flags |= GPS_DELETE_SADATA;
1401             if (extras.getBoolean("rti")) flags |= GPS_DELETE_RTI;
1402             if (extras.getBoolean("celldb-info")) flags |= GPS_DELETE_CELLDB_INFO;
1403             if (extras.getBoolean("all")) flags |= GPS_DELETE_ALL;
1404         }
1405
1406         if (flags != 0) {
1407             native_delete_aiding_data(flags);
1408             return true;
1409         }
1410
1411         return false;
1412     }
1413
1414     private void startNavigating(boolean singleShot) {
1415         if (!mStarted) {
1416             if (DEBUG) Log.d(TAG, "startNavigating, singleShot is " + singleShot);
1417             mTimeToFirstFix = 0;
1418             mLastFixTime = 0;
1419             mStarted = true;
1420             mSingleShot = singleShot;
1421             mPositionMode = GPS_POSITION_MODE_STANDALONE;
1422             // Notify about suppressed output, if speed limit was previously exceeded.
1423             // Elsewhere, we check again with every speed output reported.
1424             if (mItarSpeedLimitExceeded) {
1425                 Log.i(TAG, "startNavigating with ITAR limit in place. Output limited  " +
1426                         "until slow enough speed reported.");
1427             }
1428
1429             boolean agpsEnabled =
1430                     (Settings.Global.getInt(mContext.getContentResolver(),
1431                                             Settings.Global.ASSISTED_GPS_ENABLED, 1) != 0);
1432             mPositionMode = getSuplMode(mProperties, agpsEnabled, singleShot);
1433
1434             if (DEBUG) {
1435                 String mode;
1436
1437                 switch(mPositionMode) {
1438                     case GPS_POSITION_MODE_STANDALONE:
1439                         mode = "standalone";
1440                         break;
1441                     case GPS_POSITION_MODE_MS_ASSISTED:
1442                         mode = "MS_ASSISTED";
1443                         break;
1444                     case GPS_POSITION_MODE_MS_BASED:
1445                         mode = "MS_BASED";
1446                         break;
1447                     default:
1448                         mode = "unknown";
1449                         break;
1450                 }
1451                 Log.d(TAG, "setting position_mode to " + mode);
1452             }
1453
1454             int interval = (hasCapability(GPS_CAPABILITY_SCHEDULING) ? mFixInterval : 1000);
1455             if (!native_set_position_mode(mPositionMode, GPS_POSITION_RECURRENCE_PERIODIC,
1456                     interval, 0, 0)) {
1457                 mStarted = false;
1458                 Log.e(TAG, "set_position_mode failed in startNavigating()");
1459                 return;
1460             }
1461             if (!native_start()) {
1462                 mStarted = false;
1463                 Log.e(TAG, "native_start failed in startNavigating()");
1464                 return;
1465             }
1466
1467             // reset SV count to zero
1468             updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE, 0);
1469             mFixRequestTime = SystemClock.elapsedRealtime(); //return milliseconds since boot
1470             if (!hasCapability(GPS_CAPABILITY_SCHEDULING)) {
1471                 // set timer to give up if we do not receive a fix within NO_FIX_TIMEOUT
1472                 // and our fix interval is not short
1473                 if (mFixInterval >= NO_FIX_TIMEOUT) {
1474                     mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
1475                             SystemClock.elapsedRealtime() + NO_FIX_TIMEOUT, mTimeoutIntent);
1476                 }
1477             }
1478         }
1479     }
1480
1481     private void stopNavigating() {
1482         if (DEBUG) Log.d(TAG, "stopNavigating");
1483         if (mStarted) {
1484             mStarted = false;
1485             mSingleShot = false;
1486             native_stop();
1487             mTimeToFirstFix = 0;
1488             mLastFixTime = 0;
1489             mLocationFlags = LOCATION_INVALID;
1490
1491             // reset SV count to zero
1492             updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE, 0);
1493         }
1494     }
1495
1496     private void hibernate() {
1497         // stop GPS until our next fix interval arrives
1498         stopNavigating();
1499         mAlarmManager.cancel(mTimeoutIntent);
1500         mAlarmManager.cancel(mWakeupIntent);
1501         long now = SystemClock.elapsedRealtime();
1502         mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, now + mFixInterval, mWakeupIntent);
1503     }
1504
1505     private boolean hasCapability(int capability) {
1506         return ((mEngineCapabilities & capability) != 0);
1507     }
1508
1509
1510     /**
1511      * called from native code to update our position.
1512      */
1513     private void reportLocation(int flags, double latitude, double longitude, double altitude,
1514             float speedMetersPerSecond, float bearing, float accuracy, long timestamp) {
1515         if ((flags & LOCATION_HAS_SPEED) == LOCATION_HAS_SPEED) {
1516             mItarSpeedLimitExceeded = speedMetersPerSecond > ITAR_SPEED_LIMIT_METERS_PER_SECOND;
1517         }
1518
1519         if (mItarSpeedLimitExceeded) {
1520             Log.i(TAG, "Hal reported a speed in excess of ITAR limit." +
1521                     "  GPS/GNSS Navigation output blocked.");
1522             return;  // No output of location allowed
1523         }
1524
1525         if (VERBOSE) Log.v(TAG, "reportLocation lat: " + latitude + " long: " + longitude +
1526                 " timestamp: " + timestamp);
1527
1528         synchronized (mLocation) {
1529             mLocationFlags = flags;
1530             if ((flags & LOCATION_HAS_LAT_LONG) == LOCATION_HAS_LAT_LONG) {
1531                 mLocation.setLatitude(latitude);
1532                 mLocation.setLongitude(longitude);
1533                 mLocation.setTime(timestamp);
1534                 // It would be nice to push the elapsed real-time timestamp
1535                 // further down the stack, but this is still useful
1536                 mLocation.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());
1537             }
1538             if ((flags & LOCATION_HAS_ALTITUDE) == LOCATION_HAS_ALTITUDE) {
1539                 mLocation.setAltitude(altitude);
1540             } else {
1541                 mLocation.removeAltitude();
1542             }
1543             if ((flags & LOCATION_HAS_SPEED) == LOCATION_HAS_SPEED) {
1544                 mLocation.setSpeed(speedMetersPerSecond);
1545             } else {
1546                 mLocation.removeSpeed();
1547             }
1548             if ((flags & LOCATION_HAS_BEARING) == LOCATION_HAS_BEARING) {
1549                 mLocation.setBearing(bearing);
1550             } else {
1551                 mLocation.removeBearing();
1552             }
1553             if ((flags & LOCATION_HAS_ACCURACY) == LOCATION_HAS_ACCURACY) {
1554                 mLocation.setAccuracy(accuracy);
1555             } else {
1556                 mLocation.removeAccuracy();
1557             }
1558             mLocation.setExtras(mLocationExtras);
1559
1560             try {
1561                 mILocationManager.reportLocation(mLocation, false);
1562             } catch (RemoteException e) {
1563                 Log.e(TAG, "RemoteException calling reportLocation");
1564             }
1565         }
1566
1567         mLastFixTime = SystemClock.elapsedRealtime(); //return milliseconds since boot
1568         // report time to first fix
1569         if (mTimeToFirstFix == 0 && (flags & LOCATION_HAS_LAT_LONG) == LOCATION_HAS_LAT_LONG) {
1570             mTimeToFirstFix = (int)(mLastFixTime - mFixRequestTime);
1571             if (DEBUG) Log.d(TAG, "TTFF: " + mTimeToFirstFix);
1572
1573             // notify status listeners
1574             mListenerHelper.onFirstFix(mTimeToFirstFix);
1575         }
1576
1577         if (mSingleShot) {
1578             stopNavigating();
1579         }
1580
1581         if (mStarted && mStatus != LocationProvider.AVAILABLE) {
1582             // we want to time out if we do not receive a fix
1583             // within the time out and we are requesting infrequent fixes
1584             if (!hasCapability(GPS_CAPABILITY_SCHEDULING) && mFixInterval < NO_FIX_TIMEOUT) {
1585                 mAlarmManager.cancel(mTimeoutIntent);
1586             }
1587
1588             // send an intent to notify that the GPS is receiving fixes.
1589             Intent intent = new Intent(LocationManager.GPS_FIX_CHANGE_ACTION);
1590             intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, true);
1591             mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
1592             updateStatus(LocationProvider.AVAILABLE, mSvCount);
1593         }
1594
1595        if (!hasCapability(GPS_CAPABILITY_SCHEDULING) && mStarted &&
1596                mFixInterval > GPS_POLLING_THRESHOLD_INTERVAL) {
1597             if (DEBUG) Log.d(TAG, "got fix, hibernating");
1598             hibernate();
1599         }
1600    }
1601
1602     /**
1603      * called from native code to update our status
1604      */
1605     private void reportStatus(int status) {
1606         if (DEBUG) Log.v(TAG, "reportStatus status: " + status);
1607
1608         boolean wasNavigating = mNavigating;
1609         switch (status) {
1610             case GPS_STATUS_SESSION_BEGIN:
1611                 mNavigating = true;
1612                 mEngineOn = true;
1613                 break;
1614             case GPS_STATUS_SESSION_END:
1615                 mNavigating = false;
1616                 break;
1617             case GPS_STATUS_ENGINE_ON:
1618                 mEngineOn = true;
1619                 break;
1620             case GPS_STATUS_ENGINE_OFF:
1621                 mEngineOn = false;
1622                 mNavigating = false;
1623                 break;
1624         }
1625
1626         if (wasNavigating != mNavigating) {
1627             mListenerHelper.onStatusChanged(mNavigating);
1628
1629             // send an intent to notify that the GPS has been enabled or disabled
1630             Intent intent = new Intent(LocationManager.GPS_ENABLED_CHANGE_ACTION);
1631             intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, mNavigating);
1632             mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
1633         }
1634     }
1635
1636     /**
1637      * called from native code to update SV info
1638      */
1639     private void reportSvStatus() {
1640         int svCount = native_read_sv_status(mSvidWithFlags, mCn0s, mSvElevations, mSvAzimuths);
1641         mListenerHelper.onSvStatusChanged(
1642                 svCount,
1643                 mSvidWithFlags,
1644                 mCn0s,
1645                 mSvElevations,
1646                 mSvAzimuths);
1647
1648         if (VERBOSE) {
1649             Log.v(TAG, "SV count: " + svCount);
1650         }
1651         // Calculate number of sets used in fix.
1652         int usedInFixCount = 0;
1653         for (int i = 0; i < svCount; i++) {
1654             if ((mSvidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_USED_IN_FIX) != 0) {
1655                 ++usedInFixCount;
1656             }
1657             if (VERBOSE) {
1658                 Log.v(TAG, "svid: " + (mSvidWithFlags[i] >> GnssStatus.SVID_SHIFT_WIDTH) +
1659                         " cn0: " + mCn0s[i]/10 +
1660                         " elev: " + mSvElevations[i] +
1661                         " azimuth: " + mSvAzimuths[i] +
1662                         ((mSvidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_HAS_EPHEMERIS_DATA) == 0
1663                                 ? "  " : " E") +
1664                         ((mSvidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_HAS_ALMANAC_DATA) == 0
1665                                 ? "  " : " A") +
1666                         ((mSvidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_USED_IN_FIX) == 0
1667                                 ? "" : "U"));
1668             }
1669         }
1670         // return number of sets used in fix instead of total
1671         updateStatus(mStatus, usedInFixCount);
1672
1673         if (mNavigating && mStatus == LocationProvider.AVAILABLE && mLastFixTime > 0 &&
1674             SystemClock.elapsedRealtime() - mLastFixTime > RECENT_FIX_TIMEOUT) {
1675             // send an intent to notify that the GPS is no longer receiving fixes.
1676             Intent intent = new Intent(LocationManager.GPS_FIX_CHANGE_ACTION);
1677             intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, false);
1678             mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
1679             updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE, mSvCount);
1680         }
1681     }
1682
1683     /**
1684      * called from native code to update AGPS status
1685      */
1686     private void reportAGpsStatus(int type, int status, byte[] ipaddr) {
1687         switch (status) {
1688             case GPS_REQUEST_AGPS_DATA_CONN:
1689                 if (DEBUG) Log.d(TAG, "GPS_REQUEST_AGPS_DATA_CONN");
1690                 Log.v(TAG, "Received SUPL IP addr[]: " + Arrays.toString(ipaddr));
1691                 InetAddress connectionIpAddress = null;
1692                 if (ipaddr != null) {
1693                     try {
1694                         connectionIpAddress = InetAddress.getByAddress(ipaddr);
1695                         if (DEBUG) Log.d(TAG, "IP address converted to: " + connectionIpAddress);
1696                     } catch (UnknownHostException e) {
1697                         Log.e(TAG, "Bad IP Address: " + ipaddr, e);
1698                     }
1699                 }
1700                 sendMessage(REQUEST_SUPL_CONNECTION, 0 /*arg*/, connectionIpAddress);
1701                 break;
1702             case GPS_RELEASE_AGPS_DATA_CONN:
1703                 if (DEBUG) Log.d(TAG, "GPS_RELEASE_AGPS_DATA_CONN");
1704                 releaseSuplConnection(GPS_RELEASE_AGPS_DATA_CONN);
1705                 break;
1706             case GPS_AGPS_DATA_CONNECTED:
1707                 if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONNECTED");
1708                 break;
1709             case GPS_AGPS_DATA_CONN_DONE:
1710                 if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONN_DONE");
1711                 break;
1712             case GPS_AGPS_DATA_CONN_FAILED:
1713                 if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONN_FAILED");
1714                 break;
1715             default:
1716                 if (DEBUG) Log.d(TAG, "Received Unknown AGPS status: " + status);
1717         }
1718     }
1719
1720     private void releaseSuplConnection(int connStatus) {
1721         sendMessage(RELEASE_SUPL_CONNECTION, connStatus, null /*obj*/);
1722     }
1723
1724     /**
1725      * called from native code to report NMEA data received
1726      */
1727     private void reportNmea(long timestamp) {
1728         if (!mItarSpeedLimitExceeded) {
1729             int length = native_read_nmea(mNmeaBuffer, mNmeaBuffer.length);
1730             String nmea = new String(mNmeaBuffer, 0 /* offset */, length);
1731             mListenerHelper.onNmeaReceived(timestamp, nmea);
1732         }
1733     }
1734
1735     /**
1736      * called from native code - Gps measurements callback
1737      */
1738     private void reportMeasurementData(GnssMeasurementsEvent event) {
1739         if (!mItarSpeedLimitExceeded) {
1740             mGnssMeasurementsProvider.onMeasurementsAvailable(event);
1741         }
1742     }
1743
1744     /**
1745      * called from native code - GPS navigation message callback
1746      */
1747     private void reportNavigationMessage(GnssNavigationMessage event) {
1748         if (!mItarSpeedLimitExceeded) {
1749             mGnssNavigationMessageProvider.onNavigationMessageAvailable(event);
1750         }
1751     }
1752
1753     /**
1754      * called from native code to inform us what the GPS engine capabilities are
1755      */
1756     private void setEngineCapabilities(int capabilities) {
1757         mEngineCapabilities = capabilities;
1758
1759         if (hasCapability(GPS_CAPABILITY_ON_DEMAND_TIME)) {
1760             mOnDemandTimeInjection = true;
1761             requestUtcTime();
1762         }
1763
1764         mGnssMeasurementsProvider.onCapabilitiesUpdated(
1765                 (capabilities & GPS_CAPABILITY_MEASUREMENTS) == GPS_CAPABILITY_MEASUREMENTS);
1766         mGnssNavigationMessageProvider.onCapabilitiesUpdated(
1767                 (capabilities & GPS_CAPABILITY_NAV_MESSAGES) == GPS_CAPABILITY_NAV_MESSAGES);
1768     }
1769
1770     /**
1771      * Called from native code to inform us the hardware information.
1772      */
1773     private void setGnssYearOfHardware(int yearOfHardware) {
1774         if (DEBUG) Log.d(TAG, "setGnssYearOfHardware called with " + yearOfHardware);
1775         mYearOfHardware = yearOfHardware;
1776     }
1777
1778     public interface GnssSystemInfoProvider {
1779         /**
1780          * Returns the year of GPS hardware.
1781          */
1782         int getGnssYearOfHardware();
1783     }
1784
1785     /**
1786      * @hide
1787      */
1788     public GnssSystemInfoProvider getGnssSystemInfoProvider() {
1789         return new GnssSystemInfoProvider() {
1790             @Override
1791             public int getGnssYearOfHardware() {
1792                 return mYearOfHardware;
1793             }
1794         };
1795     }
1796
1797     /**
1798      * called from native code to request XTRA data
1799      */
1800     private void xtraDownloadRequest() {
1801         if (DEBUG) Log.d(TAG, "xtraDownloadRequest");
1802         sendMessage(DOWNLOAD_XTRA_DATA, 0, null);
1803     }
1804
1805     /**
1806      * Helper method to construct a location object.
1807      */
1808     private Location buildLocation(
1809             int flags,
1810             double latitude,
1811             double longitude,
1812             double altitude,
1813             float speed,
1814             float bearing,
1815             float accuracy,
1816             long timestamp) {
1817         Location location = new Location(LocationManager.GPS_PROVIDER);
1818         if((flags & LOCATION_HAS_LAT_LONG) == LOCATION_HAS_LAT_LONG) {
1819             location.setLatitude(latitude);
1820             location.setLongitude(longitude);
1821             location.setTime(timestamp);
1822             location.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());
1823         }
1824         if((flags & LOCATION_HAS_ALTITUDE) == LOCATION_HAS_ALTITUDE) {
1825             location.setAltitude(altitude);
1826         }
1827         if((flags & LOCATION_HAS_SPEED) == LOCATION_HAS_SPEED) {
1828             location.setSpeed(speed);
1829         }
1830         if((flags & LOCATION_HAS_BEARING) == LOCATION_HAS_BEARING) {
1831             location.setBearing(bearing);
1832         }
1833         if((flags & LOCATION_HAS_ACCURACY) == LOCATION_HAS_ACCURACY) {
1834             location.setAccuracy(accuracy);
1835         }
1836         return location;
1837     }
1838
1839     /**
1840      * Converts the GPS HAL status to the internal Geofence Hardware status.
1841      */
1842     private int getGeofenceStatus(int status) {
1843         switch(status) {
1844             case GPS_GEOFENCE_OPERATION_SUCCESS:
1845                 return GeofenceHardware.GEOFENCE_SUCCESS;
1846             case GPS_GEOFENCE_ERROR_GENERIC:
1847                 return GeofenceHardware.GEOFENCE_FAILURE;
1848             case GPS_GEOFENCE_ERROR_ID_EXISTS:
1849                 return GeofenceHardware.GEOFENCE_ERROR_ID_EXISTS;
1850             case GPS_GEOFENCE_ERROR_INVALID_TRANSITION:
1851                 return GeofenceHardware.GEOFENCE_ERROR_INVALID_TRANSITION;
1852             case GPS_GEOFENCE_ERROR_TOO_MANY_GEOFENCES:
1853                 return GeofenceHardware.GEOFENCE_ERROR_TOO_MANY_GEOFENCES;
1854             case GPS_GEOFENCE_ERROR_ID_UNKNOWN:
1855                 return GeofenceHardware.GEOFENCE_ERROR_ID_UNKNOWN;
1856             default:
1857                 return -1;
1858         }
1859     }
1860
1861     /**
1862      * Called from native to report GPS Geofence transition
1863      * All geofence callbacks are called on the same thread
1864      */
1865     private void reportGeofenceTransition(int geofenceId, int flags, double latitude,
1866             double longitude, double altitude, float speed, float bearing, float accuracy,
1867             long timestamp, int transition, long transitionTimestamp) {
1868         if (mGeofenceHardwareImpl == null) {
1869             mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
1870         }
1871         Location location = buildLocation(
1872                 flags,
1873                 latitude,
1874                 longitude,
1875                 altitude,
1876                 speed,
1877                 bearing,
1878                 accuracy,
1879                 timestamp);
1880         mGeofenceHardwareImpl.reportGeofenceTransition(
1881                 geofenceId,
1882                 location,
1883                 transition,
1884                 transitionTimestamp,
1885                 GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE,
1886                 FusedBatchOptions.SourceTechnologies.GNSS);
1887     }
1888
1889     /**
1890      * called from native code to report GPS status change.
1891      */
1892     private void reportGeofenceStatus(int status, int flags, double latitude,
1893             double longitude, double altitude, float speed, float bearing, float accuracy,
1894             long timestamp) {
1895         if (mGeofenceHardwareImpl == null) {
1896             mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
1897         }
1898         Location location = buildLocation(
1899                 flags,
1900                 latitude,
1901                 longitude,
1902                 altitude,
1903                 speed,
1904                 bearing,
1905                 accuracy,
1906                 timestamp);
1907         int monitorStatus = GeofenceHardware.MONITOR_CURRENTLY_UNAVAILABLE;
1908         if(status == GPS_GEOFENCE_AVAILABLE) {
1909             monitorStatus = GeofenceHardware.MONITOR_CURRENTLY_AVAILABLE;
1910         }
1911         mGeofenceHardwareImpl.reportGeofenceMonitorStatus(
1912                 GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE,
1913                 monitorStatus,
1914                 location,
1915                 FusedBatchOptions.SourceTechnologies.GNSS);
1916     }
1917
1918     /**
1919      * called from native code - Geofence Add callback
1920      */
1921     private void reportGeofenceAddStatus(int geofenceId, int status) {
1922         if (mGeofenceHardwareImpl == null) {
1923             mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
1924         }
1925         mGeofenceHardwareImpl.reportGeofenceAddStatus(geofenceId, getGeofenceStatus(status));
1926     }
1927
1928     /**
1929      * called from native code - Geofence Remove callback
1930      */
1931     private void reportGeofenceRemoveStatus(int geofenceId, int status) {
1932         if (mGeofenceHardwareImpl == null) {
1933             mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
1934         }
1935         mGeofenceHardwareImpl.reportGeofenceRemoveStatus(geofenceId, getGeofenceStatus(status));
1936     }
1937
1938     /**
1939      * called from native code - Geofence Pause callback
1940      */
1941     private void reportGeofencePauseStatus(int geofenceId, int status) {
1942         if (mGeofenceHardwareImpl == null) {
1943             mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
1944         }
1945         mGeofenceHardwareImpl.reportGeofencePauseStatus(geofenceId, getGeofenceStatus(status));
1946     }
1947
1948     /**
1949      * called from native code - Geofence Resume callback
1950      */
1951     private void reportGeofenceResumeStatus(int geofenceId, int status) {
1952         if (mGeofenceHardwareImpl == null) {
1953             mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
1954         }
1955         mGeofenceHardwareImpl.reportGeofenceResumeStatus(geofenceId, getGeofenceStatus(status));
1956     }
1957
1958     //=============================================================
1959     // NI Client support
1960     //=============================================================
1961     private final INetInitiatedListener mNetInitiatedListener = new INetInitiatedListener.Stub() {
1962         // Sends a response for an NI request to HAL.
1963         @Override
1964         public boolean sendNiResponse(int notificationId, int userResponse)
1965         {
1966             // TODO Add Permission check
1967
1968             if (DEBUG) Log.d(TAG, "sendNiResponse, notifId: " + notificationId +
1969                     ", response: " + userResponse);
1970             native_send_ni_response(notificationId, userResponse);
1971             return true;
1972         }
1973     };
1974
1975     public INetInitiatedListener getNetInitiatedListener() {
1976         return mNetInitiatedListener;
1977     }
1978
1979     // Called by JNI function to report an NI request.
1980     public void reportNiNotification(
1981             int notificationId,
1982             int niType,
1983             int notifyFlags,
1984             int timeout,
1985             int defaultResponse,
1986             String requestorId,
1987             String text,
1988             int requestorIdEncoding,
1989             int textEncoding,
1990             String extras  // Encoded extra data
1991         )
1992     {
1993         Log.i(TAG, "reportNiNotification: entered");
1994         Log.i(TAG, "notificationId: " + notificationId +
1995                 ", niType: " + niType +
1996                 ", notifyFlags: " + notifyFlags +
1997                 ", timeout: " + timeout +
1998                 ", defaultResponse: " + defaultResponse);
1999
2000         Log.i(TAG, "requestorId: " + requestorId +
2001                 ", text: " + text +
2002                 ", requestorIdEncoding: " + requestorIdEncoding +
2003                 ", textEncoding: " + textEncoding);
2004
2005         GpsNiNotification notification = new GpsNiNotification();
2006
2007         notification.notificationId = notificationId;
2008         notification.niType = niType;
2009         notification.needNotify = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_NEED_NOTIFY) != 0;
2010         notification.needVerify = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_NEED_VERIFY) != 0;
2011         notification.privacyOverride = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_PRIVACY_OVERRIDE) != 0;
2012         notification.timeout = timeout;
2013         notification.defaultResponse = defaultResponse;
2014         notification.requestorId = requestorId;
2015         notification.text = text;
2016         notification.requestorIdEncoding = requestorIdEncoding;
2017         notification.textEncoding = textEncoding;
2018
2019         // Process extras, assuming the format is
2020         // one of more lines of "key = value"
2021         Bundle bundle = new Bundle();
2022
2023         if (extras == null) extras = "";
2024         Properties extraProp = new Properties();
2025
2026         try {
2027             extraProp.load(new StringReader(extras));
2028         }
2029         catch (IOException e)
2030         {
2031             Log.e(TAG, "reportNiNotification cannot parse extras data: " + extras);
2032         }
2033
2034         for (Entry<Object, Object> ent : extraProp.entrySet())
2035         {
2036             bundle.putString((String) ent.getKey(), (String) ent.getValue());
2037         }
2038
2039         notification.extras = bundle;
2040
2041         mNIHandler.handleNiNotification(notification);
2042     }
2043
2044     /**
2045      * Called from native code to request set id info.
2046      * We should be careful about receiving null string from the TelephonyManager,
2047      * because sending null String to JNI function would cause a crash.
2048      */
2049
2050     private void requestSetID(int flags) {
2051         TelephonyManager phone = (TelephonyManager)
2052                 mContext.getSystemService(Context.TELEPHONY_SERVICE);
2053         int type = AGPS_SETID_TYPE_NONE;
2054         String data = "";
2055
2056         if ((flags & AGPS_RIL_REQUEST_SETID_IMSI) == AGPS_RIL_REQUEST_SETID_IMSI) {
2057             String data_temp = phone.getSubscriberId();
2058             if (data_temp == null) {
2059                 // This means the framework does not have the SIM card ready.
2060             } else {
2061                 // This means the framework has the SIM card.
2062                 data = data_temp;
2063                 type = AGPS_SETID_TYPE_IMSI;
2064             }
2065         }
2066         else if ((flags & AGPS_RIL_REQUEST_SETID_MSISDN) == AGPS_RIL_REQUEST_SETID_MSISDN) {
2067             String data_temp = phone.getLine1Number();
2068             if (data_temp == null) {
2069                 // This means the framework does not have the SIM card ready.
2070             } else {
2071                 // This means the framework has the SIM card.
2072                 data = data_temp;
2073                 type = AGPS_SETID_TYPE_MSISDN;
2074             }
2075         }
2076         native_agps_set_id(type, data);
2077     }
2078
2079     /**
2080      * Called from native code to request utc time info
2081      */
2082     private void requestUtcTime() {
2083         if (DEBUG) Log.d(TAG, "utcTimeRequest");
2084         sendMessage(INJECT_NTP_TIME, 0, null);
2085     }
2086
2087     /**
2088      * Called from native code to request reference location info
2089      */
2090
2091     private void requestRefLocation(int flags) {
2092         TelephonyManager phone = (TelephonyManager)
2093                 mContext.getSystemService(Context.TELEPHONY_SERVICE);
2094         final int phoneType = phone.getPhoneType();
2095         if (phoneType == TelephonyManager.PHONE_TYPE_GSM) {
2096             GsmCellLocation gsm_cell = (GsmCellLocation) phone.getCellLocation();
2097             if ((gsm_cell != null) && (phone.getNetworkOperator() != null)
2098                     && (phone.getNetworkOperator().length() > 3)) {
2099                 int type;
2100                 int mcc = Integer.parseInt(phone.getNetworkOperator().substring(0,3));
2101                 int mnc = Integer.parseInt(phone.getNetworkOperator().substring(3));
2102                 int networkType = phone.getNetworkType();
2103                 if (networkType == TelephonyManager.NETWORK_TYPE_UMTS
2104                     || networkType == TelephonyManager.NETWORK_TYPE_HSDPA
2105                     || networkType == TelephonyManager.NETWORK_TYPE_HSUPA
2106                     || networkType == TelephonyManager.NETWORK_TYPE_HSPA
2107                     || networkType == TelephonyManager.NETWORK_TYPE_HSPAP) {
2108                     type = AGPS_REF_LOCATION_TYPE_UMTS_CELLID;
2109                 } else {
2110                     type = AGPS_REF_LOCATION_TYPE_GSM_CELLID;
2111                 }
2112                 native_agps_set_ref_location_cellid(type, mcc, mnc,
2113                         gsm_cell.getLac(), gsm_cell.getCid(), gsm_cell.getPsc());
2114             } else {
2115                 Log.e(TAG,"Error getting cell location info.");
2116             }
2117         } else if (phoneType == TelephonyManager.PHONE_TYPE_CDMA) {
2118             Log.e(TAG, "CDMA not supported.");
2119         }
2120     }
2121
2122     private void sendMessage(int message, int arg, Object obj) {
2123         // hold a wake lock until this message is delivered
2124         // note that this assumes the message will not be removed from the queue before
2125         // it is handled (otherwise the wake lock would be leaked).
2126         mWakeLock.acquire();
2127         Log.i(TAG, "WakeLock acquired by sendMessage(" + message + ", " + arg + ", " + obj + ")");
2128         mHandler.obtainMessage(message, arg, 1, obj).sendToTarget();
2129     }
2130
2131     private final class ProviderHandler extends Handler {
2132         public ProviderHandler(Looper looper) {
2133             super(looper, null, true /*async*/);
2134         }
2135
2136         @Override
2137         public void handleMessage(Message msg) {
2138             int message = msg.what;
2139             switch (message) {
2140                 case ENABLE:
2141                     if (msg.arg1 == 1) {
2142                         handleEnable();
2143                     } else {
2144                         handleDisable();
2145                     }
2146                     break;
2147                 case SET_REQUEST:
2148                     GpsRequest gpsRequest = (GpsRequest) msg.obj;
2149                     handleSetRequest(gpsRequest.request, gpsRequest.source);
2150                     break;
2151                 case UPDATE_NETWORK_STATE:
2152                     handleUpdateNetworkState((Network) msg.obj);
2153                     break;
2154                 case REQUEST_SUPL_CONNECTION:
2155                     handleRequestSuplConnection((InetAddress) msg.obj);
2156                     break;
2157                 case RELEASE_SUPL_CONNECTION:
2158                     handleReleaseSuplConnection(msg.arg1);
2159                     break;
2160                 case INJECT_NTP_TIME:
2161                     handleInjectNtpTime();
2162                     break;
2163                 case DOWNLOAD_XTRA_DATA:
2164                     handleDownloadXtraData();
2165                     break;
2166                 case INJECT_NTP_TIME_FINISHED:
2167                     mInjectNtpTimePending = STATE_IDLE;
2168                     break;
2169                 case DOWNLOAD_XTRA_DATA_FINISHED:
2170                     mDownloadXtraDataPending = STATE_IDLE;
2171                     break;
2172                 case UPDATE_LOCATION:
2173                     handleUpdateLocation((Location) msg.obj);
2174                     break;
2175                 case SUBSCRIPTION_OR_SIM_CHANGED:
2176                     subscriptionOrSimChanged(mContext);
2177                     break;
2178                 case INITIALIZE_HANDLER:
2179                     handleInitialize();
2180                     break;
2181             }
2182             if (msg.arg2 == 1) {
2183                 // wakelock was taken for this message, release it
2184                 mWakeLock.release();
2185                 Log.i(TAG, "WakeLock released by handleMessage(" + message + ", " + msg.arg1 + ", "
2186                         + msg.obj + ")");
2187             }
2188         }
2189
2190         /**
2191          * This method is bound to {@link #GnssLocationProvider(Context, ILocationManager, Looper)}.
2192          * It is in charge of loading properties and registering for events that will be posted to
2193          * this handler.
2194          */
2195         private void handleInitialize() {
2196             // load default GPS configuration
2197             // (this configuration might change in the future based on SIM changes)
2198             reloadGpsProperties(mContext, mProperties);
2199
2200             // TODO: When this object "finishes" we should unregister by invoking
2201             // SubscriptionManager.getInstance(mContext).unregister(mOnSubscriptionsChangedListener);
2202             // This is not strictly necessary because it will be unregistered if the
2203             // notification fails but it is good form.
2204
2205             // Register for SubscriptionInfo list changes which is guaranteed
2206             // to invoke onSubscriptionsChanged the first time.
2207             SubscriptionManager.from(mContext)
2208                     .addOnSubscriptionsChangedListener(mOnSubscriptionsChangedListener);
2209
2210             // listen for events
2211             IntentFilter intentFilter;
2212             if (native_is_agps_ril_supported()) {
2213                 intentFilter = new IntentFilter();
2214                 intentFilter.addAction(Intents.DATA_SMS_RECEIVED_ACTION);
2215                 intentFilter.addDataScheme("sms");
2216                 intentFilter.addDataAuthority("localhost", "7275");
2217                 mContext.registerReceiver(mBroadcastReceiver, intentFilter, null, this);
2218
2219                 intentFilter = new IntentFilter();
2220                 intentFilter.addAction(Intents.WAP_PUSH_RECEIVED_ACTION);
2221                 try {
2222                     intentFilter.addDataType("application/vnd.omaloc-supl-init");
2223                 } catch (IntentFilter.MalformedMimeTypeException e) {
2224                     Log.w(TAG, "Malformed SUPL init mime type");
2225                 }
2226                 mContext.registerReceiver(mBroadcastReceiver, intentFilter, null, this);
2227             } else if (DEBUG) {
2228                 Log.d(TAG, "Skipped registration for SMS/WAP-PUSH messages because AGPS Ril in GPS"
2229                         + " HAL is not supported");
2230             }
2231
2232             intentFilter = new IntentFilter();
2233             intentFilter.addAction(ALARM_WAKEUP);
2234             intentFilter.addAction(ALARM_TIMEOUT);
2235             intentFilter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
2236             intentFilter.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
2237             intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
2238             intentFilter.addAction(Intent.ACTION_SCREEN_ON);
2239             intentFilter.addAction(SIM_STATE_CHANGED);
2240             mContext.registerReceiver(mBroadcastReceiver, intentFilter, null, this);
2241
2242             // register for connectivity change events, this is equivalent to the deprecated way of
2243             // registering for CONNECTIVITY_ACTION broadcasts
2244             NetworkRequest.Builder networkRequestBuilder = new NetworkRequest.Builder();
2245             networkRequestBuilder.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
2246             networkRequestBuilder.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
2247             NetworkRequest networkRequest = networkRequestBuilder.build();
2248             mConnMgr.registerNetworkCallback(networkRequest, mNetworkConnectivityCallback);
2249
2250             // listen for PASSIVE_PROVIDER updates
2251             LocationManager locManager =
2252                     (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
2253             long minTime = 0;
2254             float minDistance = 0;
2255             boolean oneShot = false;
2256             LocationRequest request = LocationRequest.createFromDeprecatedProvider(
2257                     LocationManager.PASSIVE_PROVIDER,
2258                     minTime,
2259                     minDistance,
2260                     oneShot);
2261             // Don't keep track of this request since it's done on behalf of other clients
2262             // (which are kept track of separately).
2263             request.setHideFromAppOps(true);
2264             locManager.requestLocationUpdates(
2265                     request,
2266                     new NetworkLocationListener(),
2267                     getLooper());
2268         }
2269     }
2270
2271     private final class NetworkLocationListener implements LocationListener {
2272         @Override
2273         public void onLocationChanged(Location location) {
2274             // this callback happens on mHandler looper
2275             if (LocationManager.NETWORK_PROVIDER.equals(location.getProvider())) {
2276                 handleUpdateLocation(location);
2277             }
2278         }
2279         @Override
2280         public void onStatusChanged(String provider, int status, Bundle extras) { }
2281         @Override
2282         public void onProviderEnabled(String provider) { }
2283         @Override
2284         public void onProviderDisabled(String provider) { }
2285     }
2286
2287     private String getSelectedApn() {
2288         Uri uri = Uri.parse("content://telephony/carriers/preferapn");
2289         Cursor cursor = null;
2290         try {
2291             cursor = mContext.getContentResolver().query(
2292                     uri,
2293                     new String[] { "apn" },
2294                     null /* selection */,
2295                     null /* selectionArgs */,
2296                     Carriers.DEFAULT_SORT_ORDER);
2297             if (cursor != null && cursor.moveToFirst()) {
2298                 return cursor.getString(0);
2299             } else {
2300                 Log.e(TAG, "No APN found to select.");
2301             }
2302         } catch (Exception e) {
2303             Log.e(TAG, "Error encountered on selecting the APN.", e);
2304         } finally {
2305             if (cursor != null) {
2306                 cursor.close();
2307             }
2308         }
2309
2310         return null;
2311     }
2312
2313     private int getApnIpType(String apn) {
2314         ensureInHandlerThread();
2315         if (apn == null) {
2316             return APN_INVALID;
2317         }
2318
2319         String selection = String.format("current = 1 and apn = '%s' and carrier_enabled = 1", apn);
2320         Cursor cursor = null;
2321         try {
2322             cursor = mContext.getContentResolver().query(
2323                     Carriers.CONTENT_URI,
2324                     new String[] { Carriers.PROTOCOL },
2325                     selection,
2326                     null,
2327                     Carriers.DEFAULT_SORT_ORDER);
2328
2329             if (null != cursor && cursor.moveToFirst()) {
2330                 return translateToApnIpType(cursor.getString(0), apn);
2331             } else {
2332                 Log.e(TAG, "No entry found in query for APN: " + apn);
2333             }
2334         } catch (Exception e) {
2335             Log.e(TAG, "Error encountered on APN query for: " + apn, e);
2336         } finally {
2337             if (cursor != null) {
2338                 cursor.close();
2339             }
2340         }
2341
2342         return APN_INVALID;
2343     }
2344
2345     private int translateToApnIpType(String ipProtocol, String apn) {
2346         if ("IP".equals(ipProtocol)) {
2347             return APN_IPV4;
2348         }
2349         if ("IPV6".equals(ipProtocol)) {
2350             return APN_IPV6;
2351         }
2352         if ("IPV4V6".equals(ipProtocol)) {
2353             return APN_IPV4V6;
2354         }
2355
2356         // we hit the default case so the ipProtocol is not recognized
2357         String message = String.format("Unknown IP Protocol: %s, for APN: %s", ipProtocol, apn);
2358         Log.e(TAG, message);
2359         return APN_INVALID;
2360     }
2361
2362     private void setRouting() {
2363         if (mAGpsDataConnectionIpAddr == null) {
2364             return;
2365         }
2366
2367         // TODO: replace the use of this deprecated API
2368         boolean result = mConnMgr.requestRouteToHostAddress(
2369                 ConnectivityManager.TYPE_MOBILE_SUPL,
2370                 mAGpsDataConnectionIpAddr);
2371
2372         if (!result) {
2373             Log.e(TAG, "Error requesting route to host: " + mAGpsDataConnectionIpAddr);
2374         } else if (DEBUG) {
2375             Log.d(TAG, "Successfully requested route to host: " + mAGpsDataConnectionIpAddr);
2376         }
2377     }
2378
2379     /**
2380      * @return {@code true} if there is a data network available for outgoing connections,
2381      *         {@code false} otherwise.
2382      */
2383     private boolean isDataNetworkConnected() {
2384         NetworkInfo activeNetworkInfo = mConnMgr.getActiveNetworkInfo();
2385         return activeNetworkInfo != null && activeNetworkInfo.isConnected();
2386     }
2387
2388     /**
2389      * Ensures the calling function is running in the thread associated with {@link #mHandler}.
2390      */
2391     private void ensureInHandlerThread() {
2392         if (mHandler != null && Looper.myLooper() == mHandler.getLooper()) {
2393             return;
2394         }
2395         throw new RuntimeException("This method must run on the Handler thread.");
2396     }
2397
2398     /**
2399      * @return A string representing the current state stored in {@link #mAGpsDataConnectionState}.
2400      */
2401     private String agpsDataConnStateAsString() {
2402         switch(mAGpsDataConnectionState) {
2403             case AGPS_DATA_CONNECTION_CLOSED:
2404                 return "CLOSED";
2405             case AGPS_DATA_CONNECTION_OPEN:
2406                 return "OPEN";
2407             case AGPS_DATA_CONNECTION_OPENING:
2408                 return "OPENING";
2409             default:
2410                 return "<Unknown>";
2411         }
2412     }
2413
2414     /**
2415      * @return A string representing the given GPS_AGPS_DATA status.
2416      */
2417     private String agpsDataConnStatusAsString(int agpsDataConnStatus) {
2418         switch (agpsDataConnStatus) {
2419             case GPS_AGPS_DATA_CONNECTED:
2420                 return "CONNECTED";
2421             case GPS_AGPS_DATA_CONN_DONE:
2422                 return "DONE";
2423             case GPS_AGPS_DATA_CONN_FAILED:
2424                 return "FAILED";
2425             case GPS_RELEASE_AGPS_DATA_CONN:
2426                 return "RELEASE";
2427             case GPS_REQUEST_AGPS_DATA_CONN:
2428                 return "REQUEST";
2429             default:
2430                 return "<Unknown>";
2431         }
2432     }
2433
2434     @Override
2435     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2436         StringBuilder s = new StringBuilder();
2437         s.append("  mFixInterval=").append(mFixInterval).append('\n');
2438         s.append("  mDisableGps (battery saver mode)=").append(mDisableGps).append('\n');
2439         s.append("  mEngineCapabilities=0x").append(Integer.toHexString(mEngineCapabilities));
2440         s.append(" ( ");
2441         if (hasCapability(GPS_CAPABILITY_SCHEDULING)) s.append("SCHEDULING ");
2442         if (hasCapability(GPS_CAPABILITY_MSB)) s.append("MSB ");
2443         if (hasCapability(GPS_CAPABILITY_MSA)) s.append("MSA ");
2444         if (hasCapability(GPS_CAPABILITY_SINGLE_SHOT)) s.append("SINGLE_SHOT ");
2445         if (hasCapability(GPS_CAPABILITY_ON_DEMAND_TIME)) s.append("ON_DEMAND_TIME ");
2446         if (hasCapability(GPS_CAPABILITY_GEOFENCING)) s.append("GEOFENCING ");
2447         if (hasCapability(GPS_CAPABILITY_MEASUREMENTS)) s.append("MEASUREMENTS ");
2448         if (hasCapability(GPS_CAPABILITY_NAV_MESSAGES)) s.append("NAV_MESSAGES ");
2449         s.append(")\n");
2450
2451         s.append(native_get_internal_state());
2452         pw.append(s);
2453     }
2454
2455     /**
2456      * A simple implementation of exponential backoff.
2457      */
2458     private static final class BackOff {
2459         private static final int MULTIPLIER = 2;
2460         private final long mInitIntervalMillis;
2461         private final long mMaxIntervalMillis;
2462         private long mCurrentIntervalMillis;
2463
2464         public BackOff(long initIntervalMillis, long maxIntervalMillis) {
2465             mInitIntervalMillis = initIntervalMillis;
2466             mMaxIntervalMillis = maxIntervalMillis;
2467
2468             mCurrentIntervalMillis = mInitIntervalMillis / MULTIPLIER;
2469         }
2470
2471         public long nextBackoffMillis() {
2472             if (mCurrentIntervalMillis > mMaxIntervalMillis) {
2473                 return mMaxIntervalMillis;
2474             }
2475
2476             mCurrentIntervalMillis *= MULTIPLIER;
2477             return mCurrentIntervalMillis;
2478         }
2479
2480         public void reset() {
2481             mCurrentIntervalMillis = mInitIntervalMillis / MULTIPLIER;
2482         }
2483     }
2484
2485     // for GPS SV statistics
2486     private static final int MAX_SVS = 64;
2487
2488     // preallocated arrays, to avoid memory allocation in reportStatus()
2489     private int mSvidWithFlags[] = new int[MAX_SVS];
2490     private float mCn0s[] = new float[MAX_SVS];
2491     private float mSvElevations[] = new float[MAX_SVS];
2492     private float mSvAzimuths[] = new float[MAX_SVS];
2493     private int mSvCount;
2494     // preallocated to avoid memory allocation in reportNmea()
2495     private byte[] mNmeaBuffer = new byte[120];
2496
2497     static { class_init_native(); }
2498     private static native void class_init_native();
2499     private static native boolean native_is_supported();
2500     private static native boolean native_is_agps_ril_supported();
2501     private static native boolean native_is_gnss_configuration_supported();
2502
2503     private native boolean native_init();
2504     private native void native_cleanup();
2505     private native boolean native_set_position_mode(int mode, int recurrence, int min_interval,
2506             int preferred_accuracy, int preferred_time);
2507     private native boolean native_start();
2508     private native boolean native_stop();
2509     private native void native_delete_aiding_data(int flags);
2510     // returns number of SVs
2511     // mask[0] is ephemeris mask and mask[1] is almanac mask
2512     private native int native_read_sv_status(int[] prnWithFlags, float[] cn0s, float[] elevations,
2513             float[] azimuths);
2514     private native int native_read_nmea(byte[] buffer, int bufferSize);
2515     private native void native_inject_location(double latitude, double longitude, float accuracy);
2516
2517     // XTRA Support
2518     private native void native_inject_time(long time, long timeReference, int uncertainty);
2519     private native boolean native_supports_xtra();
2520     private native void native_inject_xtra_data(byte[] data, int length);
2521
2522     // DEBUG Support
2523     private native String native_get_internal_state();
2524
2525     // AGPS Support
2526     private native void native_agps_data_conn_open(String apn, int apnIpType);
2527     private native void native_agps_data_conn_closed();
2528     private native void native_agps_data_conn_failed();
2529     private native void native_agps_ni_message(byte [] msg, int length);
2530     private native void native_set_agps_server(int type, String hostname, int port);
2531
2532     // Network-initiated (NI) Support
2533     private native void native_send_ni_response(int notificationId, int userResponse);
2534
2535     // AGPS ril suport
2536     private native void native_agps_set_ref_location_cellid(int type, int mcc, int mnc,
2537             int lac, int cid, int psc);
2538     private native void native_agps_set_id(int type, String setid);
2539
2540     private native void native_update_network_state(boolean connected, int type,
2541             boolean roaming, boolean available, String extraInfo, String defaultAPN);
2542
2543     // Hardware Geofence support.
2544     private static native boolean native_is_geofence_supported();
2545     private static native boolean native_add_geofence(int geofenceId, double latitude,
2546             double longitude, double radius, int lastTransition,int monitorTransitions,
2547             int notificationResponsivenes, int unknownTimer);
2548     private static native boolean native_remove_geofence(int geofenceId);
2549     private static native boolean native_resume_geofence(int geofenceId, int transitions);
2550     private static native boolean native_pause_geofence(int geofenceId);
2551
2552     // Gps Hal measurements support.
2553     private static native boolean native_is_measurement_supported();
2554     private native boolean native_start_measurement_collection();
2555     private native boolean native_stop_measurement_collection();
2556
2557     // Gps Navigation message support.
2558     private static native boolean native_is_navigation_message_supported();
2559     private native boolean native_start_navigation_message_collection();
2560     private native boolean native_stop_navigation_message_collection();
2561
2562     // GNSS Configuration
2563     private static native void native_configuration_update(String configData);
2564 }