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