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