OSDN Git Service

2228b3fe72c6427a91317b7e108e1be58fb76048
[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         sendMessage(INITIALIZE_HANDLER, 0, null);
752
753         // Create a GPS net-initiated handler.
754         mNIHandler = new GpsNetInitiatedHandler(context,
755                                                 mNetInitiatedListener,
756                                                 mSuplEsEnabled);
757
758         mListenerHelper = new GnssStatusListenerHelper(mHandler) {
759             @Override
760             protected boolean isAvailableInPlatform() {
761                 return isSupported();
762             }
763
764             @Override
765             protected boolean isGpsEnabled() {
766                 return isEnabled();
767             }
768         };
769
770         mGnssMeasurementsProvider = new GnssMeasurementsProvider(mHandler) {
771             @Override
772             public boolean isAvailableInPlatform() {
773                 return native_is_measurement_supported();
774             }
775
776             @Override
777             protected boolean registerWithService() {
778                 return native_start_measurement_collection();
779             }
780
781             @Override
782             protected void unregisterFromService() {
783                 native_stop_measurement_collection();
784             }
785
786             @Override
787             protected boolean isGpsEnabled() {
788                 return isEnabled();
789             }
790         };
791
792         mGnssNavigationMessageProvider = new GnssNavigationMessageProvider(mHandler) {
793             @Override
794             protected boolean isAvailableInPlatform() {
795                 return native_is_navigation_message_supported();
796             }
797
798             @Override
799             protected boolean registerWithService() {
800                 return native_start_navigation_message_collection();
801             }
802
803             @Override
804             protected void unregisterFromService() {
805                 native_stop_navigation_message_collection();
806             }
807
808             @Override
809             protected boolean isGpsEnabled() {
810                 return isEnabled();
811             }
812         };
813     }
814
815     /**
816      * Returns the name of this provider.
817      */
818     @Override
819     public String getName() {
820         return LocationManager.GPS_PROVIDER;
821     }
822
823     @Override
824     public ProviderProperties getProperties() {
825         return PROPERTIES;
826     }
827
828     private void handleUpdateNetworkState(Network network) {
829         // retrieve NetworkInfo for this UID
830         NetworkInfo info = mConnMgr.getNetworkInfo(network);
831         if (info == null) {
832             return;
833         }
834
835         boolean isConnected = info.isConnected();
836         if (DEBUG) {
837             String message = String.format(
838                     "UpdateNetworkState, state=%s, connected=%s, info=%s, capabilities=%S",
839                     agpsDataConnStateAsString(),
840                     isConnected,
841                     info,
842                     mConnMgr.getNetworkCapabilities(network));
843             Log.d(TAG, message);
844         }
845
846         if (native_is_agps_ril_supported()) {
847             boolean dataEnabled = TelephonyManager.getDefault().getDataEnabled();
848             boolean networkAvailable = info.isAvailable() && dataEnabled;
849             String defaultApn = getSelectedApn();
850             if (defaultApn == null) {
851                 defaultApn = "dummy-apn";
852             }
853
854             native_update_network_state(
855                     isConnected,
856                     info.getType(),
857                     info.isRoaming(),
858                     networkAvailable,
859                     info.getExtraInfo(),
860                     defaultApn);
861         } else if (DEBUG) {
862             Log.d(TAG, "Skipped network state update because GPS HAL AGPS-RIL is not  supported");
863         }
864
865         if (mAGpsDataConnectionState == AGPS_DATA_CONNECTION_OPENING) {
866             if (isConnected) {
867                 String apnName = info.getExtraInfo();
868                 if (apnName == null) {
869                     // assign a dummy value in the case of C2K as otherwise we will have a runtime
870                     // exception in the following call to native_agps_data_conn_open
871                     apnName = "dummy-apn";
872                 }
873                 int apnIpType = getApnIpType(apnName);
874                 setRouting();
875                 if (DEBUG) {
876                     String message = String.format(
877                             "native_agps_data_conn_open: mAgpsApn=%s, mApnIpType=%s",
878                             apnName,
879                             apnIpType);
880                     Log.d(TAG, message);
881                 }
882                 native_agps_data_conn_open(apnName, apnIpType);
883                 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPEN;
884             } else {
885                 handleReleaseSuplConnection(GPS_AGPS_DATA_CONN_FAILED);
886             }
887         }
888     }
889
890     private void handleRequestSuplConnection(InetAddress address) {
891         if (DEBUG) {
892             String message = String.format(
893                     "requestSuplConnection, state=%s, address=%s",
894                     agpsDataConnStateAsString(),
895                     address);
896             Log.d(TAG, message);
897         }
898
899         if (mAGpsDataConnectionState != AGPS_DATA_CONNECTION_CLOSED) {
900             return;
901         }
902         mAGpsDataConnectionIpAddr = address;
903         mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPENING;
904
905         NetworkRequest.Builder requestBuilder = new NetworkRequest.Builder();
906         requestBuilder.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
907         requestBuilder.addCapability(NetworkCapabilities.NET_CAPABILITY_SUPL);
908         NetworkRequest request = requestBuilder.build();
909         mConnMgr.requestNetwork(
910                 request,
911                 mSuplConnectivityCallback,
912                 ConnectivityManager.MAX_NETWORK_REQUEST_TIMEOUT_MS);
913     }
914
915     private void handleReleaseSuplConnection(int agpsDataConnStatus) {
916         if (DEBUG) {
917             String message = String.format(
918                     "releaseSuplConnection, state=%s, status=%s",
919                     agpsDataConnStateAsString(),
920                     agpsDataConnStatusAsString(agpsDataConnStatus));
921             Log.d(TAG, message);
922         }
923
924         if (mAGpsDataConnectionState == AGPS_DATA_CONNECTION_CLOSED) {
925             return;
926         }
927         mAGpsDataConnectionState = AGPS_DATA_CONNECTION_CLOSED;
928
929         mConnMgr.unregisterNetworkCallback(mSuplConnectivityCallback);
930         switch (agpsDataConnStatus) {
931             case GPS_AGPS_DATA_CONN_FAILED:
932                 native_agps_data_conn_failed();
933                 break;
934             case GPS_RELEASE_AGPS_DATA_CONN:
935                 native_agps_data_conn_closed();
936                 break;
937             default:
938                 Log.e(TAG, "Invalid status to release SUPL connection: " + agpsDataConnStatus);
939         }
940     }
941
942     private void handleInjectNtpTime() {
943         if (mInjectNtpTimePending == STATE_DOWNLOADING) {
944             // already downloading data
945             return;
946         }
947         if (!isDataNetworkConnected()) {
948             // try again when network is up
949             mInjectNtpTimePending = STATE_PENDING_NETWORK;
950             return;
951         }
952         mInjectNtpTimePending = STATE_DOWNLOADING;
953
954         // hold wake lock while task runs
955         mWakeLock.acquire();
956         Log.i(TAG, "WakeLock acquired by handleInjectNtpTime()");
957         AsyncTask.THREAD_POOL_EXECUTOR.execute(new Runnable() {
958             @Override
959             public void run() {
960                 long delay;
961
962                 // force refresh NTP cache when outdated
963                 boolean refreshSuccess = true;
964                 if (mNtpTime.getCacheAge() >= NTP_INTERVAL) {
965                     refreshSuccess = mNtpTime.forceRefresh();
966                 }
967
968                 // only update when NTP time is fresh
969                 if (mNtpTime.getCacheAge() < NTP_INTERVAL) {
970                     long time = mNtpTime.getCachedNtpTime();
971                     long timeReference = mNtpTime.getCachedNtpTimeReference();
972                     long certainty = mNtpTime.getCacheCertainty();
973                     long now = System.currentTimeMillis();
974
975                     if (DEBUG) {
976                         Log.d(TAG, "NTP server returned: "
977                                 + time + " (" + new Date(time)
978                                 + ") reference: " + timeReference
979                                 + " certainty: " + certainty
980                                 + " system time offset: " + (time - now));
981                     }
982
983                     native_inject_time(time, timeReference, (int) certainty);
984                     delay = NTP_INTERVAL;
985                     mNtpBackOff.reset();
986                 } else {
987                     Log.e(TAG, "requestTime failed");
988                     delay = mNtpBackOff.nextBackoffMillis();
989                 }
990
991                 sendMessage(INJECT_NTP_TIME_FINISHED, 0, null);
992
993                 if (DEBUG) {
994                     String message = String.format(
995                             "onDemandTimeInjection=%s, refreshSuccess=%s, delay=%s",
996                             mOnDemandTimeInjection,
997                             refreshSuccess,
998                             delay);
999                     Log.d(TAG, message);
1000                 }
1001                 if (mOnDemandTimeInjection || !refreshSuccess) {
1002                     // send delayed message for next NTP injection
1003                     // since this is delayed and not urgent we do not hold a wake lock here
1004                     mHandler.sendEmptyMessageDelayed(INJECT_NTP_TIME, delay);
1005                 }
1006
1007                 // release wake lock held by task
1008                 mWakeLock.release();
1009                 Log.i(TAG, "WakeLock released by handleInjectNtpTime()");
1010             }
1011         });
1012     }
1013
1014     private void handleDownloadXtraData() {
1015         if (!mSupportsXtra) {
1016             // native code reports xtra not supported, don't try
1017             Log.d(TAG, "handleDownloadXtraData() called when Xtra not supported");
1018             return;
1019         }
1020         if (mDownloadXtraDataPending == STATE_DOWNLOADING) {
1021             // already downloading data
1022             return;
1023         }
1024         if (!isDataNetworkConnected()) {
1025             // try again when network is up
1026             mDownloadXtraDataPending = STATE_PENDING_NETWORK;
1027             return;
1028         }
1029         mDownloadXtraDataPending = STATE_DOWNLOADING;
1030
1031         // hold wake lock while task runs
1032         mWakeLock.acquire();
1033         Log.i(TAG, "WakeLock acquired by handleDownloadXtraData()");
1034         AsyncTask.THREAD_POOL_EXECUTOR.execute(new Runnable() {
1035             @Override
1036             public void run() {
1037                 GpsXtraDownloader xtraDownloader = new GpsXtraDownloader(mProperties);
1038                 byte[] data = xtraDownloader.downloadXtraData();
1039                 if (data != null) {
1040                     if (DEBUG) Log.d(TAG, "calling native_inject_xtra_data");
1041                     native_inject_xtra_data(data, data.length);
1042                     mXtraBackOff.reset();
1043                 }
1044
1045                 sendMessage(DOWNLOAD_XTRA_DATA_FINISHED, 0, null);
1046
1047                 if (data == null) {
1048                     // try again later
1049                     // since this is delayed and not urgent we do not hold a wake lock here
1050                     mHandler.sendEmptyMessageDelayed(DOWNLOAD_XTRA_DATA,
1051                             mXtraBackOff.nextBackoffMillis());
1052                 }
1053
1054                 // release wake lock held by task
1055                 mWakeLock.release();
1056                 Log.i(TAG, "WakeLock released by handleDownloadXtraData()");
1057             }
1058         });
1059     }
1060
1061     private void handleUpdateLocation(Location location) {
1062         if (location.hasAccuracy()) {
1063             native_inject_location(location.getLatitude(), location.getLongitude(),
1064                     location.getAccuracy());
1065         }
1066     }
1067
1068     /**
1069      * Enables this provider.  When enabled, calls to getStatus()
1070      * must be handled.  Hardware may be started up
1071      * when the provider is enabled.
1072      */
1073     @Override
1074     public void enable() {
1075         synchronized (mLock) {
1076             if (mEnabled) return;
1077             mEnabled = true;
1078         }
1079
1080         sendMessage(ENABLE, 1, null);
1081     }
1082
1083     private void setSuplHostPort(String hostString, String portString) {
1084         if (hostString != null) {
1085             mSuplServerHost = hostString;
1086         }
1087         if (portString != null) {
1088             try {
1089                 mSuplServerPort = Integer.parseInt(portString);
1090             } catch (NumberFormatException e) {
1091                 Log.e(TAG, "unable to parse SUPL_PORT: " + portString);
1092             }
1093         }
1094         if (mSuplServerHost != null
1095                 && mSuplServerPort > TCP_MIN_PORT
1096                 && mSuplServerPort <= TCP_MAX_PORT) {
1097             native_set_agps_server(AGPS_TYPE_SUPL, mSuplServerHost, mSuplServerPort);
1098         }
1099     }
1100
1101     /**
1102      * Checks what SUPL mode to use, according to the AGPS mode as well as the
1103      * allowed mode from properties.
1104      *
1105      * @param properties GPS properties
1106      * @param agpsEnabled whether AGPS is enabled by settings value
1107      * @param singleShot whether "singleshot" is needed
1108      * @return SUPL mode (MSA vs MSB vs STANDALONE)
1109      */
1110     private int getSuplMode(Properties properties, boolean agpsEnabled, boolean singleShot) {
1111         if (agpsEnabled) {
1112             String modeString = properties.getProperty("SUPL_MODE");
1113             int suplMode = 0;
1114             if (!TextUtils.isEmpty(modeString)) {
1115                 try {
1116                     suplMode = Integer.parseInt(modeString);
1117                 } catch (NumberFormatException e) {
1118                     Log.e(TAG, "unable to parse SUPL_MODE: " + modeString);
1119                     return GPS_POSITION_MODE_STANDALONE;
1120                 }
1121             }
1122             // MS-Based is the preferred mode for Assisted-GPS position computation, so we favor
1123             // such mode when it is available
1124             if (hasCapability(GPS_CAPABILITY_MSB) && (suplMode & AGPS_SUPL_MODE_MSB) != 0) {
1125                 return GPS_POSITION_MODE_MS_BASED;
1126             }
1127             // for now, just as the legacy code did, we fallback to MS-Assisted if it is available,
1128             // do fallback only for single-shot requests, because it is too expensive to do for
1129             // periodic requests as well
1130             if (singleShot
1131                     && hasCapability(GPS_CAPABILITY_MSA)
1132                     && (suplMode & AGPS_SUPL_MODE_MSA) != 0) {
1133                 return GPS_POSITION_MODE_MS_ASSISTED;
1134             }
1135         }
1136         return GPS_POSITION_MODE_STANDALONE;
1137     }
1138
1139     private void handleEnable() {
1140         if (DEBUG) Log.d(TAG, "handleEnable");
1141
1142         boolean enabled = native_init();
1143
1144         if (enabled) {
1145             mSupportsXtra = native_supports_xtra();
1146
1147             // TODO: remove the following native calls if we can make sure they are redundant.
1148             if (mSuplServerHost != null) {
1149                 native_set_agps_server(AGPS_TYPE_SUPL, mSuplServerHost, mSuplServerPort);
1150             }
1151             if (mC2KServerHost != null) {
1152                 native_set_agps_server(AGPS_TYPE_C2K, mC2KServerHost, mC2KServerPort);
1153             }
1154
1155             mGnssMeasurementsProvider.onGpsEnabledChanged();
1156             mGnssNavigationMessageProvider.onGpsEnabledChanged();
1157         } else {
1158             synchronized (mLock) {
1159                 mEnabled = false;
1160             }
1161             Log.w(TAG, "Failed to enable location provider");
1162         }
1163     }
1164
1165     /**
1166      * Disables this provider.  When disabled, calls to getStatus()
1167      * need not be handled.  Hardware may be shut
1168      * down while the provider is disabled.
1169      */
1170     @Override
1171     public void disable() {
1172         synchronized (mLock) {
1173             if (!mEnabled) return;
1174             mEnabled = false;
1175         }
1176
1177         sendMessage(ENABLE, 0, null);
1178     }
1179
1180     private void handleDisable() {
1181         if (DEBUG) Log.d(TAG, "handleDisable");
1182
1183         updateClientUids(new WorkSource());
1184         stopNavigating();
1185         mAlarmManager.cancel(mWakeupIntent);
1186         mAlarmManager.cancel(mTimeoutIntent);
1187
1188         // do this before releasing wakelock
1189         native_cleanup();
1190
1191         mGnssMeasurementsProvider.onGpsEnabledChanged();
1192         mGnssNavigationMessageProvider.onGpsEnabledChanged();
1193     }
1194
1195     @Override
1196     public boolean isEnabled() {
1197         synchronized (mLock) {
1198             return mEnabled;
1199         }
1200     }
1201
1202     @Override
1203     public int getStatus(Bundle extras) {
1204         if (extras != null) {
1205             extras.putInt("satellites", mSvCount);
1206         }
1207         return mStatus;
1208     }
1209
1210     private void updateStatus(int status, int svCount) {
1211         if (status != mStatus || svCount != mSvCount) {
1212             mStatus = status;
1213             mSvCount = svCount;
1214             mLocationExtras.putInt("satellites", svCount);
1215             mStatusUpdateTime = SystemClock.elapsedRealtime();
1216         }
1217     }
1218
1219     @Override
1220     public long getStatusUpdateTime() {
1221         return mStatusUpdateTime;
1222     }
1223
1224     @Override
1225     public void setRequest(ProviderRequest request, WorkSource source) {
1226         sendMessage(SET_REQUEST, 0, new GpsRequest(request, source));
1227     }
1228
1229     private void handleSetRequest(ProviderRequest request, WorkSource source) {
1230         mProviderRequest = request;
1231         mWorkSource = source;
1232         updateRequirements();
1233     }
1234
1235     // Called when the requirements for GPS may have changed
1236     private void updateRequirements() {
1237         if (mProviderRequest == null || mWorkSource == null) {
1238             return;
1239         }
1240
1241         boolean singleShot = false;
1242
1243         // see if the request is for a single update
1244         if (mProviderRequest.locationRequests != null
1245                 && mProviderRequest.locationRequests.size() > 0) {
1246             // if any request has zero or more than one updates
1247             // requested, then this is not single-shot mode
1248             singleShot = true;
1249
1250             for (LocationRequest lr : mProviderRequest.locationRequests) {
1251                 if (lr.getNumUpdates() != 1) {
1252                     singleShot = false;
1253                 }
1254             }
1255         }
1256
1257         if (DEBUG) Log.d(TAG, "setRequest " + mProviderRequest);
1258         if (mProviderRequest.reportLocation && !mDisableGps && isEnabled()) {
1259             // update client uids
1260             updateClientUids(mWorkSource);
1261
1262             mFixInterval = (int) mProviderRequest.interval;
1263
1264             // check for overflow
1265             if (mFixInterval != mProviderRequest.interval) {
1266                 Log.w(TAG, "interval overflow: " + mProviderRequest.interval);
1267                 mFixInterval = Integer.MAX_VALUE;
1268             }
1269
1270             // apply request to GPS engine
1271             if (mStarted && hasCapability(GPS_CAPABILITY_SCHEDULING)) {
1272                 // change period
1273                 if (!native_set_position_mode(mPositionMode, GPS_POSITION_RECURRENCE_PERIODIC,
1274                         mFixInterval, 0, 0)) {
1275                     Log.e(TAG, "set_position_mode failed in setMinTime()");
1276                 }
1277             } else if (!mStarted) {
1278                 // start GPS
1279                 startNavigating(singleShot);
1280             }
1281         } else {
1282             updateClientUids(new WorkSource());
1283
1284             stopNavigating();
1285             mAlarmManager.cancel(mWakeupIntent);
1286             mAlarmManager.cancel(mTimeoutIntent);
1287         }
1288     }
1289
1290     private void updateClientUids(WorkSource source) {
1291         // Update work source.
1292         WorkSource[] changes = mClientSource.setReturningDiffs(source);
1293         if (changes == null) {
1294             return;
1295         }
1296         WorkSource newWork = changes[0];
1297         WorkSource goneWork = changes[1];
1298
1299         // Update sources that were not previously tracked.
1300         if (newWork != null) {
1301             int lastuid = -1;
1302             for (int i=0; i<newWork.size(); i++) {
1303                 try {
1304                     int uid = newWork.get(i);
1305                     mAppOpsService.startOperation(AppOpsManager.getToken(mAppOpsService),
1306                             AppOpsManager.OP_GPS, uid, newWork.getName(i));
1307                     if (uid != lastuid) {
1308                         lastuid = uid;
1309                         mBatteryStats.noteStartGps(uid);
1310                     }
1311                 } catch (RemoteException e) {
1312                     Log.w(TAG, "RemoteException", e);
1313                 }
1314             }
1315         }
1316
1317         // Update sources that are no longer tracked.
1318         if (goneWork != null) {
1319             int lastuid = -1;
1320             for (int i=0; i<goneWork.size(); i++) {
1321                 try {
1322                     int uid = goneWork.get(i);
1323                     mAppOpsService.finishOperation(AppOpsManager.getToken(mAppOpsService),
1324                             AppOpsManager.OP_GPS, uid, goneWork.getName(i));
1325                     if (uid != lastuid) {
1326                         lastuid = uid;
1327                         mBatteryStats.noteStopGps(uid);
1328                     }
1329                 } catch (RemoteException e) {
1330                     Log.w(TAG, "RemoteException", e);
1331                 }
1332             }
1333         }
1334     }
1335
1336     @Override
1337     public boolean sendExtraCommand(String command, Bundle extras) {
1338
1339         long identity = Binder.clearCallingIdentity();
1340         boolean result = false;
1341
1342         if ("delete_aiding_data".equals(command)) {
1343             result = deleteAidingData(extras);
1344         } else if ("force_time_injection".equals(command)) {
1345             requestUtcTime();
1346             result = true;
1347         } else if ("force_xtra_injection".equals(command)) {
1348             if (mSupportsXtra) {
1349                 xtraDownloadRequest();
1350                 result = true;
1351             }
1352         } else {
1353             Log.w(TAG, "sendExtraCommand: unknown command " + command);
1354         }
1355
1356         Binder.restoreCallingIdentity(identity);
1357         return result;
1358     }
1359
1360     private IGpsGeofenceHardware mGpsGeofenceBinder = new IGpsGeofenceHardware.Stub() {
1361         public boolean isHardwareGeofenceSupported() {
1362             return native_is_geofence_supported();
1363         }
1364
1365         public boolean addCircularHardwareGeofence(int geofenceId, double latitude,
1366                 double longitude, double radius, int lastTransition, int monitorTransitions,
1367                 int notificationResponsiveness, int unknownTimer) {
1368             return native_add_geofence(geofenceId, latitude, longitude, radius,
1369                     lastTransition, monitorTransitions, notificationResponsiveness, unknownTimer);
1370         }
1371
1372         public boolean removeHardwareGeofence(int geofenceId) {
1373             return native_remove_geofence(geofenceId);
1374         }
1375
1376         public boolean pauseHardwareGeofence(int geofenceId) {
1377             return native_pause_geofence(geofenceId);
1378         }
1379
1380         public boolean resumeHardwareGeofence(int geofenceId, int monitorTransition) {
1381             return native_resume_geofence(geofenceId, monitorTransition);
1382         }
1383     };
1384
1385     private boolean deleteAidingData(Bundle extras) {
1386         int flags;
1387
1388         if (extras == null) {
1389             flags = GPS_DELETE_ALL;
1390         } else {
1391             flags = 0;
1392             if (extras.getBoolean("ephemeris")) flags |= GPS_DELETE_EPHEMERIS;
1393             if (extras.getBoolean("almanac")) flags |= GPS_DELETE_ALMANAC;
1394             if (extras.getBoolean("position")) flags |= GPS_DELETE_POSITION;
1395             if (extras.getBoolean("time")) flags |= GPS_DELETE_TIME;
1396             if (extras.getBoolean("iono")) flags |= GPS_DELETE_IONO;
1397             if (extras.getBoolean("utc")) flags |= GPS_DELETE_UTC;
1398             if (extras.getBoolean("health")) flags |= GPS_DELETE_HEALTH;
1399             if (extras.getBoolean("svdir")) flags |= GPS_DELETE_SVDIR;
1400             if (extras.getBoolean("svsteer")) flags |= GPS_DELETE_SVSTEER;
1401             if (extras.getBoolean("sadata")) flags |= GPS_DELETE_SADATA;
1402             if (extras.getBoolean("rti")) flags |= GPS_DELETE_RTI;
1403             if (extras.getBoolean("celldb-info")) flags |= GPS_DELETE_CELLDB_INFO;
1404             if (extras.getBoolean("all")) flags |= GPS_DELETE_ALL;
1405         }
1406
1407         if (flags != 0) {
1408             native_delete_aiding_data(flags);
1409             return true;
1410         }
1411
1412         return false;
1413     }
1414
1415     private void startNavigating(boolean singleShot) {
1416         if (!mStarted) {
1417             if (DEBUG) Log.d(TAG, "startNavigating, singleShot is " + singleShot);
1418             mTimeToFirstFix = 0;
1419             mLastFixTime = 0;
1420             mStarted = true;
1421             mSingleShot = singleShot;
1422             mPositionMode = GPS_POSITION_MODE_STANDALONE;
1423             // Notify about suppressed output, if speed limit was previously exceeded.
1424             // Elsewhere, we check again with every speed output reported.
1425             if (mItarSpeedLimitExceeded) {
1426                 Log.i(TAG, "startNavigating with ITAR limit in place. Output limited  " +
1427                         "until slow enough speed reported.");
1428             }
1429
1430             boolean agpsEnabled =
1431                     (Settings.Global.getInt(mContext.getContentResolver(),
1432                                             Settings.Global.ASSISTED_GPS_ENABLED, 1) != 0);
1433             mPositionMode = getSuplMode(mProperties, agpsEnabled, singleShot);
1434
1435             if (DEBUG) {
1436                 String mode;
1437
1438                 switch(mPositionMode) {
1439                     case GPS_POSITION_MODE_STANDALONE:
1440                         mode = "standalone";
1441                         break;
1442                     case GPS_POSITION_MODE_MS_ASSISTED:
1443                         mode = "MS_ASSISTED";
1444                         break;
1445                     case GPS_POSITION_MODE_MS_BASED:
1446                         mode = "MS_BASED";
1447                         break;
1448                     default:
1449                         mode = "unknown";
1450                         break;
1451                 }
1452                 Log.d(TAG, "setting position_mode to " + mode);
1453             }
1454
1455             int interval = (hasCapability(GPS_CAPABILITY_SCHEDULING) ? mFixInterval : 1000);
1456             if (!native_set_position_mode(mPositionMode, GPS_POSITION_RECURRENCE_PERIODIC,
1457                     interval, 0, 0)) {
1458                 mStarted = false;
1459                 Log.e(TAG, "set_position_mode failed in startNavigating()");
1460                 return;
1461             }
1462             if (!native_start()) {
1463                 mStarted = false;
1464                 Log.e(TAG, "native_start failed in startNavigating()");
1465                 return;
1466             }
1467
1468             // reset SV count to zero
1469             updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE, 0);
1470             mFixRequestTime = SystemClock.elapsedRealtime(); //return milliseconds since boot
1471             if (!hasCapability(GPS_CAPABILITY_SCHEDULING)) {
1472                 // set timer to give up if we do not receive a fix within NO_FIX_TIMEOUT
1473                 // and our fix interval is not short
1474                 if (mFixInterval >= NO_FIX_TIMEOUT) {
1475                     mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
1476                             SystemClock.elapsedRealtime() + NO_FIX_TIMEOUT, mTimeoutIntent);
1477                 }
1478             }
1479         }
1480     }
1481
1482     private void stopNavigating() {
1483         if (DEBUG) Log.d(TAG, "stopNavigating");
1484         if (mStarted) {
1485             mStarted = false;
1486             mSingleShot = false;
1487             native_stop();
1488             mTimeToFirstFix = 0;
1489             mLastFixTime = 0;
1490             mLocationFlags = LOCATION_INVALID;
1491
1492             // reset SV count to zero
1493             updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE, 0);
1494         }
1495     }
1496
1497     private void hibernate() {
1498         // stop GPS until our next fix interval arrives
1499         stopNavigating();
1500         mAlarmManager.cancel(mTimeoutIntent);
1501         mAlarmManager.cancel(mWakeupIntent);
1502         long now = SystemClock.elapsedRealtime();
1503         mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, now + mFixInterval, mWakeupIntent);
1504     }
1505
1506     private boolean hasCapability(int capability) {
1507         return ((mEngineCapabilities & capability) != 0);
1508     }
1509
1510
1511     /**
1512      * called from native code to update our position.
1513      */
1514     private void reportLocation(int flags, double latitude, double longitude, double altitude,
1515             float speedMetersPerSecond, float bearing, float accuracy, long timestamp) {
1516         if ((flags & LOCATION_HAS_SPEED) == LOCATION_HAS_SPEED) {
1517             mItarSpeedLimitExceeded = speedMetersPerSecond > ITAR_SPEED_LIMIT_METERS_PER_SECOND;
1518         }
1519
1520         if (mItarSpeedLimitExceeded) {
1521             Log.i(TAG, "Hal reported a speed in excess of ITAR limit." +
1522                     "  GPS/GNSS Navigation output blocked.");
1523             return;  // No output of location allowed
1524         }
1525
1526         if (VERBOSE) Log.v(TAG, "reportLocation lat: " + latitude + " long: " + longitude +
1527                 " timestamp: " + timestamp);
1528
1529         synchronized (mLocation) {
1530             mLocationFlags = flags;
1531             if ((flags & LOCATION_HAS_LAT_LONG) == LOCATION_HAS_LAT_LONG) {
1532                 mLocation.setLatitude(latitude);
1533                 mLocation.setLongitude(longitude);
1534                 mLocation.setTime(timestamp);
1535                 // It would be nice to push the elapsed real-time timestamp
1536                 // further down the stack, but this is still useful
1537                 mLocation.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());
1538             }
1539             if ((flags & LOCATION_HAS_ALTITUDE) == LOCATION_HAS_ALTITUDE) {
1540                 mLocation.setAltitude(altitude);
1541             } else {
1542                 mLocation.removeAltitude();
1543             }
1544             if ((flags & LOCATION_HAS_SPEED) == LOCATION_HAS_SPEED) {
1545                 mLocation.setSpeed(speedMetersPerSecond);
1546             } else {
1547                 mLocation.removeSpeed();
1548             }
1549             if ((flags & LOCATION_HAS_BEARING) == LOCATION_HAS_BEARING) {
1550                 mLocation.setBearing(bearing);
1551             } else {
1552                 mLocation.removeBearing();
1553             }
1554             if ((flags & LOCATION_HAS_ACCURACY) == LOCATION_HAS_ACCURACY) {
1555                 mLocation.setAccuracy(accuracy);
1556             } else {
1557                 mLocation.removeAccuracy();
1558             }
1559             mLocation.setExtras(mLocationExtras);
1560
1561             try {
1562                 mILocationManager.reportLocation(mLocation, false);
1563             } catch (RemoteException e) {
1564                 Log.e(TAG, "RemoteException calling reportLocation");
1565             }
1566         }
1567
1568         mLastFixTime = SystemClock.elapsedRealtime(); //return milliseconds since boot
1569         // report time to first fix
1570         if (mTimeToFirstFix == 0 && (flags & LOCATION_HAS_LAT_LONG) == LOCATION_HAS_LAT_LONG) {
1571             mTimeToFirstFix = (int)(mLastFixTime - mFixRequestTime);
1572             if (DEBUG) Log.d(TAG, "TTFF: " + mTimeToFirstFix);
1573
1574             // notify status listeners
1575             mListenerHelper.onFirstFix(mTimeToFirstFix);
1576         }
1577
1578         if (mSingleShot) {
1579             stopNavigating();
1580         }
1581
1582         if (mStarted && mStatus != LocationProvider.AVAILABLE) {
1583             // we want to time out if we do not receive a fix
1584             // within the time out and we are requesting infrequent fixes
1585             if (!hasCapability(GPS_CAPABILITY_SCHEDULING) && mFixInterval < NO_FIX_TIMEOUT) {
1586                 mAlarmManager.cancel(mTimeoutIntent);
1587             }
1588
1589             // send an intent to notify that the GPS is receiving fixes.
1590             Intent intent = new Intent(LocationManager.GPS_FIX_CHANGE_ACTION);
1591             intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, true);
1592             mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
1593             updateStatus(LocationProvider.AVAILABLE, mSvCount);
1594         }
1595
1596        if (!hasCapability(GPS_CAPABILITY_SCHEDULING) && mStarted &&
1597                mFixInterval > GPS_POLLING_THRESHOLD_INTERVAL) {
1598             if (DEBUG) Log.d(TAG, "got fix, hibernating");
1599             hibernate();
1600         }
1601    }
1602
1603     /**
1604      * called from native code to update our status
1605      */
1606     private void reportStatus(int status) {
1607         if (DEBUG) Log.v(TAG, "reportStatus status: " + status);
1608
1609         boolean wasNavigating = mNavigating;
1610         switch (status) {
1611             case GPS_STATUS_SESSION_BEGIN:
1612                 mNavigating = true;
1613                 mEngineOn = true;
1614                 break;
1615             case GPS_STATUS_SESSION_END:
1616                 mNavigating = false;
1617                 break;
1618             case GPS_STATUS_ENGINE_ON:
1619                 mEngineOn = true;
1620                 break;
1621             case GPS_STATUS_ENGINE_OFF:
1622                 mEngineOn = false;
1623                 mNavigating = false;
1624                 break;
1625         }
1626
1627         if (wasNavigating != mNavigating) {
1628             mListenerHelper.onStatusChanged(mNavigating);
1629
1630             // send an intent to notify that the GPS has been enabled or disabled
1631             Intent intent = new Intent(LocationManager.GPS_ENABLED_CHANGE_ACTION);
1632             intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, mNavigating);
1633             mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
1634         }
1635     }
1636
1637     /**
1638      * called from native code to update SV info
1639      */
1640     private void reportSvStatus() {
1641         int svCount = native_read_sv_status(mSvidWithFlags, mCn0s, mSvElevations, mSvAzimuths);
1642         mListenerHelper.onSvStatusChanged(
1643                 svCount,
1644                 mSvidWithFlags,
1645                 mCn0s,
1646                 mSvElevations,
1647                 mSvAzimuths);
1648
1649         if (VERBOSE) {
1650             Log.v(TAG, "SV count: " + svCount);
1651         }
1652         // Calculate number of sets used in fix.
1653         int usedInFixCount = 0;
1654         for (int i = 0; i < svCount; i++) {
1655             if ((mSvidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_USED_IN_FIX) != 0) {
1656                 ++usedInFixCount;
1657             }
1658             if (VERBOSE) {
1659                 Log.v(TAG, "svid: " + (mSvidWithFlags[i] >> GnssStatus.SVID_SHIFT_WIDTH) +
1660                         " cn0: " + mCn0s[i]/10 +
1661                         " elev: " + mSvElevations[i] +
1662                         " azimuth: " + mSvAzimuths[i] +
1663                         ((mSvidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_HAS_EPHEMERIS_DATA) == 0
1664                                 ? "  " : " E") +
1665                         ((mSvidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_HAS_ALMANAC_DATA) == 0
1666                                 ? "  " : " A") +
1667                         ((mSvidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_USED_IN_FIX) == 0
1668                                 ? "" : "U"));
1669             }
1670         }
1671         // return number of sets used in fix instead of total
1672         updateStatus(mStatus, usedInFixCount);
1673
1674         if (mNavigating && mStatus == LocationProvider.AVAILABLE && mLastFixTime > 0 &&
1675             SystemClock.elapsedRealtime() - mLastFixTime > RECENT_FIX_TIMEOUT) {
1676             // send an intent to notify that the GPS is no longer receiving fixes.
1677             Intent intent = new Intent(LocationManager.GPS_FIX_CHANGE_ACTION);
1678             intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, false);
1679             mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
1680             updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE, mSvCount);
1681         }
1682     }
1683
1684     /**
1685      * called from native code to update AGPS status
1686      */
1687     private void reportAGpsStatus(int type, int status, byte[] ipaddr) {
1688         switch (status) {
1689             case GPS_REQUEST_AGPS_DATA_CONN:
1690                 if (DEBUG) Log.d(TAG, "GPS_REQUEST_AGPS_DATA_CONN");
1691                 Log.v(TAG, "Received SUPL IP addr[]: " + Arrays.toString(ipaddr));
1692                 InetAddress connectionIpAddress = null;
1693                 if (ipaddr != null) {
1694                     try {
1695                         connectionIpAddress = InetAddress.getByAddress(ipaddr);
1696                         if (DEBUG) Log.d(TAG, "IP address converted to: " + connectionIpAddress);
1697                     } catch (UnknownHostException e) {
1698                         Log.e(TAG, "Bad IP Address: " + ipaddr, e);
1699                     }
1700                 }
1701                 sendMessage(REQUEST_SUPL_CONNECTION, 0 /*arg*/, connectionIpAddress);
1702                 break;
1703             case GPS_RELEASE_AGPS_DATA_CONN:
1704                 if (DEBUG) Log.d(TAG, "GPS_RELEASE_AGPS_DATA_CONN");
1705                 releaseSuplConnection(GPS_RELEASE_AGPS_DATA_CONN);
1706                 break;
1707             case GPS_AGPS_DATA_CONNECTED:
1708                 if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONNECTED");
1709                 break;
1710             case GPS_AGPS_DATA_CONN_DONE:
1711                 if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONN_DONE");
1712                 break;
1713             case GPS_AGPS_DATA_CONN_FAILED:
1714                 if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONN_FAILED");
1715                 break;
1716             default:
1717                 if (DEBUG) Log.d(TAG, "Received Unknown AGPS status: " + status);
1718         }
1719     }
1720
1721     private void releaseSuplConnection(int connStatus) {
1722         sendMessage(RELEASE_SUPL_CONNECTION, connStatus, null /*obj*/);
1723     }
1724
1725     /**
1726      * called from native code to report NMEA data received
1727      */
1728     private void reportNmea(long timestamp) {
1729         if (!mItarSpeedLimitExceeded) {
1730             int length = native_read_nmea(mNmeaBuffer, mNmeaBuffer.length);
1731             String nmea = new String(mNmeaBuffer, 0 /* offset */, length);
1732             mListenerHelper.onNmeaReceived(timestamp, nmea);
1733         }
1734     }
1735
1736     /**
1737      * called from native code - Gps measurements callback
1738      */
1739     private void reportMeasurementData(GnssMeasurementsEvent event) {
1740         if (!mItarSpeedLimitExceeded) {
1741             mGnssMeasurementsProvider.onMeasurementsAvailable(event);
1742         }
1743     }
1744
1745     /**
1746      * called from native code - GPS navigation message callback
1747      */
1748     private void reportNavigationMessage(GnssNavigationMessage event) {
1749         if (!mItarSpeedLimitExceeded) {
1750             mGnssNavigationMessageProvider.onNavigationMessageAvailable(event);
1751         }
1752     }
1753
1754     /**
1755      * called from native code to inform us what the GPS engine capabilities are
1756      */
1757     private void setEngineCapabilities(int capabilities) {
1758         mEngineCapabilities = capabilities;
1759
1760         if (hasCapability(GPS_CAPABILITY_ON_DEMAND_TIME)) {
1761             mOnDemandTimeInjection = true;
1762             requestUtcTime();
1763         }
1764
1765         mGnssMeasurementsProvider.onCapabilitiesUpdated(
1766                 (capabilities & GPS_CAPABILITY_MEASUREMENTS) == GPS_CAPABILITY_MEASUREMENTS);
1767         mGnssNavigationMessageProvider.onCapabilitiesUpdated(
1768                 (capabilities & GPS_CAPABILITY_NAV_MESSAGES) == GPS_CAPABILITY_NAV_MESSAGES);
1769     }
1770
1771     /**
1772      * Called from native code to inform us the hardware information.
1773      */
1774     private void setGnssYearOfHardware(int yearOfHardware) {
1775         if (DEBUG) Log.d(TAG, "setGnssYearOfHardware called with " + yearOfHardware);
1776         mYearOfHardware = yearOfHardware;
1777     }
1778
1779     public interface GnssSystemInfoProvider {
1780         /**
1781          * Returns the year of GPS hardware.
1782          */
1783         int getGnssYearOfHardware();
1784     }
1785
1786     /**
1787      * @hide
1788      */
1789     public GnssSystemInfoProvider getGnssSystemInfoProvider() {
1790         return new GnssSystemInfoProvider() {
1791             @Override
1792             public int getGnssYearOfHardware() {
1793                 return mYearOfHardware;
1794             }
1795         };
1796     }
1797
1798     /**
1799      * called from native code to request XTRA data
1800      */
1801     private void xtraDownloadRequest() {
1802         if (DEBUG) Log.d(TAG, "xtraDownloadRequest");
1803         sendMessage(DOWNLOAD_XTRA_DATA, 0, null);
1804     }
1805
1806     /**
1807      * Helper method to construct a location object.
1808      */
1809     private Location buildLocation(
1810             int flags,
1811             double latitude,
1812             double longitude,
1813             double altitude,
1814             float speed,
1815             float bearing,
1816             float accuracy,
1817             long timestamp) {
1818         Location location = new Location(LocationManager.GPS_PROVIDER);
1819         if((flags & LOCATION_HAS_LAT_LONG) == LOCATION_HAS_LAT_LONG) {
1820             location.setLatitude(latitude);
1821             location.setLongitude(longitude);
1822             location.setTime(timestamp);
1823             location.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());
1824         }
1825         if((flags & LOCATION_HAS_ALTITUDE) == LOCATION_HAS_ALTITUDE) {
1826             location.setAltitude(altitude);
1827         }
1828         if((flags & LOCATION_HAS_SPEED) == LOCATION_HAS_SPEED) {
1829             location.setSpeed(speed);
1830         }
1831         if((flags & LOCATION_HAS_BEARING) == LOCATION_HAS_BEARING) {
1832             location.setBearing(bearing);
1833         }
1834         if((flags & LOCATION_HAS_ACCURACY) == LOCATION_HAS_ACCURACY) {
1835             location.setAccuracy(accuracy);
1836         }
1837         return location;
1838     }
1839
1840     /**
1841      * Converts the GPS HAL status to the internal Geofence Hardware status.
1842      */
1843     private int getGeofenceStatus(int status) {
1844         switch(status) {
1845             case GPS_GEOFENCE_OPERATION_SUCCESS:
1846                 return GeofenceHardware.GEOFENCE_SUCCESS;
1847             case GPS_GEOFENCE_ERROR_GENERIC:
1848                 return GeofenceHardware.GEOFENCE_FAILURE;
1849             case GPS_GEOFENCE_ERROR_ID_EXISTS:
1850                 return GeofenceHardware.GEOFENCE_ERROR_ID_EXISTS;
1851             case GPS_GEOFENCE_ERROR_INVALID_TRANSITION:
1852                 return GeofenceHardware.GEOFENCE_ERROR_INVALID_TRANSITION;
1853             case GPS_GEOFENCE_ERROR_TOO_MANY_GEOFENCES:
1854                 return GeofenceHardware.GEOFENCE_ERROR_TOO_MANY_GEOFENCES;
1855             case GPS_GEOFENCE_ERROR_ID_UNKNOWN:
1856                 return GeofenceHardware.GEOFENCE_ERROR_ID_UNKNOWN;
1857             default:
1858                 return -1;
1859         }
1860     }
1861
1862     /**
1863      * Called from native to report GPS Geofence transition
1864      * All geofence callbacks are called on the same thread
1865      */
1866     private void reportGeofenceTransition(int geofenceId, int flags, double latitude,
1867             double longitude, double altitude, float speed, float bearing, float accuracy,
1868             long timestamp, int transition, long transitionTimestamp) {
1869         if (mGeofenceHardwareImpl == null) {
1870             mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
1871         }
1872         Location location = buildLocation(
1873                 flags,
1874                 latitude,
1875                 longitude,
1876                 altitude,
1877                 speed,
1878                 bearing,
1879                 accuracy,
1880                 timestamp);
1881         mGeofenceHardwareImpl.reportGeofenceTransition(
1882                 geofenceId,
1883                 location,
1884                 transition,
1885                 transitionTimestamp,
1886                 GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE,
1887                 FusedBatchOptions.SourceTechnologies.GNSS);
1888     }
1889
1890     /**
1891      * called from native code to report GPS status change.
1892      */
1893     private void reportGeofenceStatus(int status, int flags, double latitude,
1894             double longitude, double altitude, float speed, float bearing, float accuracy,
1895             long timestamp) {
1896         if (mGeofenceHardwareImpl == null) {
1897             mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
1898         }
1899         Location location = buildLocation(
1900                 flags,
1901                 latitude,
1902                 longitude,
1903                 altitude,
1904                 speed,
1905                 bearing,
1906                 accuracy,
1907                 timestamp);
1908         int monitorStatus = GeofenceHardware.MONITOR_CURRENTLY_UNAVAILABLE;
1909         if(status == GPS_GEOFENCE_AVAILABLE) {
1910             monitorStatus = GeofenceHardware.MONITOR_CURRENTLY_AVAILABLE;
1911         }
1912         mGeofenceHardwareImpl.reportGeofenceMonitorStatus(
1913                 GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE,
1914                 monitorStatus,
1915                 location,
1916                 FusedBatchOptions.SourceTechnologies.GNSS);
1917     }
1918
1919     /**
1920      * called from native code - Geofence Add callback
1921      */
1922     private void reportGeofenceAddStatus(int geofenceId, int status) {
1923         if (mGeofenceHardwareImpl == null) {
1924             mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
1925         }
1926         mGeofenceHardwareImpl.reportGeofenceAddStatus(geofenceId, getGeofenceStatus(status));
1927     }
1928
1929     /**
1930      * called from native code - Geofence Remove callback
1931      */
1932     private void reportGeofenceRemoveStatus(int geofenceId, int status) {
1933         if (mGeofenceHardwareImpl == null) {
1934             mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
1935         }
1936         mGeofenceHardwareImpl.reportGeofenceRemoveStatus(geofenceId, getGeofenceStatus(status));
1937     }
1938
1939     /**
1940      * called from native code - Geofence Pause callback
1941      */
1942     private void reportGeofencePauseStatus(int geofenceId, int status) {
1943         if (mGeofenceHardwareImpl == null) {
1944             mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
1945         }
1946         mGeofenceHardwareImpl.reportGeofencePauseStatus(geofenceId, getGeofenceStatus(status));
1947     }
1948
1949     /**
1950      * called from native code - Geofence Resume callback
1951      */
1952     private void reportGeofenceResumeStatus(int geofenceId, int status) {
1953         if (mGeofenceHardwareImpl == null) {
1954             mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
1955         }
1956         mGeofenceHardwareImpl.reportGeofenceResumeStatus(geofenceId, getGeofenceStatus(status));
1957     }
1958
1959     //=============================================================
1960     // NI Client support
1961     //=============================================================
1962     private final INetInitiatedListener mNetInitiatedListener = new INetInitiatedListener.Stub() {
1963         // Sends a response for an NI request to HAL.
1964         @Override
1965         public boolean sendNiResponse(int notificationId, int userResponse)
1966         {
1967             // TODO Add Permission check
1968
1969             if (DEBUG) Log.d(TAG, "sendNiResponse, notifId: " + notificationId +
1970                     ", response: " + userResponse);
1971             native_send_ni_response(notificationId, userResponse);
1972             return true;
1973         }
1974     };
1975
1976     public INetInitiatedListener getNetInitiatedListener() {
1977         return mNetInitiatedListener;
1978     }
1979
1980     // Called by JNI function to report an NI request.
1981     public void reportNiNotification(
1982             int notificationId,
1983             int niType,
1984             int notifyFlags,
1985             int timeout,
1986             int defaultResponse,
1987             String requestorId,
1988             String text,
1989             int requestorIdEncoding,
1990             int textEncoding,
1991             String extras  // Encoded extra data
1992         )
1993     {
1994         Log.i(TAG, "reportNiNotification: entered");
1995         Log.i(TAG, "notificationId: " + notificationId +
1996                 ", niType: " + niType +
1997                 ", notifyFlags: " + notifyFlags +
1998                 ", timeout: " + timeout +
1999                 ", defaultResponse: " + defaultResponse);
2000
2001         Log.i(TAG, "requestorId: " + requestorId +
2002                 ", text: " + text +
2003                 ", requestorIdEncoding: " + requestorIdEncoding +
2004                 ", textEncoding: " + textEncoding);
2005
2006         GpsNiNotification notification = new GpsNiNotification();
2007
2008         notification.notificationId = notificationId;
2009         notification.niType = niType;
2010         notification.needNotify = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_NEED_NOTIFY) != 0;
2011         notification.needVerify = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_NEED_VERIFY) != 0;
2012         notification.privacyOverride = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_PRIVACY_OVERRIDE) != 0;
2013         notification.timeout = timeout;
2014         notification.defaultResponse = defaultResponse;
2015         notification.requestorId = requestorId;
2016         notification.text = text;
2017         notification.requestorIdEncoding = requestorIdEncoding;
2018         notification.textEncoding = textEncoding;
2019
2020         // Process extras, assuming the format is
2021         // one of more lines of "key = value"
2022         Bundle bundle = new Bundle();
2023
2024         if (extras == null) extras = "";
2025         Properties extraProp = new Properties();
2026
2027         try {
2028             extraProp.load(new StringReader(extras));
2029         }
2030         catch (IOException e)
2031         {
2032             Log.e(TAG, "reportNiNotification cannot parse extras data: " + extras);
2033         }
2034
2035         for (Entry<Object, Object> ent : extraProp.entrySet())
2036         {
2037             bundle.putString((String) ent.getKey(), (String) ent.getValue());
2038         }
2039
2040         notification.extras = bundle;
2041
2042         mNIHandler.handleNiNotification(notification);
2043     }
2044
2045     /**
2046      * Called from native code to request set id info.
2047      * We should be careful about receiving null string from the TelephonyManager,
2048      * because sending null String to JNI function would cause a crash.
2049      */
2050
2051     private void requestSetID(int flags) {
2052         TelephonyManager phone = (TelephonyManager)
2053                 mContext.getSystemService(Context.TELEPHONY_SERVICE);
2054         int type = AGPS_SETID_TYPE_NONE;
2055         String data = "";
2056
2057         if ((flags & AGPS_RIL_REQUEST_SETID_IMSI) == AGPS_RIL_REQUEST_SETID_IMSI) {
2058             String data_temp = phone.getSubscriberId();
2059             if (data_temp == null) {
2060                 // This means the framework does not have the SIM card ready.
2061             } else {
2062                 // This means the framework has the SIM card.
2063                 data = data_temp;
2064                 type = AGPS_SETID_TYPE_IMSI;
2065             }
2066         }
2067         else if ((flags & AGPS_RIL_REQUEST_SETID_MSISDN) == AGPS_RIL_REQUEST_SETID_MSISDN) {
2068             String data_temp = phone.getLine1Number();
2069             if (data_temp == null) {
2070                 // This means the framework does not have the SIM card ready.
2071             } else {
2072                 // This means the framework has the SIM card.
2073                 data = data_temp;
2074                 type = AGPS_SETID_TYPE_MSISDN;
2075             }
2076         }
2077         native_agps_set_id(type, data);
2078     }
2079
2080     /**
2081      * Called from native code to request utc time info
2082      */
2083     private void requestUtcTime() {
2084         if (DEBUG) Log.d(TAG, "utcTimeRequest");
2085         sendMessage(INJECT_NTP_TIME, 0, null);
2086     }
2087
2088     /**
2089      * Called from native code to request reference location info
2090      */
2091
2092     private void requestRefLocation(int flags) {
2093         TelephonyManager phone = (TelephonyManager)
2094                 mContext.getSystemService(Context.TELEPHONY_SERVICE);
2095         final int phoneType = phone.getPhoneType();
2096         if (phoneType == TelephonyManager.PHONE_TYPE_GSM) {
2097             GsmCellLocation gsm_cell = (GsmCellLocation) phone.getCellLocation();
2098             if ((gsm_cell != null) && (phone.getNetworkOperator() != null)
2099                     && (phone.getNetworkOperator().length() > 3)) {
2100                 int type;
2101                 int mcc = Integer.parseInt(phone.getNetworkOperator().substring(0,3));
2102                 int mnc = Integer.parseInt(phone.getNetworkOperator().substring(3));
2103                 int networkType = phone.getNetworkType();
2104                 if (networkType == TelephonyManager.NETWORK_TYPE_UMTS
2105                     || networkType == TelephonyManager.NETWORK_TYPE_HSDPA
2106                     || networkType == TelephonyManager.NETWORK_TYPE_HSUPA
2107                     || networkType == TelephonyManager.NETWORK_TYPE_HSPA
2108                     || networkType == TelephonyManager.NETWORK_TYPE_HSPAP) {
2109                     type = AGPS_REF_LOCATION_TYPE_UMTS_CELLID;
2110                 } else {
2111                     type = AGPS_REF_LOCATION_TYPE_GSM_CELLID;
2112                 }
2113                 native_agps_set_ref_location_cellid(type, mcc, mnc,
2114                         gsm_cell.getLac(), gsm_cell.getCid(), gsm_cell.getPsc());
2115             } else {
2116                 Log.e(TAG,"Error getting cell location info.");
2117             }
2118         } else if (phoneType == TelephonyManager.PHONE_TYPE_CDMA) {
2119             Log.e(TAG, "CDMA not supported.");
2120         }
2121     }
2122
2123     private void sendMessage(int message, int arg, Object obj) {
2124         // hold a wake lock until this message is delivered
2125         // note that this assumes the message will not be removed from the queue before
2126         // it is handled (otherwise the wake lock would be leaked).
2127         mWakeLock.acquire();
2128         Log.i(TAG, "WakeLock acquired by sendMessage(" + message + ", " + arg + ", " + obj + ")");
2129         mHandler.obtainMessage(message, arg, 1, obj).sendToTarget();
2130     }
2131
2132     private final class ProviderHandler extends Handler {
2133         public ProviderHandler(Looper looper) {
2134             super(looper, null, true /*async*/);
2135         }
2136
2137         @Override
2138         public void handleMessage(Message msg) {
2139             int message = msg.what;
2140             switch (message) {
2141                 case ENABLE:
2142                     if (msg.arg1 == 1) {
2143                         handleEnable();
2144                     } else {
2145                         handleDisable();
2146                     }
2147                     break;
2148                 case SET_REQUEST:
2149                     GpsRequest gpsRequest = (GpsRequest) msg.obj;
2150                     handleSetRequest(gpsRequest.request, gpsRequest.source);
2151                     break;
2152                 case UPDATE_NETWORK_STATE:
2153                     handleUpdateNetworkState((Network) msg.obj);
2154                     break;
2155                 case REQUEST_SUPL_CONNECTION:
2156                     handleRequestSuplConnection((InetAddress) msg.obj);
2157                     break;
2158                 case RELEASE_SUPL_CONNECTION:
2159                     handleReleaseSuplConnection(msg.arg1);
2160                     break;
2161                 case INJECT_NTP_TIME:
2162                     handleInjectNtpTime();
2163                     break;
2164                 case DOWNLOAD_XTRA_DATA:
2165                     handleDownloadXtraData();
2166                     break;
2167                 case INJECT_NTP_TIME_FINISHED:
2168                     mInjectNtpTimePending = STATE_IDLE;
2169                     break;
2170                 case DOWNLOAD_XTRA_DATA_FINISHED:
2171                     mDownloadXtraDataPending = STATE_IDLE;
2172                     break;
2173                 case UPDATE_LOCATION:
2174                     handleUpdateLocation((Location) msg.obj);
2175                     break;
2176                 case SUBSCRIPTION_OR_SIM_CHANGED:
2177                     subscriptionOrSimChanged(mContext);
2178                     break;
2179                 case INITIALIZE_HANDLER:
2180                     handleInitialize();
2181                     break;
2182             }
2183             if (msg.arg2 == 1) {
2184                 // wakelock was taken for this message, release it
2185                 mWakeLock.release();
2186                 Log.i(TAG, "WakeLock released by handleMessage(" + message + ", " + msg.arg1 + ", "
2187                         + msg.obj + ")");
2188             }
2189         }
2190
2191         /**
2192          * This method is bound to {@link #GnssLocationProvider(Context, ILocationManager, Looper)}.
2193          * It is in charge of loading properties and registering for events that will be posted to
2194          * this handler.
2195          */
2196         private void handleInitialize() {
2197             // load default GPS configuration
2198             // (this configuration might change in the future based on SIM changes)
2199             reloadGpsProperties(mContext, mProperties);
2200
2201             // TODO: When this object "finishes" we should unregister by invoking
2202             // SubscriptionManager.getInstance(mContext).unregister(mOnSubscriptionsChangedListener);
2203             // This is not strictly necessary because it will be unregistered if the
2204             // notification fails but it is good form.
2205
2206             // Register for SubscriptionInfo list changes which is guaranteed
2207             // to invoke onSubscriptionsChanged the first time.
2208             SubscriptionManager.from(mContext)
2209                     .addOnSubscriptionsChangedListener(mOnSubscriptionsChangedListener);
2210
2211             // listen for events
2212             IntentFilter intentFilter;
2213             if (native_is_agps_ril_supported()) {
2214                 intentFilter = new IntentFilter();
2215                 intentFilter.addAction(Intents.DATA_SMS_RECEIVED_ACTION);
2216                 intentFilter.addDataScheme("sms");
2217                 intentFilter.addDataAuthority("localhost", "7275");
2218                 mContext.registerReceiver(mBroadcastReceiver, intentFilter, null, this);
2219
2220                 intentFilter = new IntentFilter();
2221                 intentFilter.addAction(Intents.WAP_PUSH_RECEIVED_ACTION);
2222                 try {
2223                     intentFilter.addDataType("application/vnd.omaloc-supl-init");
2224                 } catch (IntentFilter.MalformedMimeTypeException e) {
2225                     Log.w(TAG, "Malformed SUPL init mime type");
2226                 }
2227                 mContext.registerReceiver(mBroadcastReceiver, intentFilter, null, this);
2228             } else if (DEBUG) {
2229                 Log.d(TAG, "Skipped registration for SMS/WAP-PUSH messages because AGPS Ril in GPS"
2230                         + " HAL is not supported");
2231             }
2232
2233             intentFilter = new IntentFilter();
2234             intentFilter.addAction(ALARM_WAKEUP);
2235             intentFilter.addAction(ALARM_TIMEOUT);
2236             intentFilter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
2237             intentFilter.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
2238             intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
2239             intentFilter.addAction(Intent.ACTION_SCREEN_ON);
2240             intentFilter.addAction(SIM_STATE_CHANGED);
2241             mContext.registerReceiver(mBroadcastReceiver, intentFilter, null, this);
2242
2243             // register for connectivity change events, this is equivalent to the deprecated way of
2244             // registering for CONNECTIVITY_ACTION broadcasts
2245             NetworkRequest.Builder networkRequestBuilder = new NetworkRequest.Builder();
2246             networkRequestBuilder.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
2247             networkRequestBuilder.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
2248             NetworkRequest networkRequest = networkRequestBuilder.build();
2249             mConnMgr.registerNetworkCallback(networkRequest, mNetworkConnectivityCallback);
2250
2251             // listen for PASSIVE_PROVIDER updates
2252             LocationManager locManager =
2253                     (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
2254             long minTime = 0;
2255             float minDistance = 0;
2256             boolean oneShot = false;
2257             LocationRequest request = LocationRequest.createFromDeprecatedProvider(
2258                     LocationManager.PASSIVE_PROVIDER,
2259                     minTime,
2260                     minDistance,
2261                     oneShot);
2262             // Don't keep track of this request since it's done on behalf of other clients
2263             // (which are kept track of separately).
2264             request.setHideFromAppOps(true);
2265             locManager.requestLocationUpdates(
2266                     request,
2267                     new NetworkLocationListener(),
2268                     getLooper());
2269         }
2270     }
2271
2272     private final class NetworkLocationListener implements LocationListener {
2273         @Override
2274         public void onLocationChanged(Location location) {
2275             // this callback happens on mHandler looper
2276             if (LocationManager.NETWORK_PROVIDER.equals(location.getProvider())) {
2277                 handleUpdateLocation(location);
2278             }
2279         }
2280         @Override
2281         public void onStatusChanged(String provider, int status, Bundle extras) { }
2282         @Override
2283         public void onProviderEnabled(String provider) { }
2284         @Override
2285         public void onProviderDisabled(String provider) { }
2286     }
2287
2288     private String getSelectedApn() {
2289         Uri uri = Uri.parse("content://telephony/carriers/preferapn");
2290         Cursor cursor = null;
2291         try {
2292             cursor = mContext.getContentResolver().query(
2293                     uri,
2294                     new String[] { "apn" },
2295                     null /* selection */,
2296                     null /* selectionArgs */,
2297                     Carriers.DEFAULT_SORT_ORDER);
2298             if (cursor != null && cursor.moveToFirst()) {
2299                 return cursor.getString(0);
2300             } else {
2301                 Log.e(TAG, "No APN found to select.");
2302             }
2303         } catch (Exception e) {
2304             Log.e(TAG, "Error encountered on selecting the APN.", e);
2305         } finally {
2306             if (cursor != null) {
2307                 cursor.close();
2308             }
2309         }
2310
2311         return null;
2312     }
2313
2314     private int getApnIpType(String apn) {
2315         ensureInHandlerThread();
2316         if (apn == null) {
2317             return APN_INVALID;
2318         }
2319
2320         String selection = String.format("current = 1 and apn = '%s' and carrier_enabled = 1", apn);
2321         Cursor cursor = null;
2322         try {
2323             cursor = mContext.getContentResolver().query(
2324                     Carriers.CONTENT_URI,
2325                     new String[] { Carriers.PROTOCOL },
2326                     selection,
2327                     null,
2328                     Carriers.DEFAULT_SORT_ORDER);
2329
2330             if (null != cursor && cursor.moveToFirst()) {
2331                 return translateToApnIpType(cursor.getString(0), apn);
2332             } else {
2333                 Log.e(TAG, "No entry found in query for APN: " + apn);
2334             }
2335         } catch (Exception e) {
2336             Log.e(TAG, "Error encountered on APN query for: " + apn, e);
2337         } finally {
2338             if (cursor != null) {
2339                 cursor.close();
2340             }
2341         }
2342
2343         return APN_INVALID;
2344     }
2345
2346     private int translateToApnIpType(String ipProtocol, String apn) {
2347         if ("IP".equals(ipProtocol)) {
2348             return APN_IPV4;
2349         }
2350         if ("IPV6".equals(ipProtocol)) {
2351             return APN_IPV6;
2352         }
2353         if ("IPV4V6".equals(ipProtocol)) {
2354             return APN_IPV4V6;
2355         }
2356
2357         // we hit the default case so the ipProtocol is not recognized
2358         String message = String.format("Unknown IP Protocol: %s, for APN: %s", ipProtocol, apn);
2359         Log.e(TAG, message);
2360         return APN_INVALID;
2361     }
2362
2363     private void setRouting() {
2364         if (mAGpsDataConnectionIpAddr == null) {
2365             return;
2366         }
2367
2368         // TODO: replace the use of this deprecated API
2369         boolean result = mConnMgr.requestRouteToHostAddress(
2370                 ConnectivityManager.TYPE_MOBILE_SUPL,
2371                 mAGpsDataConnectionIpAddr);
2372
2373         if (!result) {
2374             Log.e(TAG, "Error requesting route to host: " + mAGpsDataConnectionIpAddr);
2375         } else if (DEBUG) {
2376             Log.d(TAG, "Successfully requested route to host: " + mAGpsDataConnectionIpAddr);
2377         }
2378     }
2379
2380     /**
2381      * @return {@code true} if there is a data network available for outgoing connections,
2382      *         {@code false} otherwise.
2383      */
2384     private boolean isDataNetworkConnected() {
2385         NetworkInfo activeNetworkInfo = mConnMgr.getActiveNetworkInfo();
2386         return activeNetworkInfo != null && activeNetworkInfo.isConnected();
2387     }
2388
2389     /**
2390      * Ensures the calling function is running in the thread associated with {@link #mHandler}.
2391      */
2392     private void ensureInHandlerThread() {
2393         if (mHandler != null && Looper.myLooper() == mHandler.getLooper()) {
2394             return;
2395         }
2396         throw new RuntimeException("This method must run on the Handler thread.");
2397     }
2398
2399     /**
2400      * @return A string representing the current state stored in {@link #mAGpsDataConnectionState}.
2401      */
2402     private String agpsDataConnStateAsString() {
2403         switch(mAGpsDataConnectionState) {
2404             case AGPS_DATA_CONNECTION_CLOSED:
2405                 return "CLOSED";
2406             case AGPS_DATA_CONNECTION_OPEN:
2407                 return "OPEN";
2408             case AGPS_DATA_CONNECTION_OPENING:
2409                 return "OPENING";
2410             default:
2411                 return "<Unknown>";
2412         }
2413     }
2414
2415     /**
2416      * @return A string representing the given GPS_AGPS_DATA status.
2417      */
2418     private String agpsDataConnStatusAsString(int agpsDataConnStatus) {
2419         switch (agpsDataConnStatus) {
2420             case GPS_AGPS_DATA_CONNECTED:
2421                 return "CONNECTED";
2422             case GPS_AGPS_DATA_CONN_DONE:
2423                 return "DONE";
2424             case GPS_AGPS_DATA_CONN_FAILED:
2425                 return "FAILED";
2426             case GPS_RELEASE_AGPS_DATA_CONN:
2427                 return "RELEASE";
2428             case GPS_REQUEST_AGPS_DATA_CONN:
2429                 return "REQUEST";
2430             default:
2431                 return "<Unknown>";
2432         }
2433     }
2434
2435     @Override
2436     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2437         StringBuilder s = new StringBuilder();
2438         s.append("  mFixInterval=").append(mFixInterval).append('\n');
2439         s.append("  mDisableGps (battery saver mode)=").append(mDisableGps).append('\n');
2440         s.append("  mEngineCapabilities=0x").append(Integer.toHexString(mEngineCapabilities));
2441         s.append(" ( ");
2442         if (hasCapability(GPS_CAPABILITY_SCHEDULING)) s.append("SCHEDULING ");
2443         if (hasCapability(GPS_CAPABILITY_MSB)) s.append("MSB ");
2444         if (hasCapability(GPS_CAPABILITY_MSA)) s.append("MSA ");
2445         if (hasCapability(GPS_CAPABILITY_SINGLE_SHOT)) s.append("SINGLE_SHOT ");
2446         if (hasCapability(GPS_CAPABILITY_ON_DEMAND_TIME)) s.append("ON_DEMAND_TIME ");
2447         if (hasCapability(GPS_CAPABILITY_GEOFENCING)) s.append("GEOFENCING ");
2448         if (hasCapability(GPS_CAPABILITY_MEASUREMENTS)) s.append("MEASUREMENTS ");
2449         if (hasCapability(GPS_CAPABILITY_NAV_MESSAGES)) s.append("NAV_MESSAGES ");
2450         s.append(")\n");
2451
2452         s.append(native_get_internal_state());
2453         pw.append(s);
2454     }
2455
2456     /**
2457      * A simple implementation of exponential backoff.
2458      */
2459     private static final class BackOff {
2460         private static final int MULTIPLIER = 2;
2461         private final long mInitIntervalMillis;
2462         private final long mMaxIntervalMillis;
2463         private long mCurrentIntervalMillis;
2464
2465         public BackOff(long initIntervalMillis, long maxIntervalMillis) {
2466             mInitIntervalMillis = initIntervalMillis;
2467             mMaxIntervalMillis = maxIntervalMillis;
2468
2469             mCurrentIntervalMillis = mInitIntervalMillis / MULTIPLIER;
2470         }
2471
2472         public long nextBackoffMillis() {
2473             if (mCurrentIntervalMillis > mMaxIntervalMillis) {
2474                 return mMaxIntervalMillis;
2475             }
2476
2477             mCurrentIntervalMillis *= MULTIPLIER;
2478             return mCurrentIntervalMillis;
2479         }
2480
2481         public void reset() {
2482             mCurrentIntervalMillis = mInitIntervalMillis / MULTIPLIER;
2483         }
2484     }
2485
2486     // for GPS SV statistics
2487     private static final int MAX_SVS = 64;
2488
2489     // preallocated arrays, to avoid memory allocation in reportStatus()
2490     private int mSvidWithFlags[] = new int[MAX_SVS];
2491     private float mCn0s[] = new float[MAX_SVS];
2492     private float mSvElevations[] = new float[MAX_SVS];
2493     private float mSvAzimuths[] = new float[MAX_SVS];
2494     private int mSvCount;
2495     // preallocated to avoid memory allocation in reportNmea()
2496     private byte[] mNmeaBuffer = new byte[120];
2497
2498     static { class_init_native(); }
2499     private static native void class_init_native();
2500     private static native boolean native_is_supported();
2501     private static native boolean native_is_agps_ril_supported();
2502     private static native boolean native_is_gnss_configuration_supported();
2503
2504     private native boolean native_init();
2505     private native void native_cleanup();
2506     private native boolean native_set_position_mode(int mode, int recurrence, int min_interval,
2507             int preferred_accuracy, int preferred_time);
2508     private native boolean native_start();
2509     private native boolean native_stop();
2510     private native void native_delete_aiding_data(int flags);
2511     // returns number of SVs
2512     // mask[0] is ephemeris mask and mask[1] is almanac mask
2513     private native int native_read_sv_status(int[] prnWithFlags, float[] cn0s, float[] elevations,
2514             float[] azimuths);
2515     private native int native_read_nmea(byte[] buffer, int bufferSize);
2516     private native void native_inject_location(double latitude, double longitude, float accuracy);
2517
2518     // XTRA Support
2519     private native void native_inject_time(long time, long timeReference, int uncertainty);
2520     private native boolean native_supports_xtra();
2521     private native void native_inject_xtra_data(byte[] data, int length);
2522
2523     // DEBUG Support
2524     private native String native_get_internal_state();
2525
2526     // AGPS Support
2527     private native void native_agps_data_conn_open(String apn, int apnIpType);
2528     private native void native_agps_data_conn_closed();
2529     private native void native_agps_data_conn_failed();
2530     private native void native_agps_ni_message(byte [] msg, int length);
2531     private native void native_set_agps_server(int type, String hostname, int port);
2532
2533     // Network-initiated (NI) Support
2534     private native void native_send_ni_response(int notificationId, int userResponse);
2535
2536     // AGPS ril suport
2537     private native void native_agps_set_ref_location_cellid(int type, int mcc, int mnc,
2538             int lac, int cid, int psc);
2539     private native void native_agps_set_id(int type, String setid);
2540
2541     private native void native_update_network_state(boolean connected, int type,
2542             boolean roaming, boolean available, String extraInfo, String defaultAPN);
2543
2544     // Hardware Geofence support.
2545     private static native boolean native_is_geofence_supported();
2546     private static native boolean native_add_geofence(int geofenceId, double latitude,
2547             double longitude, double radius, int lastTransition,int monitorTransitions,
2548             int notificationResponsivenes, int unknownTimer);
2549     private static native boolean native_remove_geofence(int geofenceId);
2550     private static native boolean native_resume_geofence(int geofenceId, int transitions);
2551     private static native boolean native_pause_geofence(int geofenceId);
2552
2553     // Gps Hal measurements support.
2554     private static native boolean native_is_measurement_supported();
2555     private native boolean native_start_measurement_collection();
2556     private native boolean native_stop_measurement_collection();
2557
2558     // Gps Navigation message support.
2559     private static native boolean native_is_navigation_message_supported();
2560     private native boolean native_start_navigation_message_collection();
2561     private native boolean native_stop_navigation_message_collection();
2562
2563     // GNSS Configuration
2564     private static native void native_configuration_update(String configData);
2565 }