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