GpsLocationProvider.java revision ea8a8a6076f04360de2d25b3e5853cde8026cd5f
19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
569a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes * you may not use this file except in compliance with the License.
669a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes * You may obtain a copy of the License at
769a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes *
89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
969a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes *
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
1169a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes * distributed under the License is distributed on an "AS IS" BASIS,
1269a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1369a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes * See the License for the specific language governing permissions and
1469a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes * limitations under the License.
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage com.android.server.location;
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport com.android.internal.app.IAppOpsService;
209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport com.android.internal.app.IBatteryStats;
210795272aa226f4e965968a03daddc53ce30b7cdaMathias Agopianimport com.android.internal.location.GpsNetInitiatedHandler;
220795272aa226f4e965968a03daddc53ce30b7cdaMathias Agopianimport com.android.internal.location.GpsNetInitiatedHandler.GpsNiNotification;
230795272aa226f4e965968a03daddc53ce30b7cdaMathias Agopianimport com.android.internal.location.ProviderProperties;
24f1b56449f58963e4f0473d5e26961f68c31759f4Glenn Kastenimport com.android.internal.location.ProviderRequest;
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport com.android.internal.telephony.Phone;
269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport com.android.internal.telephony.PhoneConstants;
279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.app.AlarmManager;
299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.app.AppOpsManager;
309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.app.PendingIntent;
319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.BroadcastReceiver;
329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context;
339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Intent;
349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.IntentFilter;
359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.database.Cursor;
369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.hardware.location.GeofenceHardware;
379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.hardware.location.GeofenceHardwareImpl;
389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.location.Criteria;
399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.location.FusedBatchOptions;
409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.location.GpsMeasurementsEvent;
416af763bec7c3f4d50fee8dd0046409bb8a7fe8f6Glenn Kastenimport android.location.IGpsGeofenceHardware;
429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.location.IGpsStatusListener;
43957e58670baad8c5995f1368e3b5280f0dbd891fSan Mehatimport android.location.IGpsStatusProvider;
44160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tateimport android.location.ILocationManager;
45a5109a878eeff22e32ee5ce1b1cd15e8daad5234San Mehatimport android.location.INetInitiatedListener;
469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.location.Location;
479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.location.LocationListener;
48160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tateimport android.location.LocationManager;
49160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tateimport android.location.LocationProvider;
50160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tateimport android.location.LocationRequest;
51160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tateimport android.net.ConnectivityManager;
52160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tateimport android.net.NetworkInfo;
53f1b56449f58963e4f0473d5e26961f68c31759f4Glenn Kastenimport android.net.Uri;
54f1b56449f58963e4f0473d5e26961f68c31759f4Glenn Kastenimport android.os.AsyncTask;
556793ac943afeb16642f477c43ddfd27e498db37bGlenn Kastenimport android.os.BatteryStats;
569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Binder;
579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Bundle;
589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Handler;
599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Looper;
609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Message;
619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.PowerManager;
629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.RemoteException;
639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.ServiceManager;
649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.SystemClock;
659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.UserHandle;
669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.WorkSource;
679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.provider.Settings;
689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.provider.Telephony.Carriers;
699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.provider.Telephony.Sms.Intents;
709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.telephony.SmsMessage;
719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.telephony.TelephonyManager;
729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.telephony.gsm.GsmCellLocation;
739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.Log;
749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.NtpTrustedTime;
759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
766793ac943afeb16642f477c43ddfd27e498db37bGlenn Kastenimport java.io.File;
77e9d376b801b7890b1ef5006ed55de4208e64bb63San Mehatimport java.io.FileDescriptor;
78e9d376b801b7890b1ef5006ed55de4208e64bb63San Mehatimport java.io.FileInputStream;
79e9d376b801b7890b1ef5006ed55de4208e64bb63San Mehatimport java.io.IOException;
80e9d376b801b7890b1ef5006ed55de4208e64bb63San Mehatimport java.io.PrintWriter;
81e9d376b801b7890b1ef5006ed55de4208e64bb63San Mehatimport java.io.StringReader;
82e9d376b801b7890b1ef5006ed55de4208e64bb63San Mehatimport java.net.InetAddress;
83e9d376b801b7890b1ef5006ed55de4208e64bb63San Mehatimport java.net.UnknownHostException;
84e9d376b801b7890b1ef5006ed55de4208e64bb63San Mehatimport java.util.Date;
85e9d376b801b7890b1ef5006ed55de4208e64bb63San Mehatimport java.util.Map.Entry;
86e9d376b801b7890b1ef5006ed55de4208e64bb63San Mehatimport java.util.Properties;
87e9d376b801b7890b1ef5006ed55de4208e64bb63San Mehat
88e9d376b801b7890b1ef5006ed55de4208e64bb63San Mehat/**
89e9d376b801b7890b1ef5006ed55de4208e64bb63San Mehat * A GPS implementation of LocationProvider used by LocationManager.
90e9d376b801b7890b1ef5006ed55de4208e64bb63San Mehat *
91e9d376b801b7890b1ef5006ed55de4208e64bb63San Mehat * {@hide}
92e9d376b801b7890b1ef5006ed55de4208e64bb63San Mehat */
93e9d376b801b7890b1ef5006ed55de4208e64bb63San Mehatpublic class GpsLocationProvider implements LocationProviderInterface {
94e9d376b801b7890b1ef5006ed55de4208e64bb63San Mehat
95e9d376b801b7890b1ef5006ed55de4208e64bb63San Mehat    private static final String TAG = "GpsLocationProvider";
96e9d376b801b7890b1ef5006ed55de4208e64bb63San Mehat
979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final ProviderProperties PROPERTIES = new ProviderProperties(
1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            true, true, false, false, true, true, true,
1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Criteria.POWER_HIGH, Criteria.ACCURACY_FINE);
1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // these need to match GpsPositionMode enum in gps.h
1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int GPS_POSITION_MODE_STANDALONE = 0;
1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int GPS_POSITION_MODE_MS_BASED = 1;
1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int GPS_POSITION_MODE_MS_ASSISTED = 2;
1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
109887f355f99ff83d568ef2885a4fdcaae475583dfDianne Hackborn    // these need to match GpsPositionRecurrence enum in gps.h
1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int GPS_POSITION_RECURRENCE_PERIODIC = 0;
1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int GPS_POSITION_RECURRENCE_SINGLE = 1;
1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // these need to match GpsStatusValue defines in gps.h
1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int GPS_STATUS_NONE = 0;
11569a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes    private static final int GPS_STATUS_SESSION_BEGIN = 1;
1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int GPS_STATUS_SESSION_END = 2;
1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int GPS_STATUS_ENGINE_ON = 3;
11869a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes    private static final int GPS_STATUS_ENGINE_OFF = 4;
1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // these need to match GpsApgsStatusValue defines in gps.h
1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** AGPS status event values. */
1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int GPS_REQUEST_AGPS_DATA_CONN = 1;
1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int GPS_RELEASE_AGPS_DATA_CONN = 2;
1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int GPS_AGPS_DATA_CONNECTED = 3;
1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int GPS_AGPS_DATA_CONN_DONE = 4;
1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int GPS_AGPS_DATA_CONN_FAILED = 5;
1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // these need to match GpsLocationFlags enum in gps.h
1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int LOCATION_INVALID = 0;
1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int LOCATION_HAS_LAT_LONG = 1;
1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int LOCATION_HAS_ALTITUDE = 2;
1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int LOCATION_HAS_SPEED = 4;
1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int LOCATION_HAS_BEARING = 8;
1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int LOCATION_HAS_ACCURACY = 16;
1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// IMPORTANT - the GPS_DELETE_* symbols here must match constants in gps.h
1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int GPS_DELETE_EPHEMERIS = 0x0001;
1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int GPS_DELETE_ALMANAC = 0x0002;
1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int GPS_DELETE_POSITION = 0x0004;
1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int GPS_DELETE_TIME = 0x0008;
1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int GPS_DELETE_IONO = 0x0010;
1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int GPS_DELETE_UTC = 0x0020;
1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int GPS_DELETE_HEALTH = 0x0040;
1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int GPS_DELETE_SVDIR = 0x0080;
1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int GPS_DELETE_SVSTEER = 0x0100;
14669a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes    private static final int GPS_DELETE_SADATA = 0x0200;
1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int GPS_DELETE_RTI = 0x0400;
1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int GPS_DELETE_CELLDB_INFO = 0x8000;
14969a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes    private static final int GPS_DELETE_ALL = 0xFFFF;
1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // The GPS_CAPABILITY_* flags must match the values in gps.h
1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int GPS_CAPABILITY_SCHEDULING = 0x0000001;
1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int GPS_CAPABILITY_MSB = 0x0000002;
1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int GPS_CAPABILITY_MSA = 0x0000004;
1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int GPS_CAPABILITY_SINGLE_SHOT = 0x0000008;
1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int GPS_CAPABILITY_ON_DEMAND_TIME = 0x0000010;
1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // these need to match AGpsType enum in gps.h
1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int AGPS_TYPE_SUPL = 1;
1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int AGPS_TYPE_C2K = 2;
1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // these must match the definitions in gps.h
1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int APN_INVALID = 0;
1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int APN_IPV4 = 1;
1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int APN_IPV6 = 2;
1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int APN_IPV4V6 = 3;
1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // for mAGpsDataConnectionState
1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int AGPS_DATA_CONNECTION_CLOSED = 0;
1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int AGPS_DATA_CONNECTION_OPENING = 1;
1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int AGPS_DATA_CONNECTION_OPEN = 2;
1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Handler messages
174f1b56449f58963e4f0473d5e26961f68c31759f4Glenn Kasten    private static final int CHECK_LOCATION = 1;
175e9d376b801b7890b1ef5006ed55de4208e64bb63San Mehat    private static final int ENABLE = 2;
176f1b56449f58963e4f0473d5e26961f68c31759f4Glenn Kasten    private static final int SET_REQUEST = 3;
177f1b56449f58963e4f0473d5e26961f68c31759f4Glenn Kasten    private static final int UPDATE_NETWORK_STATE = 4;
178f1b56449f58963e4f0473d5e26961f68c31759f4Glenn Kasten    private static final int INJECT_NTP_TIME = 5;
179887f355f99ff83d568ef2885a4fdcaae475583dfDianne Hackborn    private static final int DOWNLOAD_XTRA_DATA = 6;
180f1b56449f58963e4f0473d5e26961f68c31759f4Glenn Kasten    private static final int UPDATE_LOCATION = 7;
181e9d376b801b7890b1ef5006ed55de4208e64bb63San Mehat    private static final int ADD_LISTENER = 8;
182e9d376b801b7890b1ef5006ed55de4208e64bb63San Mehat    private static final int REMOVE_LISTENER = 9;
183e9d376b801b7890b1ef5006ed55de4208e64bb63San Mehat    private static final int INJECT_NTP_TIME_FINISHED = 10;
18469a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes    private static final int DOWNLOAD_XTRA_DATA_FINISHED = 11;
1853e458241d9930465a20a861ecb42744355d48e48San Mehat
186f1b56449f58963e4f0473d5e26961f68c31759f4Glenn Kasten    // Request setid
1873e458241d9930465a20a861ecb42744355d48e48San Mehat    private static final int AGPS_RIL_REQUEST_SETID_IMSI = 1;
1883e458241d9930465a20a861ecb42744355d48e48San Mehat    private static final int AGPS_RIL_REQUEST_SETID_MSISDN = 2;
1893e458241d9930465a20a861ecb42744355d48e48San Mehat
1903e458241d9930465a20a861ecb42744355d48e48San Mehat    // Request ref location
1913e458241d9930465a20a861ecb42744355d48e48San Mehat    private static final int AGPS_RIL_REQUEST_REFLOC_CELLID = 1;
192f1b56449f58963e4f0473d5e26961f68c31759f4Glenn Kasten    private static final int AGPS_RIL_REQUEST_REFLOC_MAC = 2;
1936793ac943afeb16642f477c43ddfd27e498db37bGlenn Kasten
1943e458241d9930465a20a861ecb42744355d48e48San Mehat    // ref. location info
1953e458241d9930465a20a861ecb42744355d48e48San Mehat    private static final int AGPS_REF_LOCATION_TYPE_GSM_CELLID = 1;
1963e458241d9930465a20a861ecb42744355d48e48San Mehat    private static final int AGPS_REF_LOCATION_TYPE_UMTS_CELLID = 2;
197f1b56449f58963e4f0473d5e26961f68c31759f4Glenn Kasten    private static final int AGPS_REG_LOCATION_TYPE_MAC        = 3;
198f1b56449f58963e4f0473d5e26961f68c31759f4Glenn Kasten
199f1b56449f58963e4f0473d5e26961f68c31759f4Glenn Kasten    // set id info
200f1b56449f58963e4f0473d5e26961f68c31759f4Glenn Kasten    private static final int AGPS_SETID_TYPE_NONE = 0;
201f1b56449f58963e4f0473d5e26961f68c31759f4Glenn Kasten    private static final int AGPS_SETID_TYPE_IMSI = 1;
202f1b56449f58963e4f0473d5e26961f68c31759f4Glenn Kasten    private static final int AGPS_SETID_TYPE_MSISDN = 2;
203f1b56449f58963e4f0473d5e26961f68c31759f4Glenn Kasten
204a5109a878eeff22e32ee5ce1b1cd15e8daad5234San Mehat    private static final String PROPERTIES_FILE = "/etc/gps.conf";
205a5109a878eeff22e32ee5ce1b1cd15e8daad5234San Mehat
206a5109a878eeff22e32ee5ce1b1cd15e8daad5234San Mehat    private static final int GPS_GEOFENCE_UNAVAILABLE = 1<<0L;
207a5109a878eeff22e32ee5ce1b1cd15e8daad5234San Mehat    private static final int GPS_GEOFENCE_AVAILABLE = 1<<1L;
208a5109a878eeff22e32ee5ce1b1cd15e8daad5234San Mehat
209a5109a878eeff22e32ee5ce1b1cd15e8daad5234San Mehat    // GPS Geofence errors. Should match gps.h constants.
210a5109a878eeff22e32ee5ce1b1cd15e8daad5234San Mehat    private static final int GPS_GEOFENCE_OPERATION_SUCCESS = 0;
211a5109a878eeff22e32ee5ce1b1cd15e8daad5234San Mehat    private static final int GPS_GEOFENCE_ERROR_TOO_MANY_GEOFENCES = 100;
212a5109a878eeff22e32ee5ce1b1cd15e8daad5234San Mehat    private static final int GPS_GEOFENCE_ERROR_ID_EXISTS  = -101;
213a5109a878eeff22e32ee5ce1b1cd15e8daad5234San Mehat    private static final int GPS_GEOFENCE_ERROR_ID_UNKNOWN = -102;
214a5109a878eeff22e32ee5ce1b1cd15e8daad5234San Mehat    private static final int GPS_GEOFENCE_ERROR_INVALID_TRANSITION = -103;
215a5109a878eeff22e32ee5ce1b1cd15e8daad5234San Mehat    private static final int GPS_GEOFENCE_ERROR_GENERIC = -149;
216a5109a878eeff22e32ee5ce1b1cd15e8daad5234San Mehat
21769a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes    /** simpler wrapper for ProviderRequest + Worksource */
218f1b56449f58963e4f0473d5e26961f68c31759f4Glenn Kasten    private static class GpsRequest {
2195baa3a62a97544669fba6d65a11c07f252e654ddSteve Block        public ProviderRequest request;
220a5109a878eeff22e32ee5ce1b1cd15e8daad5234San Mehat        public WorkSource source;
2215baa3a62a97544669fba6d65a11c07f252e654ddSteve Block        public GpsRequest(ProviderRequest request, WorkSource source) {
222a5109a878eeff22e32ee5ce1b1cd15e8daad5234San Mehat            this.request = request;
223a5109a878eeff22e32ee5ce1b1cd15e8daad5234San Mehat            this.source = source;
2243e458241d9930465a20a861ecb42744355d48e48San Mehat        }
2253e458241d9930465a20a861ecb42744355d48e48San Mehat    }
2261fd0ec738b0a2b97cc28701aa37b1a9869afc684San Mehat
2271fd0ec738b0a2b97cc28701aa37b1a9869afc684San Mehat    private Object mLock = new Object();
2286793ac943afeb16642f477c43ddfd27e498db37bGlenn Kasten
2293e458241d9930465a20a861ecb42744355d48e48San Mehat    private int mLocationFlags = LOCATION_INVALID;
2303e458241d9930465a20a861ecb42744355d48e48San Mehat
2313e458241d9930465a20a861ecb42744355d48e48San Mehat    // current status
2323e458241d9930465a20a861ecb42744355d48e48San Mehat    private int mStatus = LocationProvider.TEMPORARILY_UNAVAILABLE;
2337e63789a0e0689d940609b1daceebc1bc08dcbefSan Mehat
2347e63789a0e0689d940609b1daceebc1bc08dcbefSan Mehat    // time for last status update
2357e63789a0e0689d940609b1daceebc1bc08dcbefSan Mehat    private long mStatusUpdateTime = SystemClock.elapsedRealtime();
2363e458241d9930465a20a861ecb42744355d48e48San Mehat
2373e458241d9930465a20a861ecb42744355d48e48San Mehat    // turn off GPS fix icon if we haven't received a fix in 10 seconds
2387e63789a0e0689d940609b1daceebc1bc08dcbefSan Mehat    private static final long RECENT_FIX_TIMEOUT = 10 * 1000;
2397e63789a0e0689d940609b1daceebc1bc08dcbefSan Mehat
2407e63789a0e0689d940609b1daceebc1bc08dcbefSan Mehat    // stop trying if we do not receive a fix within 60 seconds
2413762c311729fe9f3af085c14c5c1fb471d994c03Steve Block    private static final int NO_FIX_TIMEOUT = 60 * 1000;
2427e63789a0e0689d940609b1daceebc1bc08dcbefSan Mehat
2437e63789a0e0689d940609b1daceebc1bc08dcbefSan Mehat    // if the fix interval is below this we leave GPS on,
2441fd0ec738b0a2b97cc28701aa37b1a9869afc684San Mehat    // if above then we cycle the GPS driver.
24507b0465095bd9ab3412caefa4fcacbdc3825c64bGlenn Kasten    // Typical hot TTTF is ~5 seconds, so 10 seconds seems sane.
24607b0465095bd9ab3412caefa4fcacbdc3825c64bGlenn Kasten    private static final int GPS_POLLING_THRESHOLD_INTERVAL = 10 * 1000;
24707b0465095bd9ab3412caefa4fcacbdc3825c64bGlenn Kasten
24807b0465095bd9ab3412caefa4fcacbdc3825c64bGlenn Kasten    // how often to request NTP time, in milliseconds
24907b0465095bd9ab3412caefa4fcacbdc3825c64bGlenn Kasten    // current setting 24 hours
25007b0465095bd9ab3412caefa4fcacbdc3825c64bGlenn Kasten    private static final long NTP_INTERVAL = 24*60*60*1000;
25107b0465095bd9ab3412caefa4fcacbdc3825c64bGlenn Kasten    // how long to wait if we have a network error in NTP or XTRA downloading
25207b0465095bd9ab3412caefa4fcacbdc3825c64bGlenn Kasten    // current setting - 5 minutes
25307b0465095bd9ab3412caefa4fcacbdc3825c64bGlenn Kasten    private static final long RETRY_INTERVAL = 5*60*1000;
2547e63789a0e0689d940609b1daceebc1bc08dcbefSan Mehat
25507b0465095bd9ab3412caefa4fcacbdc3825c64bGlenn Kasten    // true if we are enabled, protected by this
256f1b56449f58963e4f0473d5e26961f68c31759f4Glenn Kasten    private boolean mEnabled;
257f1b56449f58963e4f0473d5e26961f68c31759f4Glenn Kasten
258f1b56449f58963e4f0473d5e26961f68c31759f4Glenn Kasten    // true if we have network connectivity
259f1b56449f58963e4f0473d5e26961f68c31759f4Glenn Kasten    private boolean mNetworkAvailable;
2607e63789a0e0689d940609b1daceebc1bc08dcbefSan Mehat
26169a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes    // states for injecting ntp and downloading xtra data
262f1b56449f58963e4f0473d5e26961f68c31759f4Glenn Kasten    private static final int STATE_PENDING_NETWORK = 0;
263f1b56449f58963e4f0473d5e26961f68c31759f4Glenn Kasten    private static final int STATE_DOWNLOADING = 1;
264f1b56449f58963e4f0473d5e26961f68c31759f4Glenn Kasten    private static final int STATE_IDLE = 2;
2650a42b811aea490a9a605b75f0320101f6eafd283San Mehat
266242d65bf9faf1d2bc3468490e510551140e23462San Mehat    // flags to trigger NTP or XTRA data download when network becomes available
2673e458241d9930465a20a861ecb42744355d48e48San Mehat    // initialized to true so we do NTP and XTRA when the network comes up after booting
2683e458241d9930465a20a861ecb42744355d48e48San Mehat    private int mInjectNtpTimePending = STATE_PENDING_NETWORK;
2693e458241d9930465a20a861ecb42744355d48e48San Mehat    private int mDownloadXtraDataPending = STATE_PENDING_NETWORK;
2703e458241d9930465a20a861ecb42744355d48e48San Mehat
271160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tate    // set to true if the GPS engine does not do on-demand NTP time requests
272160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tate    private boolean mPeriodicTimeInjection;
273160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tate
274160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tate    // true if GPS is navigating
27571f2cf116aab893e224056c38ab146bd1538dd3eSteve Block    private boolean mNavigating;
276160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tate
277160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tate    // true if GPS engine is on
278160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tate    private boolean mEngineOn;
279160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tate
280160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tate    // requested frequency of fixes, in milliseconds
281160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tate    private int mFixInterval = 1000;
282160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tate
283160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tate    // true if we started navigation
284160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tate    private boolean mStarted;
285160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tate
286160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tate    // true if single shot request is in progress
287160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tate    private boolean mSingleShot;
2886793ac943afeb16642f477c43ddfd27e498db37bGlenn Kasten
2896793ac943afeb16642f477c43ddfd27e498db37bGlenn Kasten    // capabilities of the GPS engine
2906793ac943afeb16642f477c43ddfd27e498db37bGlenn Kasten    private int mEngineCapabilities;
291cc767191cfb675f744e0165608b0a4196aba2b37Glenn Kasten
2926793ac943afeb16642f477c43ddfd27e498db37bGlenn Kasten    // true if XTRA is supported
2936793ac943afeb16642f477c43ddfd27e498db37bGlenn Kasten    private boolean mSupportsXtra;
2946793ac943afeb16642f477c43ddfd27e498db37bGlenn Kasten
2956793ac943afeb16642f477c43ddfd27e498db37bGlenn Kasten    // for calculating time to first fix
2966793ac943afeb16642f477c43ddfd27e498db37bGlenn Kasten    private long mFixRequestTime = 0;
2976793ac943afeb16642f477c43ddfd27e498db37bGlenn Kasten    // time to first fix for most recent session
298cc767191cfb675f744e0165608b0a4196aba2b37Glenn Kasten    private int mTimeToFirstFix = 0;
299cc767191cfb675f744e0165608b0a4196aba2b37Glenn Kasten    // time we received our last fix
300cc767191cfb675f744e0165608b0a4196aba2b37Glenn Kasten    private long mLastFixTime;
3016793ac943afeb16642f477c43ddfd27e498db37bGlenn Kasten
3026793ac943afeb16642f477c43ddfd27e498db37bGlenn Kasten    private int mPositionMode;
3039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // properties loaded from PROPERTIES_FILE
3059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private Properties mProperties;
306160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tate    private String mSuplServerHost;
307160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tate    private int mSuplServerPort;
308160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tate    private String mC2KServerHost;
309160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tate    private int mC2KServerPort;
310160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tate
311160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tate    private final Context mContext;
312160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tate    private final NtpTrustedTime mNtpTime;
3133762c311729fe9f3af085c14c5c1fb471d994c03Steve Block    private final ILocationManager mILocationManager;
314160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tate    private Location mLocation = new Location(LocationManager.GPS_PROVIDER);
315160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tate    private Bundle mLocationExtras = new Bundle();
316160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tate    private GpsStatusListenerHelper mListenerHelper = new GpsStatusListenerHelper() {
317160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tate        @Override
318160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tate        protected boolean isSupported() {
319160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tate            return native_is_measurement_supported();
320160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tate        }
321887f355f99ff83d568ef2885a4fdcaae475583dfDianne Hackborn    };
322887f355f99ff83d568ef2885a4fdcaae475583dfDianne Hackborn
323887f355f99ff83d568ef2885a4fdcaae475583dfDianne Hackborn    // Handler for processing events
3246793ac943afeb16642f477c43ddfd27e498db37bGlenn Kasten    private Handler mHandler;
325887f355f99ff83d568ef2885a4fdcaae475583dfDianne Hackborn
3266793ac943afeb16642f477c43ddfd27e498db37bGlenn Kasten    private String mAGpsApn;
327887f355f99ff83d568ef2885a4fdcaae475583dfDianne Hackborn    private int mApnIpType;
3289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int mAGpsDataConnectionState;
32969a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes    private InetAddress mAGpsDataConnectionIpAddr;
3306215d3ff4b5dfa52a5d8b9a42e343051f31066a5Steve Block    private final ConnectivityManager mConnMgr;
3319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final GpsNetInitiatedHandler mNIHandler;
3329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Wakelocks
3349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final static String WAKELOCK_KEY = "GpsLocationProvider";
3359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final PowerManager.WakeLock mWakeLock;
3369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Alarms
3389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final static String ALARM_WAKEUP = "com.android.internal.location.ALARM_WAKEUP";
3399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final static String ALARM_TIMEOUT = "com.android.internal.location.ALARM_TIMEOUT";
3409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final AlarmManager mAlarmManager;
3419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final PendingIntent mWakeupIntent;
3429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final PendingIntent mTimeoutIntent;
3439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final IAppOpsService mAppOpsService;
3459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final IBatteryStats mBatteryStats;
3469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3476793ac943afeb16642f477c43ddfd27e498db37bGlenn Kasten    // only modified on handler thread
3489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private WorkSource mClientSource = new WorkSource();
3496215d3ff4b5dfa52a5d8b9a42e343051f31066a5Steve Block
3509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private GeofenceHardwareImpl mGeofenceHardwareImpl;
3519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final IGpsStatusProvider mGpsStatusProvider = new IGpsStatusProvider.Stub() {
3539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
3549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void addGpsStatusListener(IGpsStatusListener listener) throws RemoteException {
3559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mListenerHelper.addListener(listener);
3569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
35710e89712863f5b91a2982dc1783fbdfe39c1485dJeff Brown
35810e89712863f5b91a2982dc1783fbdfe39c1485dJeff Brown        @Override
35910e89712863f5b91a2982dc1783fbdfe39c1485dJeff Brown        public void removeGpsStatusListener(IGpsStatusListener listener) {
36010e89712863f5b91a2982dc1783fbdfe39c1485dJeff Brown            mListenerHelper.removeListener(listener);
36110e89712863f5b91a2982dc1783fbdfe39c1485dJeff Brown        }
36210e89712863f5b91a2982dc1783fbdfe39c1485dJeff Brown    };
36310e89712863f5b91a2982dc1783fbdfe39c1485dJeff Brown
3649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final GpsMeasurementsProvider mGpsMeasurementsProvider = new GpsMeasurementsProvider() {
36510e89712863f5b91a2982dc1783fbdfe39c1485dJeff Brown        @Override
3669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public boolean isSupported() {
3679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return native_is_measurement_supported();
3689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
3719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        protected void onFirstListenerAdded() {
3729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            native_start_measurement_collection();
37369a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes        }
3749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
37669a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes        protected void onLastListenerRemoved() {
3779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            native_stop_measurement_collection();
3789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    };
3809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public IGpsStatusProvider getGpsStatusProvider() {
3829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mGpsStatusProvider;
3839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public IGpsGeofenceHardware getGpsGeofenceProxy() {
3869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mGpsGeofenceBinder;
3879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public GpsMeasurementsProvider getGpsMeasurementsProvider() {
3909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mGpsMeasurementsProvider;
3919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final BroadcastReceiver mBroadcastReciever = new BroadcastReceiver() {
3949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override public void onReceive(Context context, Intent intent) {
3959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            String action = intent.getAction();
3969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (action.equals(ALARM_WAKEUP)) {
3989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (DEBUG) Log.d(TAG, "ALARM_WAKEUP");
3999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                startNavigating(false);
4009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else if (action.equals(ALARM_TIMEOUT)) {
4016215d3ff4b5dfa52a5d8b9a42e343051f31066a5Steve Block                if (DEBUG) Log.d(TAG, "ALARM_TIMEOUT");
4029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                hibernate();
4039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else if (action.equals(Intents.DATA_SMS_RECEIVED_ACTION)) {
4049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                checkSmsSuplInit(intent);
40559325eb31f25704bb88c348160bb69e7c1aa3b48Dianne Hackborn            } else if (action.equals(Intents.WAP_PUSH_RECEIVED_ACTION)) {
4069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                checkWapSuplInit(intent);
4079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             } else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
40869a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes                 int networkState;
4099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                 if (intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false)) {
4108564c8da817a845353d213acd8636b76f567b234Steve Block                     networkState = LocationProvider.TEMPORARILY_UNAVAILABLE;
4119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                 } else {
4129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                     networkState = LocationProvider.AVAILABLE;
41369a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes                 }
4149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                 // retrieve NetworkInfo result for this UID
4169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                 NetworkInfo info =
41769a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes                         intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
4189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                 ConnectivityManager connManager = (ConnectivityManager)
4198564c8da817a845353d213acd8636b76f567b234Steve Block                         mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
4209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                 info = connManager.getNetworkInfo(info.getType());
4219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                 updateNetworkState(networkState, info);
4239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             }
4249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4250bca96bcbfe559f9330a01f723c5c9cba51ec05aMarco Nelissen    };
42669a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes
4279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void checkSmsSuplInit(Intent intent) {
42859325eb31f25704bb88c348160bb69e7c1aa3b48Dianne Hackborn        SmsMessage[] messages = Intents.getMessagesFromIntent(intent);
4299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i=0; i <messages.length; i++) {
4309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            byte[] supl_init = messages[i].getUserData();
4319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            native_agps_ni_message(supl_init,supl_init.length);
4329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void checkWapSuplInit(Intent intent) {
4369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        byte[] supl_init = (byte[]) intent.getExtra("data");
4379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        native_agps_ni_message(supl_init,supl_init.length);
4389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static boolean isSupported() {
4410bca96bcbfe559f9330a01f723c5c9cba51ec05aMarco Nelissen        return native_is_supported();
4429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public GpsLocationProvider(Context context, ILocationManager ilocationManager,
4459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Looper looper) {
4469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext = context;
4479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mNtpTime = NtpTrustedTime.getInstance(context);
4489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mILocationManager = ilocationManager;
44969a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes        mNIHandler = new GpsNetInitiatedHandler(context);
4509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mLocation.setExtras(mLocationExtras);
4529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
45359325eb31f25704bb88c348160bb69e7c1aa3b48Dianne Hackborn        // Create a wake lock
45459325eb31f25704bb88c348160bb69e7c1aa3b48Dianne Hackborn        PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
45559325eb31f25704bb88c348160bb69e7c1aa3b48Dianne Hackborn        mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
45659325eb31f25704bb88c348160bb69e7c1aa3b48Dianne Hackborn        mWakeLock.setReferenceCounted(true);
45759325eb31f25704bb88c348160bb69e7c1aa3b48Dianne Hackborn
45859325eb31f25704bb88c348160bb69e7c1aa3b48Dianne Hackborn        mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
45959325eb31f25704bb88c348160bb69e7c1aa3b48Dianne Hackborn        mWakeupIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_WAKEUP), 0);
46059325eb31f25704bb88c348160bb69e7c1aa3b48Dianne Hackborn        mTimeoutIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_TIMEOUT), 0);
46159325eb31f25704bb88c348160bb69e7c1aa3b48Dianne Hackborn
46259325eb31f25704bb88c348160bb69e7c1aa3b48Dianne Hackborn        mConnMgr = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
46359325eb31f25704bb88c348160bb69e7c1aa3b48Dianne Hackborn
46459325eb31f25704bb88c348160bb69e7c1aa3b48Dianne Hackborn        // App ops service to keep track of who is accessing the GPS
46559325eb31f25704bb88c348160bb69e7c1aa3b48Dianne Hackborn        mAppOpsService = IAppOpsService.Stub.asInterface(ServiceManager.getService(
46659325eb31f25704bb88c348160bb69e7c1aa3b48Dianne Hackborn                Context.APP_OPS_SERVICE));
4679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Battery statistics service to be notified when GPS turns on or off
4699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService(
4706215d3ff4b5dfa52a5d8b9a42e343051f31066a5Steve Block                BatteryStats.SERVICE_NAME));
47169a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes
4729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mProperties = new Properties();
47369a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes        try {
4749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            File file = new File(PROPERTIES_FILE);
4759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            FileInputStream stream = new FileInputStream(file);
47669a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes            mProperties.load(stream);
4779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            stream.close();
4789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mSuplServerHost = mProperties.getProperty("SUPL_HOST");
4809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            String portString = mProperties.getProperty("SUPL_PORT");
4819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mSuplServerHost != null && portString != null) {
4829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                try {
48369a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes                    mSuplServerPort = Integer.parseInt(portString);
4849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } catch (NumberFormatException e) {
4859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    Log.e(TAG, "unable to parse SUPL_PORT: " + portString);
4869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
4879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
4889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
48969a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes            mC2KServerHost = mProperties.getProperty("C2K_HOST");
4909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            portString = mProperties.getProperty("C2K_PORT");
4919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mC2KServerHost != null && portString != null) {
49269a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes                try {
4939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mC2KServerPort = Integer.parseInt(portString);
4949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } catch (NumberFormatException e) {
4959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    Log.e(TAG, "unable to parse C2K_PORT: " + portString);
4969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
4976215d3ff4b5dfa52a5d8b9a42e343051f31066a5Steve Block            }
4989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } catch (IOException e) {
49969a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes            Log.w(TAG, "Could not open GPS configuration file " + PROPERTIES_FILE);
5009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // construct handler, listen for events
5039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mHandler = new ProviderHandler(looper);
5049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        listenForBroadcasts();
50569a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes
5069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // also listen for PASSIVE_PROVIDER updates
5079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mHandler.post(new Runnable() {
5089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            @Override
50969a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes            public void run() {
5109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                LocationManager locManager =
5119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
5129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final long minTime = 0;
5139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final float minDistance = 0;
51469a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes                final boolean oneShot = false;
5156215d3ff4b5dfa52a5d8b9a42e343051f31066a5Steve Block                LocationRequest request = LocationRequest.createFromDeprecatedProvider(
5169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        LocationManager.PASSIVE_PROVIDER,
5179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        minTime,
5189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        minDistance,
51969a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes                        oneShot);
5209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Don't keep track of this request since it's done on behalf of other clients
52169a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes                // (which are kept track of separately).
5229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                request.setHideFromAppOps(true);
5239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                locManager.requestLocationUpdates(
5249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        request,
5259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        new NetworkLocationListener(),
5269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        mHandler.getLooper());
52769a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes            }
5289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        });
5298564c8da817a845353d213acd8636b76f567b234Steve Block    }
5309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void listenForBroadcasts() {
5329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        IntentFilter intentFilter = new IntentFilter();
53369a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes        intentFilter.addAction(Intents.DATA_SMS_RECEIVED_ACTION);
5349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        intentFilter.addDataScheme("sms");
53569a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes        intentFilter.addDataAuthority("localhost","7275");
5369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.registerReceiver(mBroadcastReciever, intentFilter, null, mHandler);
5379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        intentFilter = new IntentFilter();
5396215d3ff4b5dfa52a5d8b9a42e343051f31066a5Steve Block        intentFilter.addAction(Intents.WAP_PUSH_RECEIVED_ACTION);
5409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
5419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            intentFilter.addDataType("application/vnd.omaloc-supl-init");
5429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } catch (IntentFilter.MalformedMimeTypeException e) {
5439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Log.w(TAG, "Malformed SUPL init mime type");
544add868cebaf62cffe96e79764ea0b7f2320a03ebAmith Yamasani        }
5459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.registerReceiver(mBroadcastReciever, intentFilter, null, mHandler);
5469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        intentFilter = new IntentFilter();
5489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        intentFilter.addAction(ALARM_WAKEUP);
5499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        intentFilter.addAction(ALARM_TIMEOUT);
5509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
5519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.registerReceiver(mBroadcastReciever, intentFilter, null, mHandler);
5529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5546215d3ff4b5dfa52a5d8b9a42e343051f31066a5Steve Block    /**
5559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Returns the name of this provider.
5569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
5579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
5589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public String getName() {
5599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return LocationManager.GPS_PROVIDER;
5609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
5639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public ProviderProperties getProperties() {
5649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return PROPERTIES;
5659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void updateNetworkState(int state, NetworkInfo info) {
56869a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes        sendMessage(UPDATE_NETWORK_STATE, state, info);
5699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5718564c8da817a845353d213acd8636b76f567b234Steve Block    private void handleUpdateNetworkState(int state, NetworkInfo info) {
5729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mNetworkAvailable = (state == LocationProvider.AVAILABLE);
57369a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes
5746215d3ff4b5dfa52a5d8b9a42e343051f31066a5Steve Block        if (DEBUG) {
5759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Log.d(TAG, "updateNetworkState " + (mNetworkAvailable ? "available" : "unavailable")
5769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                + " info: " + info);
5779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (info != null) {
5809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            boolean dataEnabled = Settings.Global.getInt(mContext.getContentResolver(),
5819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                         Settings.Global.MOBILE_DATA, 1) == 1;
58269a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes            boolean networkAvailable = info.isAvailable() && dataEnabled;
5839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            String defaultApn = getSelectedApn();
5849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (defaultApn == null) {
58569a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes                defaultApn = "dummy-apn";
5869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            native_update_network_state(info.isConnected(), info.getType(),
5899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                        info.isRoaming(), networkAvailable,
5909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                        info.getExtraInfo(), defaultApn);
59169a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes        }
5929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
59369a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes        if (info != null && info.getType() == ConnectivityManager.TYPE_MOBILE_SUPL
5949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                && mAGpsDataConnectionState == AGPS_DATA_CONNECTION_OPENING) {
59569a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes            if (mNetworkAvailable) {
5969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                String apnName = info.getExtraInfo();
5979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (apnName == null) {
5989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    /* Assign a dummy value in the case of C2K as otherwise we will have a runtime
59969a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes                    exception in the following call to native_agps_data_conn_open*/
6009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    apnName = "dummy-apn";
6019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
6029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mAGpsApn = apnName;
6039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mApnIpType = getApnIpType(apnName);
6049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                setRouting();
6059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (DEBUG) {
60669a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes                    String message = String.format(
6079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            "native_agps_data_conn_open: mAgpsApn=%s, mApnIpType=%s",
60869a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes                            mAGpsApn, mApnIpType);
6099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    Log.d(TAG, message);
6109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
6119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                native_agps_data_conn_open(mAGpsApn, mApnIpType);
6129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPEN;
6139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
6149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Log.e(TAG, "call native_agps_data_conn_failed, info: " + info);
6159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mAGpsApn = null;
6169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mApnIpType = APN_INVALID;
61769a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes                mAGpsDataConnectionState = AGPS_DATA_CONNECTION_CLOSED;
6189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                native_agps_data_conn_failed();
6199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
6206215d3ff4b5dfa52a5d8b9a42e343051f31066a5Steve Block        }
6219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mNetworkAvailable) {
6239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mInjectNtpTimePending == STATE_PENDING_NETWORK) {
6249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                sendMessage(INJECT_NTP_TIME, 0, null);
6259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
6269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mDownloadXtraDataPending == STATE_PENDING_NETWORK) {
6279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                sendMessage(DOWNLOAD_XTRA_DATA, 0, null);
6289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
6299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void handleInjectNtpTime() {
6339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mInjectNtpTimePending == STATE_DOWNLOADING) {
6349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // already downloading data
6359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return;
6369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!mNetworkAvailable) {
63869a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes            // try again when network is up
6399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mInjectNtpTimePending = STATE_PENDING_NETWORK;
6409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return;
6419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
64269a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes        mInjectNtpTimePending = STATE_DOWNLOADING;
6439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
64469a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes        // hold wake lock while task runs
6459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mWakeLock.acquire();
6469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        AsyncTask.THREAD_POOL_EXECUTOR.execute(new Runnable() {
6479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            @Override
64869a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes            public void run() {
6499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                long delay;
6509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // force refresh NTP cache when outdated
6529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (mNtpTime.getCacheAge() >= NTP_INTERVAL) {
65369a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes                    mNtpTime.forceRefresh();
6549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
6559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // only update when NTP time is fresh
65769a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes                if (mNtpTime.getCacheAge() < NTP_INTERVAL) {
6589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    long time = mNtpTime.getCachedNtpTime();
6599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    long timeReference = mNtpTime.getCachedNtpTimeReference();
6609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    long certainty = mNtpTime.getCacheCertainty();
6619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    long now = System.currentTimeMillis();
6629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    Log.d(TAG, "NTP server returned: "
6649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            + time + " (" + new Date(time)
6659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            + ") reference: " + timeReference
6669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            + " certainty: " + certainty
6679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            + " system time offset: " + (time - now));
6689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    native_inject_time(time, timeReference, (int) certainty);
6709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    delay = NTP_INTERVAL;
6719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else {
672c64edde69d18498fb2954f71a546357b07ab996aEvan Millar                    if (DEBUG) Log.d(TAG, "requestTime failed");
67369a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes                    delay = RETRY_INTERVAL;
674c64edde69d18498fb2954f71a546357b07ab996aEvan Millar                }
6759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
67669a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes                sendMessage(INJECT_NTP_TIME_FINISHED, 0, null);
6779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (mPeriodicTimeInjection) {
6799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // send delayed message for next NTP injection
6809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // since this is delayed and not urgent we do not hold a wake lock here
68169a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes                    mHandler.sendEmptyMessageDelayed(INJECT_NTP_TIME, delay);
6829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
6839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // release wake lock held by task
6859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mWakeLock.release();
6869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
6879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        });
6889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void handleDownloadXtraData() {
6919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mDownloadXtraDataPending == STATE_DOWNLOADING) {
6929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // already downloading data
6939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return;
6949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!mNetworkAvailable) {
6969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // try again when network is up
6979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mDownloadXtraDataPending = STATE_PENDING_NETWORK;
6989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return;
6999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mDownloadXtraDataPending = STATE_DOWNLOADING;
7019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
702c64edde69d18498fb2954f71a546357b07ab996aEvan Millar        // hold wake lock while task runs
7039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mWakeLock.acquire();
70469a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes        AsyncTask.THREAD_POOL_EXECUTOR.execute(new Runnable() {
7059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            @Override
70669a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes            public void run() {
7079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                GpsXtraDownloader xtraDownloader = new GpsXtraDownloader(mContext, mProperties);
7089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                byte[] data = xtraDownloader.downloadXtraData();
7099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (data != null) {
7109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (DEBUG) {
7119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        Log.d(TAG, "calling native_inject_xtra_data");
7129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
7139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    native_inject_xtra_data(data, data.length);
714c64edde69d18498fb2954f71a546357b07ab996aEvan Millar                }
7159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                sendMessage(DOWNLOAD_XTRA_DATA_FINISHED, 0, null);
7179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
71869a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes                if (data == null) {
7199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // try again later
7209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // since this is delayed and not urgent we do not hold a wake lock here
721c64edde69d18498fb2954f71a546357b07ab996aEvan Millar                    mHandler.sendEmptyMessageDelayed(DOWNLOAD_XTRA_DATA, RETRY_INTERVAL);
7229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
7239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // release wake lock held by task
7259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mWakeLock.release();
7269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
727c64edde69d18498fb2954f71a546357b07ab996aEvan Millar        });
7289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void handleUpdateLocation(Location location) {
7319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (location.hasAccuracy()) {
7329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            native_inject_location(location.getLatitude(), location.getLongitude(),
73369a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes                    location.getAccuracy());
734c64edde69d18498fb2954f71a546357b07ab996aEvan Millar        }
7359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
737c64edde69d18498fb2954f71a546357b07ab996aEvan Millar    /**
7389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Enables this provider.  When enabled, calls to getStatus()
7399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * must be handled.  Hardware may be started up
7409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * when the provider is enabled.
7419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
74269a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes    @Override
7436215d3ff4b5dfa52a5d8b9a42e343051f31066a5Steve Block    public void enable() {
74469a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes        synchronized (mLock) {
7459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mEnabled) return;
7469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mEnabled = true;
7479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        sendMessage(ENABLE, 1, null);
7509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void handleEnable() {
7539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (DEBUG) Log.d(TAG, "handleEnable");
7549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean enabled = native_init();
7569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (enabled) {
7589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mSupportsXtra = native_supports_xtra();
7599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mSuplServerHost != null) {
7609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                native_set_agps_server(AGPS_TYPE_SUPL, mSuplServerHost, mSuplServerPort);
7619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
7629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mC2KServerHost != null) {
7639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                native_set_agps_server(AGPS_TYPE_C2K, mC2KServerHost, mC2KServerPort);
76469a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes            }
7659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
7669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            synchronized (mLock) {
7679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mEnabled = false;
7689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
7699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Log.w(TAG, "Failed to enable location provider");
7709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
77269a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes
7739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
7749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Disables this provider.  When disabled, calls to getStatus()
7759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * need not be handled.  Hardware may be shut
776c64edde69d18498fb2954f71a546357b07ab996aEvan Millar     * down while the provider is disabled.
77769a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes     */
778c64edde69d18498fb2954f71a546357b07ab996aEvan Millar    @Override
779c64edde69d18498fb2954f71a546357b07ab996aEvan Millar    public void disable() {
780c64edde69d18498fb2954f71a546357b07ab996aEvan Millar        synchronized (mLock) {
781c64edde69d18498fb2954f71a546357b07ab996aEvan Millar            if (!mEnabled) return;
78269a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes            mEnabled = false;
78369a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes        }
784c64edde69d18498fb2954f71a546357b07ab996aEvan Millar
78569a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes        sendMessage(ENABLE, 0, null);
786c64edde69d18498fb2954f71a546357b07ab996aEvan Millar    }
78769a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes
788c64edde69d18498fb2954f71a546357b07ab996aEvan Millar    private void handleDisable() {
789c64edde69d18498fb2954f71a546357b07ab996aEvan Millar        if (DEBUG) Log.d(TAG, "handleDisable");
790c64edde69d18498fb2954f71a546357b07ab996aEvan Millar
791c64edde69d18498fb2954f71a546357b07ab996aEvan Millar        updateClientUids(new WorkSource());
792c64edde69d18498fb2954f71a546357b07ab996aEvan Millar        stopNavigating();
793c64edde69d18498fb2954f71a546357b07ab996aEvan Millar        mAlarmManager.cancel(mWakeupIntent);
794c64edde69d18498fb2954f71a546357b07ab996aEvan Millar        mAlarmManager.cancel(mTimeoutIntent);
795c64edde69d18498fb2954f71a546357b07ab996aEvan Millar
79669a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes        // do this before releasing wakelock
797c64edde69d18498fb2954f71a546357b07ab996aEvan Millar        native_cleanup();
798c64edde69d18498fb2954f71a546357b07ab996aEvan Millar    }
799c64edde69d18498fb2954f71a546357b07ab996aEvan Millar
800c64edde69d18498fb2954f71a546357b07ab996aEvan Millar    @Override
801c64edde69d18498fb2954f71a546357b07ab996aEvan Millar    public boolean isEnabled() {
802c64edde69d18498fb2954f71a546357b07ab996aEvan Millar        synchronized (mLock) {
803c64edde69d18498fb2954f71a546357b07ab996aEvan Millar            return mEnabled;
804c64edde69d18498fb2954f71a546357b07ab996aEvan Millar        }
805c64edde69d18498fb2954f71a546357b07ab996aEvan Millar    }
806c64edde69d18498fb2954f71a546357b07ab996aEvan Millar
80769a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes    @Override
808c64edde69d18498fb2954f71a546357b07ab996aEvan Millar    public int getStatus(Bundle extras) {
8098564c8da817a845353d213acd8636b76f567b234Steve Block        if (extras != null) {
810c64edde69d18498fb2954f71a546357b07ab996aEvan Millar            extras.putInt("satellites", mSvCount);
811c64edde69d18498fb2954f71a546357b07ab996aEvan Millar        }
81269a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes        return mStatus;
813c64edde69d18498fb2954f71a546357b07ab996aEvan Millar    }
814c64edde69d18498fb2954f71a546357b07ab996aEvan Millar
815c64edde69d18498fb2954f71a546357b07ab996aEvan Millar    private void updateStatus(int status, int svCount) {
81669a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes        if (status != mStatus || svCount != mSvCount) {
817c64edde69d18498fb2954f71a546357b07ab996aEvan Millar            mStatus = status;
8188564c8da817a845353d213acd8636b76f567b234Steve Block            mSvCount = svCount;
819c64edde69d18498fb2954f71a546357b07ab996aEvan Millar            mLocationExtras.putInt("satellites", svCount);
820c64edde69d18498fb2954f71a546357b07ab996aEvan Millar            mStatusUpdateTime = SystemClock.elapsedRealtime();
821c64edde69d18498fb2954f71a546357b07ab996aEvan Millar        }
82269a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes    }
82369a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes
824c64edde69d18498fb2954f71a546357b07ab996aEvan Millar    @Override
82569a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes    public long getStatusUpdateTime() {
826c64edde69d18498fb2954f71a546357b07ab996aEvan Millar        return mStatusUpdateTime;
827c64edde69d18498fb2954f71a546357b07ab996aEvan Millar    }
8289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
8309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setRequest(ProviderRequest request, WorkSource source) {
8319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        sendMessage(SET_REQUEST, 0, new GpsRequest(request, source));
83269a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes    }
8339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void handleSetRequest(ProviderRequest request, WorkSource source) {
8359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean singleShot = false;
8369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // see if the request is for a single update
8389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (request.locationRequests != null && request.locationRequests.size() > 0) {
8399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // if any request has zero or more than one updates
8409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // requested, then this is not single-shot mode
8419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            singleShot = true;
8426215d3ff4b5dfa52a5d8b9a42e343051f31066a5Steve Block
8439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (LocationRequest lr : request.locationRequests) {
8449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (lr.getNumUpdates() != 1) {
8459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    singleShot = false;
8469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
847906497c574d45d8dfd295b16dece0d0bc32c0895Dianne Hackborn            }
848906497c574d45d8dfd295b16dece0d0bc32c0895Dianne Hackborn        }
849906497c574d45d8dfd295b16dece0d0bc32c0895Dianne Hackborn
850906497c574d45d8dfd295b16dece0d0bc32c0895Dianne Hackborn        if (DEBUG) Log.d(TAG, "setRequest " + request);
851906497c574d45d8dfd295b16dece0d0bc32c0895Dianne Hackborn        if (request.reportLocation) {
852906497c574d45d8dfd295b16dece0d0bc32c0895Dianne Hackborn            // update client uids
853906497c574d45d8dfd295b16dece0d0bc32c0895Dianne Hackborn            updateClientUids(source);
8549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mFixInterval = (int) request.interval;
8569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // check for overflow
8589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mFixInterval != request.interval) {
85969a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes                Log.w(TAG, "interval overflow: " + request.interval);
8609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mFixInterval = Integer.MAX_VALUE;
8619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
86269a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes
86369a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes            // apply request to GPS engine
8649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mStarted && hasCapability(GPS_CAPABILITY_SCHEDULING)) {
8659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // change period
8669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (!native_set_position_mode(mPositionMode, GPS_POSITION_RECURRENCE_PERIODIC,
8679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        mFixInterval, 0, 0)) {
8689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    Log.e(TAG, "set_position_mode failed in setMinTime()");
8699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
8709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else if (!mStarted) {
8719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // start GPS
8729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                startNavigating(singleShot);
8739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
8749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
8759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            updateClientUids(new WorkSource());
8769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            stopNavigating();
8789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mAlarmManager.cancel(mWakeupIntent);
8799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mAlarmManager.cancel(mTimeoutIntent);
8809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void updateClientUids(WorkSource source) {
8849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Update work source.
8859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        WorkSource[] changes = mClientSource.setReturningDiffs(source);
8869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (changes == null) {
8879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return;
8889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        WorkSource newWork = changes[0];
8909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        WorkSource goneWork = changes[1];
8919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Update sources that were not previously tracked.
8939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (newWork != null) {
8949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int lastuid = -1;
8959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int i=0; i<newWork.size(); i++) {
8969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                try {
8979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    int uid = newWork.get(i);
8989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mAppOpsService.startOperation(AppOpsManager.getToken(mAppOpsService),
8999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            AppOpsManager.OP_GPS, uid, newWork.getName(i));
9009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (uid != lastuid) {
9019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        lastuid = uid;
9026793ac943afeb16642f477c43ddfd27e498db37bGlenn Kasten                        mBatteryStats.noteStartGps(uid);
903160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tate                    }
9049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } catch (RemoteException e) {
9059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    Log.w(TAG, "RemoteException", e);
906e9d376b801b7890b1ef5006ed55de4208e64bb63San Mehat                }
9073e458241d9930465a20a861ecb42744355d48e48San Mehat            }
9089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Update sources that are no longer tracked.
9119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (goneWork != null) {
9129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int lastuid = -1;
913906497c574d45d8dfd295b16dece0d0bc32c0895Dianne Hackborn            for (int i=0; i<goneWork.size(); i++) {
9140bca96bcbfe559f9330a01f723c5c9cba51ec05aMarco Nelissen                try {
91559325eb31f25704bb88c348160bb69e7c1aa3b48Dianne Hackborn                    int uid = goneWork.get(i);
9169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mAppOpsService.finishOperation(AppOpsManager.getToken(mAppOpsService),
9179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            AppOpsManager.OP_GPS, uid, goneWork.getName(i));
9189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (uid != lastuid) {
919c64edde69d18498fb2954f71a546357b07ab996aEvan Millar                        lastuid = uid;
9209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        mBatteryStats.noteStopGps(uid);
9219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
9229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } catch (RemoteException e) {
9239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    Log.w(TAG, "RemoteException", e);
9249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
9259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
9269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
9309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean sendExtraCommand(String command, Bundle extras) {
9319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        long identity = Binder.clearCallingIdentity();
933        boolean result = false;
934
935        if ("delete_aiding_data".equals(command)) {
936            result = deleteAidingData(extras);
937        } else if ("force_time_injection".equals(command)) {
938            sendMessage(INJECT_NTP_TIME, 0, null);
939            result = true;
940        } else if ("force_xtra_injection".equals(command)) {
941            if (mSupportsXtra) {
942                xtraDownloadRequest();
943                result = true;
944            }
945        } else {
946            Log.w(TAG, "sendExtraCommand: unknown command " + command);
947        }
948
949        Binder.restoreCallingIdentity(identity);
950        return result;
951    }
952
953    private IGpsGeofenceHardware mGpsGeofenceBinder = new IGpsGeofenceHardware.Stub() {
954        public boolean isHardwareGeofenceSupported() {
955            return native_is_geofence_supported();
956        }
957
958        public boolean addCircularHardwareGeofence(int geofenceId, double latitude,
959                double longitude, double radius, int lastTransition, int monitorTransitions,
960                int notificationResponsiveness, int unknownTimer) {
961            return native_add_geofence(geofenceId, latitude, longitude, radius,
962                    lastTransition, monitorTransitions, notificationResponsiveness, unknownTimer);
963        }
964
965        public boolean removeHardwareGeofence(int geofenceId) {
966            return native_remove_geofence(geofenceId);
967        }
968
969        public boolean pauseHardwareGeofence(int geofenceId) {
970            return native_pause_geofence(geofenceId);
971        }
972
973        public boolean resumeHardwareGeofence(int geofenceId, int monitorTransition) {
974            return native_resume_geofence(geofenceId, monitorTransition);
975        }
976    };
977
978    private boolean deleteAidingData(Bundle extras) {
979        int flags;
980
981        if (extras == null) {
982            flags = GPS_DELETE_ALL;
983        } else {
984            flags = 0;
985            if (extras.getBoolean("ephemeris")) flags |= GPS_DELETE_EPHEMERIS;
986            if (extras.getBoolean("almanac")) flags |= GPS_DELETE_ALMANAC;
987            if (extras.getBoolean("position")) flags |= GPS_DELETE_POSITION;
988            if (extras.getBoolean("time")) flags |= GPS_DELETE_TIME;
989            if (extras.getBoolean("iono")) flags |= GPS_DELETE_IONO;
990            if (extras.getBoolean("utc")) flags |= GPS_DELETE_UTC;
991            if (extras.getBoolean("health")) flags |= GPS_DELETE_HEALTH;
992            if (extras.getBoolean("svdir")) flags |= GPS_DELETE_SVDIR;
993            if (extras.getBoolean("svsteer")) flags |= GPS_DELETE_SVSTEER;
994            if (extras.getBoolean("sadata")) flags |= GPS_DELETE_SADATA;
995            if (extras.getBoolean("rti")) flags |= GPS_DELETE_RTI;
996            if (extras.getBoolean("celldb-info")) flags |= GPS_DELETE_CELLDB_INFO;
997            if (extras.getBoolean("all")) flags |= GPS_DELETE_ALL;
998        }
999
1000        if (flags != 0) {
1001            native_delete_aiding_data(flags);
1002            return true;
1003        }
1004
1005        return false;
1006    }
1007
1008    private void startNavigating(boolean singleShot) {
1009        if (!mStarted) {
1010            if (DEBUG) Log.d(TAG, "startNavigating, singleShot is " + singleShot);
1011            mTimeToFirstFix = 0;
1012            mLastFixTime = 0;
1013            mStarted = true;
1014            mSingleShot = singleShot;
1015            mPositionMode = GPS_POSITION_MODE_STANDALONE;
1016
1017             if (Settings.Global.getInt(mContext.getContentResolver(),
1018                    Settings.Global.ASSISTED_GPS_ENABLED, 1) != 0) {
1019                if (singleShot && hasCapability(GPS_CAPABILITY_MSA)) {
1020                    mPositionMode = GPS_POSITION_MODE_MS_ASSISTED;
1021                } else if (hasCapability(GPS_CAPABILITY_MSB)) {
1022                    mPositionMode = GPS_POSITION_MODE_MS_BASED;
1023                }
1024            }
1025
1026            if (DEBUG) {
1027                String mode;
1028
1029                switch(mPositionMode) {
1030                    case GPS_POSITION_MODE_STANDALONE:
1031                        mode = "standalone";
1032                        break;
1033                    case GPS_POSITION_MODE_MS_ASSISTED:
1034                        mode = "MS_ASSISTED";
1035                        break;
1036                    case GPS_POSITION_MODE_MS_BASED:
1037                        mode = "MS_BASED";
1038                        break;
1039                    default:
1040                        mode = "unknown";
1041                        break;
1042                }
1043                Log.d(TAG, "setting position_mode to " + mode);
1044            }
1045
1046            int interval = (hasCapability(GPS_CAPABILITY_SCHEDULING) ? mFixInterval : 1000);
1047            if (!native_set_position_mode(mPositionMode, GPS_POSITION_RECURRENCE_PERIODIC,
1048                    interval, 0, 0)) {
1049                mStarted = false;
1050                Log.e(TAG, "set_position_mode failed in startNavigating()");
1051                return;
1052            }
1053            if (!native_start()) {
1054                mStarted = false;
1055                Log.e(TAG, "native_start failed in startNavigating()");
1056                return;
1057            }
1058
1059            // reset SV count to zero
1060            updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE, 0);
1061            mFixRequestTime = System.currentTimeMillis();
1062            if (!hasCapability(GPS_CAPABILITY_SCHEDULING)) {
1063                // set timer to give up if we do not receive a fix within NO_FIX_TIMEOUT
1064                // and our fix interval is not short
1065                if (mFixInterval >= NO_FIX_TIMEOUT) {
1066                    mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
1067                            SystemClock.elapsedRealtime() + NO_FIX_TIMEOUT, mTimeoutIntent);
1068                }
1069            }
1070        }
1071    }
1072
1073    private void stopNavigating() {
1074        if (DEBUG) Log.d(TAG, "stopNavigating");
1075        if (mStarted) {
1076            mStarted = false;
1077            mSingleShot = false;
1078            native_stop();
1079            mTimeToFirstFix = 0;
1080            mLastFixTime = 0;
1081            mLocationFlags = LOCATION_INVALID;
1082
1083            // reset SV count to zero
1084            updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE, 0);
1085        }
1086    }
1087
1088    private void hibernate() {
1089        // stop GPS until our next fix interval arrives
1090        stopNavigating();
1091        mAlarmManager.cancel(mTimeoutIntent);
1092        mAlarmManager.cancel(mWakeupIntent);
1093        long now = SystemClock.elapsedRealtime();
1094        mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, now + mFixInterval, mWakeupIntent);
1095    }
1096
1097    private boolean hasCapability(int capability) {
1098        return ((mEngineCapabilities & capability) != 0);
1099    }
1100
1101
1102    /**
1103     * called from native code to update our position.
1104     */
1105    private void reportLocation(int flags, double latitude, double longitude, double altitude,
1106            float speed, float bearing, float accuracy, long timestamp) {
1107        if (VERBOSE) Log.v(TAG, "reportLocation lat: " + latitude + " long: " + longitude +
1108                " timestamp: " + timestamp);
1109
1110        synchronized (mLocation) {
1111            mLocationFlags = flags;
1112            if ((flags & LOCATION_HAS_LAT_LONG) == LOCATION_HAS_LAT_LONG) {
1113                mLocation.setLatitude(latitude);
1114                mLocation.setLongitude(longitude);
1115                mLocation.setTime(timestamp);
1116                // It would be nice to push the elapsed real-time timestamp
1117                // further down the stack, but this is still useful
1118                mLocation.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());
1119            }
1120            if ((flags & LOCATION_HAS_ALTITUDE) == LOCATION_HAS_ALTITUDE) {
1121                mLocation.setAltitude(altitude);
1122            } else {
1123                mLocation.removeAltitude();
1124            }
1125            if ((flags & LOCATION_HAS_SPEED) == LOCATION_HAS_SPEED) {
1126                mLocation.setSpeed(speed);
1127            } else {
1128                mLocation.removeSpeed();
1129            }
1130            if ((flags & LOCATION_HAS_BEARING) == LOCATION_HAS_BEARING) {
1131                mLocation.setBearing(bearing);
1132            } else {
1133                mLocation.removeBearing();
1134            }
1135            if ((flags & LOCATION_HAS_ACCURACY) == LOCATION_HAS_ACCURACY) {
1136                mLocation.setAccuracy(accuracy);
1137            } else {
1138                mLocation.removeAccuracy();
1139            }
1140            mLocation.setExtras(mLocationExtras);
1141
1142            try {
1143                mILocationManager.reportLocation(mLocation, false);
1144            } catch (RemoteException e) {
1145                Log.e(TAG, "RemoteException calling reportLocation");
1146            }
1147        }
1148
1149        mLastFixTime = System.currentTimeMillis();
1150        // report time to first fix
1151        if (mTimeToFirstFix == 0 && (flags & LOCATION_HAS_LAT_LONG) == LOCATION_HAS_LAT_LONG) {
1152            mTimeToFirstFix = (int)(mLastFixTime - mFixRequestTime);
1153            if (DEBUG) Log.d(TAG, "TTFF: " + mTimeToFirstFix);
1154
1155            // notify status listeners
1156            mListenerHelper.onFirstFix(mTimeToFirstFix);
1157        }
1158
1159        if (mSingleShot) {
1160            stopNavigating();
1161        }
1162
1163        if (mStarted && mStatus != LocationProvider.AVAILABLE) {
1164            // we want to time out if we do not receive a fix
1165            // within the time out and we are requesting infrequent fixes
1166            if (!hasCapability(GPS_CAPABILITY_SCHEDULING) && mFixInterval < NO_FIX_TIMEOUT) {
1167                mAlarmManager.cancel(mTimeoutIntent);
1168            }
1169
1170            // send an intent to notify that the GPS is receiving fixes.
1171            Intent intent = new Intent(LocationManager.GPS_FIX_CHANGE_ACTION);
1172            intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, true);
1173            mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
1174            updateStatus(LocationProvider.AVAILABLE, mSvCount);
1175        }
1176
1177       if (!hasCapability(GPS_CAPABILITY_SCHEDULING) && mStarted &&
1178               mFixInterval > GPS_POLLING_THRESHOLD_INTERVAL) {
1179            if (DEBUG) Log.d(TAG, "got fix, hibernating");
1180            hibernate();
1181        }
1182   }
1183
1184    /**
1185     * called from native code to update our status
1186     */
1187    private void reportStatus(int status) {
1188        if (DEBUG) Log.v(TAG, "reportStatus status: " + status);
1189
1190        boolean wasNavigating = mNavigating;
1191        switch (status) {
1192            case GPS_STATUS_SESSION_BEGIN:
1193                mNavigating = true;
1194                mEngineOn = true;
1195                break;
1196            case GPS_STATUS_SESSION_END:
1197                mNavigating = false;
1198                break;
1199            case GPS_STATUS_ENGINE_ON:
1200                mEngineOn = true;
1201                break;
1202            case GPS_STATUS_ENGINE_OFF:
1203                mEngineOn = false;
1204                mNavigating = false;
1205                break;
1206        }
1207
1208        if (wasNavigating != mNavigating) {
1209            mListenerHelper.onStatusChanged(mNavigating);
1210
1211            // send an intent to notify that the GPS has been enabled or disabled
1212            Intent intent = new Intent(LocationManager.GPS_ENABLED_CHANGE_ACTION);
1213            intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, mNavigating);
1214            mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
1215        }
1216    }
1217
1218    /**
1219     * called from native code to update SV info
1220     */
1221    private void reportSvStatus() {
1222        int svCount = native_read_sv_status(mSvs, mSnrs, mSvElevations, mSvAzimuths, mSvMasks);
1223        mListenerHelper.onSvStatusChanged(
1224                svCount,
1225                mSvs,
1226                mSnrs,
1227                mSvElevations,
1228                mSvAzimuths,
1229                mSvMasks[EPHEMERIS_MASK],
1230                mSvMasks[ALMANAC_MASK],
1231                mSvMasks[USED_FOR_FIX_MASK]);
1232
1233        if (VERBOSE) {
1234            Log.v(TAG, "SV count: " + svCount +
1235                    " ephemerisMask: " + Integer.toHexString(mSvMasks[EPHEMERIS_MASK]) +
1236                    " almanacMask: " + Integer.toHexString(mSvMasks[ALMANAC_MASK]));
1237            for (int i = 0; i < svCount; i++) {
1238                Log.v(TAG, "sv: " + mSvs[i] +
1239                        " snr: " + mSnrs[i]/10 +
1240                        " elev: " + mSvElevations[i] +
1241                        " azimuth: " + mSvAzimuths[i] +
1242                        ((mSvMasks[EPHEMERIS_MASK] & (1 << (mSvs[i] - 1))) == 0 ? "  " : " E") +
1243                        ((mSvMasks[ALMANAC_MASK] & (1 << (mSvs[i] - 1))) == 0 ? "  " : " A") +
1244                        ((mSvMasks[USED_FOR_FIX_MASK] & (1 << (mSvs[i] - 1))) == 0 ? "" : "U"));
1245            }
1246        }
1247
1248        // return number of sets used in fix instead of total
1249        updateStatus(mStatus, Integer.bitCount(mSvMasks[USED_FOR_FIX_MASK]));
1250
1251        if (mNavigating && mStatus == LocationProvider.AVAILABLE && mLastFixTime > 0 &&
1252            System.currentTimeMillis() - mLastFixTime > RECENT_FIX_TIMEOUT) {
1253            // send an intent to notify that the GPS is no longer receiving fixes.
1254            Intent intent = new Intent(LocationManager.GPS_FIX_CHANGE_ACTION);
1255            intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, false);
1256            mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
1257            updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE, mSvCount);
1258        }
1259    }
1260
1261    /**
1262     * called from native code to update AGPS status
1263     */
1264    private void reportAGpsStatus(int type, int status, byte[] ipaddr) {
1265        switch (status) {
1266            case GPS_REQUEST_AGPS_DATA_CONN:
1267                if (DEBUG) Log.d(TAG, "GPS_REQUEST_AGPS_DATA_CONN");
1268                // Set mAGpsDataConnectionState before calling startUsingNetworkFeature
1269                //  to avoid a race condition with handleUpdateNetworkState()
1270                mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPENING;
1271                int result = mConnMgr.startUsingNetworkFeature(
1272                        ConnectivityManager.TYPE_MOBILE, Phone.FEATURE_ENABLE_SUPL);
1273                if (ipaddr != null) {
1274                    try {
1275                        mAGpsDataConnectionIpAddr = InetAddress.getByAddress(ipaddr);
1276                    } catch (UnknownHostException e) {
1277                        Log.e(TAG, "Bad IP Address: " + ipaddr, e);
1278                        mAGpsDataConnectionIpAddr = null;
1279                    }
1280                }
1281
1282                if (result == PhoneConstants.APN_ALREADY_ACTIVE) {
1283                    if (DEBUG) Log.d(TAG, "PhoneConstants.APN_ALREADY_ACTIVE");
1284                    if (mAGpsApn != null) {
1285                        setRouting();
1286                        native_agps_data_conn_open(mAGpsApn, mApnIpType);
1287                        mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPEN;
1288                    } else {
1289                        Log.e(TAG, "mAGpsApn not set when receiving PhoneConstants.APN_ALREADY_ACTIVE");
1290                        mAGpsDataConnectionState = AGPS_DATA_CONNECTION_CLOSED;
1291                        native_agps_data_conn_failed();
1292                    }
1293                } else if (result == PhoneConstants.APN_REQUEST_STARTED) {
1294                    if (DEBUG) Log.d(TAG, "PhoneConstants.APN_REQUEST_STARTED");
1295                    // Nothing to do here
1296                } else {
1297                    if (DEBUG) Log.d(TAG, "startUsingNetworkFeature failed, value is " +
1298                                     result);
1299                    mAGpsDataConnectionState = AGPS_DATA_CONNECTION_CLOSED;
1300                    native_agps_data_conn_failed();
1301                }
1302                break;
1303            case GPS_RELEASE_AGPS_DATA_CONN:
1304                if (DEBUG) Log.d(TAG, "GPS_RELEASE_AGPS_DATA_CONN");
1305                if (mAGpsDataConnectionState != AGPS_DATA_CONNECTION_CLOSED) {
1306                    mConnMgr.stopUsingNetworkFeature(
1307                            ConnectivityManager.TYPE_MOBILE, Phone.FEATURE_ENABLE_SUPL);
1308                    native_agps_data_conn_closed();
1309                    mAGpsDataConnectionState = AGPS_DATA_CONNECTION_CLOSED;
1310                    mAGpsDataConnectionIpAddr = null;
1311                }
1312                break;
1313            case GPS_AGPS_DATA_CONNECTED:
1314                if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONNECTED");
1315                break;
1316            case GPS_AGPS_DATA_CONN_DONE:
1317                if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONN_DONE");
1318                break;
1319            case GPS_AGPS_DATA_CONN_FAILED:
1320                if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONN_FAILED");
1321                break;
1322        }
1323    }
1324
1325    /**
1326     * called from native code to report NMEA data received
1327     */
1328    private void reportNmea(long timestamp) {
1329        int length = native_read_nmea(mNmeaBuffer, mNmeaBuffer.length);
1330        String nmea = new String(mNmeaBuffer, 0 /* offset */, length);
1331        mListenerHelper.onNmeaReceived(timestamp, nmea);
1332    }
1333
1334    /**
1335     * called from native code - Gps Data callback
1336     */
1337    private void reportMeasurementData(GpsMeasurementsEvent event) {
1338        mGpsMeasurementsProvider.onMeasurementsAvailable(event);
1339    }
1340
1341    /**
1342     * called from native code to inform us what the GPS engine capabilities are
1343     */
1344    private void setEngineCapabilities(int capabilities) {
1345        mEngineCapabilities = capabilities;
1346
1347        if (!hasCapability(GPS_CAPABILITY_ON_DEMAND_TIME) && !mPeriodicTimeInjection) {
1348            mPeriodicTimeInjection = true;
1349            requestUtcTime();
1350        }
1351    }
1352
1353    /**
1354     * called from native code to request XTRA data
1355     */
1356    private void xtraDownloadRequest() {
1357        if (DEBUG) Log.d(TAG, "xtraDownloadRequest");
1358        sendMessage(DOWNLOAD_XTRA_DATA, 0, null);
1359    }
1360
1361    /**
1362     * Helper method to construct a location object.
1363     */
1364    private Location buildLocation(
1365            int flags,
1366            double latitude,
1367            double longitude,
1368            double altitude,
1369            float speed,
1370            float bearing,
1371            float accuracy,
1372            long timestamp) {
1373        Location location = new Location(LocationManager.GPS_PROVIDER);
1374        if((flags & LOCATION_HAS_LAT_LONG) == LOCATION_HAS_LAT_LONG) {
1375            location.setLatitude(latitude);
1376            location.setLongitude(longitude);
1377            location.setTime(timestamp);
1378            location.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());
1379        }
1380        if((flags & LOCATION_HAS_ALTITUDE) == LOCATION_HAS_ALTITUDE) {
1381            location.setAltitude(altitude);
1382        }
1383        if((flags & LOCATION_HAS_SPEED) == LOCATION_HAS_SPEED) {
1384            location.setSpeed(speed);
1385        }
1386        if((flags & LOCATION_HAS_BEARING) == LOCATION_HAS_BEARING) {
1387            location.setBearing(bearing);
1388        }
1389        if((flags & LOCATION_HAS_ACCURACY) == LOCATION_HAS_ACCURACY) {
1390            location.setAccuracy(accuracy);
1391        }
1392        return location;
1393    }
1394
1395    /**
1396     * Converts the GPS HAL status to the internal Geofence Hardware status.
1397     */
1398    private int getGeofenceStatus(int status) {
1399        switch(status) {
1400            case GPS_GEOFENCE_OPERATION_SUCCESS:
1401                return GeofenceHardware.GEOFENCE_SUCCESS;
1402            case GPS_GEOFENCE_ERROR_GENERIC:
1403                return GeofenceHardware.GEOFENCE_FAILURE;
1404            case GPS_GEOFENCE_ERROR_ID_EXISTS:
1405                return GeofenceHardware.GEOFENCE_ERROR_ID_EXISTS;
1406            case GPS_GEOFENCE_ERROR_INVALID_TRANSITION:
1407                return GeofenceHardware.GEOFENCE_ERROR_INVALID_TRANSITION;
1408            case GPS_GEOFENCE_ERROR_TOO_MANY_GEOFENCES:
1409                return GeofenceHardware.GEOFENCE_ERROR_TOO_MANY_GEOFENCES;
1410            case GPS_GEOFENCE_ERROR_ID_UNKNOWN:
1411                return GeofenceHardware.GEOFENCE_ERROR_ID_UNKNOWN;
1412            default:
1413                return -1;
1414        }
1415    }
1416
1417    /**
1418     * Called from native to report GPS Geofence transition
1419     * All geofence callbacks are called on the same thread
1420     */
1421    private void reportGeofenceTransition(int geofenceId, int flags, double latitude,
1422            double longitude, double altitude, float speed, float bearing, float accuracy,
1423            long timestamp, int transition, long transitionTimestamp) {
1424        if (mGeofenceHardwareImpl == null) {
1425            mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
1426        }
1427        Location location = buildLocation(
1428                flags,
1429                latitude,
1430                longitude,
1431                altitude,
1432                speed,
1433                bearing,
1434                accuracy,
1435                timestamp);
1436        mGeofenceHardwareImpl.reportGeofenceTransition(
1437                geofenceId,
1438                location,
1439                transition,
1440                transitionTimestamp,
1441                GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE,
1442                FusedBatchOptions.SourceTechnologies.GNSS);
1443    }
1444
1445    /**
1446     * called from native code to report GPS status change.
1447     */
1448    private void reportGeofenceStatus(int status, int flags, double latitude,
1449            double longitude, double altitude, float speed, float bearing, float accuracy,
1450            long timestamp) {
1451        if (mGeofenceHardwareImpl == null) {
1452            mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
1453        }
1454        Location location = buildLocation(
1455                flags,
1456                latitude,
1457                longitude,
1458                altitude,
1459                speed,
1460                bearing,
1461                accuracy,
1462                timestamp);
1463        int monitorStatus = GeofenceHardware.MONITOR_CURRENTLY_UNAVAILABLE;
1464        if(status == GPS_GEOFENCE_AVAILABLE) {
1465            monitorStatus = GeofenceHardware.MONITOR_CURRENTLY_AVAILABLE;
1466        }
1467        mGeofenceHardwareImpl.reportGeofenceMonitorStatus(
1468                GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE,
1469                monitorStatus,
1470                location,
1471                FusedBatchOptions.SourceTechnologies.GNSS);
1472    }
1473
1474    /**
1475     * called from native code - Geofence Add callback
1476     */
1477    private void reportGeofenceAddStatus(int geofenceId, int status) {
1478        if (mGeofenceHardwareImpl == null) {
1479            mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
1480        }
1481        mGeofenceHardwareImpl.reportGeofenceAddStatus(geofenceId, getGeofenceStatus(status));
1482    }
1483
1484    /**
1485     * called from native code - Geofence Remove callback
1486     */
1487    private void reportGeofenceRemoveStatus(int geofenceId, int status) {
1488        if (mGeofenceHardwareImpl == null) {
1489            mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
1490        }
1491        mGeofenceHardwareImpl.reportGeofenceRemoveStatus(geofenceId, getGeofenceStatus(status));
1492    }
1493
1494    /**
1495     * called from native code - Geofence Pause callback
1496     */
1497    private void reportGeofencePauseStatus(int geofenceId, int status) {
1498        if (mGeofenceHardwareImpl == null) {
1499            mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
1500        }
1501        mGeofenceHardwareImpl.reportGeofencePauseStatus(geofenceId, getGeofenceStatus(status));
1502    }
1503
1504    /**
1505     * called from native code - Geofence Resume callback
1506     */
1507    private void reportGeofenceResumeStatus(int geofenceId, int status) {
1508        if (mGeofenceHardwareImpl == null) {
1509            mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
1510        }
1511        mGeofenceHardwareImpl.reportGeofenceResumeStatus(geofenceId, getGeofenceStatus(status));
1512    }
1513
1514    //=============================================================
1515    // NI Client support
1516    //=============================================================
1517    private final INetInitiatedListener mNetInitiatedListener = new INetInitiatedListener.Stub() {
1518        // Sends a response for an NI reqeust to HAL.
1519        @Override
1520        public boolean sendNiResponse(int notificationId, int userResponse)
1521        {
1522            // TODO Add Permission check
1523
1524            if (DEBUG) Log.d(TAG, "sendNiResponse, notifId: " + notificationId +
1525                    ", response: " + userResponse);
1526            native_send_ni_response(notificationId, userResponse);
1527            return true;
1528        }
1529    };
1530
1531    public INetInitiatedListener getNetInitiatedListener() {
1532        return mNetInitiatedListener;
1533    }
1534
1535    // Called by JNI function to report an NI request.
1536    public void reportNiNotification(
1537            int notificationId,
1538            int niType,
1539            int notifyFlags,
1540            int timeout,
1541            int defaultResponse,
1542            String requestorId,
1543            String text,
1544            int requestorIdEncoding,
1545            int textEncoding,
1546            String extras  // Encoded extra data
1547        )
1548    {
1549        Log.i(TAG, "reportNiNotification: entered");
1550        Log.i(TAG, "notificationId: " + notificationId +
1551                ", niType: " + niType +
1552                ", notifyFlags: " + notifyFlags +
1553                ", timeout: " + timeout +
1554                ", defaultResponse: " + defaultResponse);
1555
1556        Log.i(TAG, "requestorId: " + requestorId +
1557                ", text: " + text +
1558                ", requestorIdEncoding: " + requestorIdEncoding +
1559                ", textEncoding: " + textEncoding);
1560
1561        GpsNiNotification notification = new GpsNiNotification();
1562
1563        notification.notificationId = notificationId;
1564        notification.niType = niType;
1565        notification.needNotify = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_NEED_NOTIFY) != 0;
1566        notification.needVerify = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_NEED_VERIFY) != 0;
1567        notification.privacyOverride = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_PRIVACY_OVERRIDE) != 0;
1568        notification.timeout = timeout;
1569        notification.defaultResponse = defaultResponse;
1570        notification.requestorId = requestorId;
1571        notification.text = text;
1572        notification.requestorIdEncoding = requestorIdEncoding;
1573        notification.textEncoding = textEncoding;
1574
1575        // Process extras, assuming the format is
1576        // one of more lines of "key = value"
1577        Bundle bundle = new Bundle();
1578
1579        if (extras == null) extras = "";
1580        Properties extraProp = new Properties();
1581
1582        try {
1583            extraProp.load(new StringReader(extras));
1584        }
1585        catch (IOException e)
1586        {
1587            Log.e(TAG, "reportNiNotification cannot parse extras data: " + extras);
1588        }
1589
1590        for (Entry<Object, Object> ent : extraProp.entrySet())
1591        {
1592            bundle.putString((String) ent.getKey(), (String) ent.getValue());
1593        }
1594
1595        notification.extras = bundle;
1596
1597        mNIHandler.handleNiNotification(notification);
1598    }
1599
1600    /**
1601     * Called from native code to request set id info.
1602     * We should be careful about receiving null string from the TelephonyManager,
1603     * because sending null String to JNI function would cause a crash.
1604     */
1605
1606    private void requestSetID(int flags) {
1607        TelephonyManager phone = (TelephonyManager)
1608                mContext.getSystemService(Context.TELEPHONY_SERVICE);
1609        int    type = AGPS_SETID_TYPE_NONE;
1610        String data = "";
1611
1612        if ((flags & AGPS_RIL_REQUEST_SETID_IMSI) == AGPS_RIL_REQUEST_SETID_IMSI) {
1613            String data_temp = phone.getSubscriberId();
1614            if (data_temp == null) {
1615                // This means the framework does not have the SIM card ready.
1616            } else {
1617                // This means the framework has the SIM card.
1618                data = data_temp;
1619                type = AGPS_SETID_TYPE_IMSI;
1620            }
1621        }
1622        else if ((flags & AGPS_RIL_REQUEST_SETID_MSISDN) == AGPS_RIL_REQUEST_SETID_MSISDN) {
1623            String data_temp = phone.getLine1Number();
1624            if (data_temp == null) {
1625                // This means the framework does not have the SIM card ready.
1626            } else {
1627                // This means the framework has the SIM card.
1628                data = data_temp;
1629                type = AGPS_SETID_TYPE_MSISDN;
1630            }
1631        }
1632        native_agps_set_id(type, data);
1633    }
1634
1635    /**
1636     * Called from native code to request utc time info
1637     */
1638
1639    private void requestUtcTime() {
1640        sendMessage(INJECT_NTP_TIME, 0, null);
1641    }
1642
1643    /**
1644     * Called from native code to request reference location info
1645     */
1646
1647    private void requestRefLocation(int flags) {
1648        TelephonyManager phone = (TelephonyManager)
1649                mContext.getSystemService(Context.TELEPHONY_SERVICE);
1650        final int phoneType = phone.getPhoneType();
1651        if (phoneType == TelephonyManager.PHONE_TYPE_GSM) {
1652            GsmCellLocation gsm_cell = (GsmCellLocation) phone.getCellLocation();
1653            if ((gsm_cell != null) && (phone.getNetworkOperator() != null)
1654                    && (phone.getNetworkOperator().length() > 3)) {
1655                int type;
1656                int mcc = Integer.parseInt(phone.getNetworkOperator().substring(0,3));
1657                int mnc = Integer.parseInt(phone.getNetworkOperator().substring(3));
1658                int networkType = phone.getNetworkType();
1659                if (networkType == TelephonyManager.NETWORK_TYPE_UMTS
1660                    || networkType == TelephonyManager.NETWORK_TYPE_HSDPA
1661                    || networkType == TelephonyManager.NETWORK_TYPE_HSUPA
1662                    || networkType == TelephonyManager.NETWORK_TYPE_HSPA
1663                    || networkType == TelephonyManager.NETWORK_TYPE_HSPAP) {
1664                    type = AGPS_REF_LOCATION_TYPE_UMTS_CELLID;
1665                } else {
1666                    type = AGPS_REF_LOCATION_TYPE_GSM_CELLID;
1667                }
1668                native_agps_set_ref_location_cellid(type, mcc, mnc,
1669                        gsm_cell.getLac(), gsm_cell.getCid());
1670            } else {
1671                Log.e(TAG,"Error getting cell location info.");
1672            }
1673        } else if (phoneType == TelephonyManager.PHONE_TYPE_CDMA) {
1674            Log.e(TAG, "CDMA not supported.");
1675        }
1676    }
1677
1678    private void sendMessage(int message, int arg, Object obj) {
1679        // hold a wake lock until this message is delivered
1680        // note that this assumes the message will not be removed from the queue before
1681        // it is handled (otherwise the wake lock would be leaked).
1682        mWakeLock.acquire();
1683        mHandler.obtainMessage(message, arg, 1, obj).sendToTarget();
1684    }
1685
1686    private final class ProviderHandler extends Handler {
1687        public ProviderHandler(Looper looper) {
1688            super(looper, null, true /*async*/);
1689        }
1690
1691        @Override
1692        public void handleMessage(Message msg) {
1693            int message = msg.what;
1694            switch (message) {
1695                case ENABLE:
1696                    if (msg.arg1 == 1) {
1697                        handleEnable();
1698                    } else {
1699                        handleDisable();
1700                    }
1701                    break;
1702                case SET_REQUEST:
1703                    GpsRequest gpsRequest = (GpsRequest) msg.obj;
1704                    handleSetRequest(gpsRequest.request, gpsRequest.source);
1705                    break;
1706                case UPDATE_NETWORK_STATE:
1707                    handleUpdateNetworkState(msg.arg1, (NetworkInfo)msg.obj);
1708                    break;
1709                case INJECT_NTP_TIME:
1710                    handleInjectNtpTime();
1711                    break;
1712                case DOWNLOAD_XTRA_DATA:
1713                    if (mSupportsXtra) {
1714                        handleDownloadXtraData();
1715                    }
1716                    break;
1717                case INJECT_NTP_TIME_FINISHED:
1718                    mInjectNtpTimePending = STATE_IDLE;
1719                    break;
1720                case DOWNLOAD_XTRA_DATA_FINISHED:
1721                    mDownloadXtraDataPending = STATE_IDLE;
1722                    break;
1723                case UPDATE_LOCATION:
1724                    handleUpdateLocation((Location)msg.obj);
1725                    break;
1726            }
1727            if (msg.arg2 == 1) {
1728                // wakelock was taken for this message, release it
1729                mWakeLock.release();
1730            }
1731        }
1732    };
1733
1734    private final class NetworkLocationListener implements LocationListener {
1735        @Override
1736        public void onLocationChanged(Location location) {
1737            // this callback happens on mHandler looper
1738            if (LocationManager.NETWORK_PROVIDER.equals(location.getProvider())) {
1739                handleUpdateLocation(location);
1740            }
1741        }
1742        @Override
1743        public void onStatusChanged(String provider, int status, Bundle extras) { }
1744        @Override
1745        public void onProviderEnabled(String provider) { }
1746        @Override
1747        public void onProviderDisabled(String provider) { }
1748    }
1749
1750    private String getSelectedApn() {
1751        Uri uri = Uri.parse("content://telephony/carriers/preferapn");
1752        Cursor cursor = null;
1753        try {
1754            cursor = mContext.getContentResolver().query(
1755                    uri,
1756                    new String[] { "apn" },
1757                    null /* selection */,
1758                    null /* selectionArgs */,
1759                    Carriers.DEFAULT_SORT_ORDER);
1760            if (cursor != null && cursor.moveToFirst()) {
1761                return cursor.getString(0);
1762            } else {
1763                Log.e(TAG, "No APN found to select.");
1764            }
1765        } catch (Exception e) {
1766            Log.e(TAG, "Error encountered on selecting the APN.", e);
1767        } finally {
1768            if (cursor != null) {
1769                cursor.close();
1770            }
1771        }
1772
1773        return null;
1774    }
1775
1776    private int getApnIpType(String apn) {
1777        if (apn == null) {
1778            return APN_INVALID;
1779        }
1780
1781        // look for cached data to use
1782        if (apn.equals(mAGpsApn) && mApnIpType != APN_INVALID) {
1783            return mApnIpType;
1784        }
1785
1786        String selection = String.format("current = 1 and apn = '%s' and carrier_enabled = 1", apn);
1787        Cursor cursor = null;
1788        try {
1789            cursor = mContext.getContentResolver().query(
1790                    Carriers.CONTENT_URI,
1791                    new String[] { Carriers.PROTOCOL },
1792                    selection,
1793                    null,
1794                    Carriers.DEFAULT_SORT_ORDER);
1795
1796            if (null != cursor && cursor.moveToFirst()) {
1797                return translateToApnIpType(cursor.getString(0), apn);
1798            } else {
1799                Log.e(TAG, "No entry found in query for APN: " + apn);
1800            }
1801        } catch (Exception e) {
1802            Log.e(TAG, "Error encountered on APN query for: " + apn, e);
1803        } finally {
1804            if (cursor != null) {
1805                cursor.close();
1806            }
1807        }
1808
1809        return APN_INVALID;
1810    }
1811
1812    private int translateToApnIpType(String ipProtocol, String apn) {
1813        if ("IP".equals(ipProtocol)) {
1814            return APN_IPV4;
1815        }
1816        if ("IPV6".equals(ipProtocol)) {
1817            return APN_IPV6;
1818        }
1819        if ("IPV4V6".equals(ipProtocol)) {
1820            return APN_IPV4V6;
1821        }
1822
1823        // we hit the default case so the ipProtocol is not recognized
1824        String message = String.format("Unknown IP Protocol: %s, for APN: %s", ipProtocol, apn);
1825        Log.e(TAG, message);
1826        return APN_INVALID;
1827    }
1828
1829    private void setRouting() {
1830        if (mAGpsDataConnectionIpAddr == null) {
1831            return;
1832        }
1833
1834        boolean result = mConnMgr.requestRouteToHostAddress(
1835                ConnectivityManager.TYPE_MOBILE_SUPL,
1836                mAGpsDataConnectionIpAddr);
1837
1838        if (!result) {
1839            Log.e(TAG, "Error requesting route to host: " + mAGpsDataConnectionIpAddr);
1840        } else if (DEBUG) {
1841            Log.d(TAG, "Successfully requested route to host: " + mAGpsDataConnectionIpAddr);
1842        }
1843    }
1844
1845    @Override
1846    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1847        StringBuilder s = new StringBuilder();
1848        s.append("  mFixInterval=").append(mFixInterval).append("\n");
1849        s.append("  mEngineCapabilities=0x").append(Integer.toHexString(mEngineCapabilities)).append(" (");
1850        if (hasCapability(GPS_CAPABILITY_SCHEDULING)) s.append("SCHED ");
1851        if (hasCapability(GPS_CAPABILITY_MSB)) s.append("MSB ");
1852        if (hasCapability(GPS_CAPABILITY_MSA)) s.append("MSA ");
1853        if (hasCapability(GPS_CAPABILITY_SINGLE_SHOT)) s.append("SINGLE_SHOT ");
1854        if (hasCapability(GPS_CAPABILITY_ON_DEMAND_TIME)) s.append("ON_DEMAND_TIME ");
1855        s.append(")\n");
1856
1857        s.append(native_get_internal_state());
1858        pw.append(s);
1859    }
1860
1861    // for GPS SV statistics
1862    private static final int MAX_SVS = 32;
1863    private static final int EPHEMERIS_MASK = 0;
1864    private static final int ALMANAC_MASK = 1;
1865    private static final int USED_FOR_FIX_MASK = 2;
1866
1867    // preallocated arrays, to avoid memory allocation in reportStatus()
1868    private int mSvs[] = new int[MAX_SVS];
1869    private float mSnrs[] = new float[MAX_SVS];
1870    private float mSvElevations[] = new float[MAX_SVS];
1871    private float mSvAzimuths[] = new float[MAX_SVS];
1872    private int mSvMasks[] = new int[3];
1873    private int mSvCount;
1874    // preallocated to avoid memory allocation in reportNmea()
1875    private byte[] mNmeaBuffer = new byte[120];
1876
1877    static { class_init_native(); }
1878    private static native void class_init_native();
1879    private static native boolean native_is_supported();
1880
1881    private native boolean native_init();
1882    private native void native_cleanup();
1883    private native boolean native_set_position_mode(int mode, int recurrence, int min_interval,
1884            int preferred_accuracy, int preferred_time);
1885    private native boolean native_start();
1886    private native boolean native_stop();
1887    private native void native_delete_aiding_data(int flags);
1888    // returns number of SVs
1889    // mask[0] is ephemeris mask and mask[1] is almanac mask
1890    private native int native_read_sv_status(int[] svs, float[] snrs,
1891            float[] elevations, float[] azimuths, int[] masks);
1892    private native int native_read_nmea(byte[] buffer, int bufferSize);
1893    private native void native_inject_location(double latitude, double longitude, float accuracy);
1894
1895    // XTRA Support
1896    private native void native_inject_time(long time, long timeReference, int uncertainty);
1897    private native boolean native_supports_xtra();
1898    private native void native_inject_xtra_data(byte[] data, int length);
1899
1900    // DEBUG Support
1901    private native String native_get_internal_state();
1902
1903    // AGPS Support
1904    private native void native_agps_data_conn_open(String apn, int apnIpType);
1905    private native void native_agps_data_conn_closed();
1906    private native void native_agps_data_conn_failed();
1907    private native void native_agps_ni_message(byte [] msg, int length);
1908    private native void native_set_agps_server(int type, String hostname, int port);
1909
1910    // Network-initiated (NI) Support
1911    private native void native_send_ni_response(int notificationId, int userResponse);
1912
1913    // AGPS ril suport
1914    private native void native_agps_set_ref_location_cellid(int type, int mcc, int mnc,
1915            int lac, int cid);
1916    private native void native_agps_set_id(int type, String setid);
1917
1918    private native void native_update_network_state(boolean connected, int type,
1919            boolean roaming, boolean available, String extraInfo, String defaultAPN);
1920
1921    // Hardware Geofence support.
1922    private static native boolean native_is_geofence_supported();
1923    private static native boolean native_add_geofence(int geofenceId, double latitude,
1924            double longitude, double radius, int lastTransition,int monitorTransitions,
1925            int notificationResponsivenes, int unknownTimer);
1926    private static native boolean native_remove_geofence(int geofenceId);
1927    private static native boolean native_resume_geofence(int geofenceId, int transitions);
1928    private static native boolean native_pause_geofence(int geofenceId);
1929
1930    // Gps Hal measurements support.
1931    private static native boolean native_is_measurement_supported();
1932    private static native boolean native_start_measurement_collection();
1933    private static native boolean native_stop_measurement_collection();
1934}
1935