OSDN Git Service

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