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