GpsLocationProvider.java revision e3635c9693c4cd9650684f14e19dcabcea0d488a
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");
59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License.
69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and
149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License.
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage com.android.internal.location;
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1929c84340a14e70419449628ab193d11b7a609e9aMike Lockwoodimport android.app.AlarmManager;
2029c84340a14e70419449628ab193d11b7a609e9aMike Lockwoodimport android.app.PendingIntent;
21105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Projectimport android.content.BroadcastReceiver;
229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context;
239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Intent;
24105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Projectimport android.content.IntentFilter;
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.location.Criteria;
269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.location.IGpsStatusListener;
2715e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwoodimport android.location.IGpsStatusProvider;
284e50b78bda9cd58be61581d2886c88ff6348a1c1Mike Lockwoodimport android.location.ILocationManager;
2915e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwoodimport android.location.ILocationProvider;
309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.location.Location;
319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.location.LocationManager;
329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.location.LocationProvider;
3358bda987665af759c379cd494ff4873ac61acf29Mike Lockwoodimport android.net.ConnectivityManager;
349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.net.SntpClient;
359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Bundle;
369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.IBinder;
370528b9b26a9d64ba43acd0e334638303d514b8ebMike Lockwoodimport android.os.PowerManager;
389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.RemoteException;
392f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwoodimport android.os.ServiceManager;
409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.SystemClock;
419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.Config;
429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.Log;
432f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwoodimport android.util.SparseIntArray;
449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
452f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwoodimport com.android.internal.app.IBatteryStats;
46105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Projectimport com.android.internal.telephony.Phone;
47105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Projectimport com.android.internal.telephony.TelephonyIntents;
48105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.File;
509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.FileInputStream;
519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.IOException;
52105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Projectimport java.net.InetAddress;
53105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Projectimport java.net.UnknownHostException;
549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.ArrayList;
559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.Properties;
569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * A GPS implementation of LocationProvider used by LocationManager.
599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@hide}
619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
6215e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwoodpublic class GpsLocationProvider extends ILocationProvider.Stub {
639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String TAG = "GpsLocationProvider";
6529c84340a14e70419449628ab193d11b7a609e9aMike Lockwood
6629c84340a14e70419449628ab193d11b7a609e9aMike Lockwood    private static final boolean DEBUG = true;
6729c84340a14e70419449628ab193d11b7a609e9aMike Lockwood    private static final boolean VERBOSE = false;
689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Broadcast intent action indicating that the GPS has either been
719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * enabled or disabled. An intent extra provides this state as a boolean,
729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * where {@code true} means enabled.
739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #EXTRA_ENABLED
749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * {@hide}
769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static final String GPS_ENABLED_CHANGE_ACTION =
789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "android.location.GPS_ENABLED_CHANGE";
799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Broadcast intent action indicating that the GPS has either started or
829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * stopped receiving GPS fixes. An intent extra provides this state as a
839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * boolean, where {@code true} means that the GPS is actively receiving fixes.
849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #EXTRA_ENABLED
859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * {@hide}
879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static final String GPS_FIX_CHANGE_ACTION =
899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "android.location.GPS_FIX_CHANGE";
909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * The lookup key for a boolean that indicates whether GPS is enabled or
939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * disabled. {@code true} means GPS is enabled. Retrieve it with
949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * {@link android.content.Intent#getBooleanExtra(String,boolean)}.
959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * {@hide}
979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static final String EXTRA_ENABLED = "enabled";
999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
100105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    // these need to match GpsPositionMode enum in gps.h
101105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    private static final int GPS_POSITION_MODE_STANDALONE = 0;
102105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    private static final int GPS_POSITION_MODE_MS_BASED = 1;
103105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    private static final int GPS_POSITION_MODE_MS_ASSISTED = 2;
104105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // these need to match GpsStatusValue defines in gps.h
1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int GPS_STATUS_NONE = 0;
1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int GPS_STATUS_SESSION_BEGIN = 1;
1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int GPS_STATUS_SESSION_END = 2;
1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int GPS_STATUS_ENGINE_ON = 3;
1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int GPS_STATUS_ENGINE_OFF = 4;
1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
112e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood    // these need to match GpsApgsStatusValue defines in gps.h
113e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood    /** AGPS status event values. */
114e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood    private static final int GPS_REQUEST_AGPS_DATA_CONN = 1;
115e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood    private static final int GPS_RELEASE_AGPS_DATA_CONN = 2;
116e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood    private static final int GPS_AGPS_DATA_CONNECTED = 3;
117e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood    private static final int GPS_AGPS_DATA_CONN_DONE = 4;
118e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood    private static final int GPS_AGPS_DATA_CONN_FAILED = 5;
11958bda987665af759c379cd494ff4873ac61acf29Mike Lockwood
1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // these need to match GpsLocationFlags enum in gps.h
1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int LOCATION_INVALID = 0;
1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int LOCATION_HAS_LAT_LONG = 1;
1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int LOCATION_HAS_ALTITUDE = 2;
1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int LOCATION_HAS_SPEED = 4;
1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int LOCATION_HAS_BEARING = 8;
1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int LOCATION_HAS_ACCURACY = 16;
127e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood
128e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood// IMPORTANT - the GPS_DELETE_* symbols here must match constants in gps.h
1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int GPS_DELETE_EPHEMERIS = 0x0001;
1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int GPS_DELETE_ALMANAC = 0x0002;
1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int GPS_DELETE_POSITION = 0x0004;
1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int GPS_DELETE_TIME = 0x0008;
1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int GPS_DELETE_IONO = 0x0010;
1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int GPS_DELETE_UTC = 0x0020;
1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int GPS_DELETE_HEALTH = 0x0040;
1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int GPS_DELETE_SVDIR = 0x0080;
1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int GPS_DELETE_SVSTEER = 0x0100;
1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int GPS_DELETE_SADATA = 0x0200;
1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int GPS_DELETE_RTI = 0x0400;
1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int GPS_DELETE_CELLDB_INFO = 0x8000;
1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int GPS_DELETE_ALL = 0xFFFF;
1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
143e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood    // these need to match AGpsType enum in gps.h
144e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood    private static final int AGPS_TYPE_SUPL = 1;
145e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood    private static final int AGPS_TYPE_C2K = 2;
146e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood
147e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood    // for mAGpsDataConnectionState
148e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood    private static final int AGPS_DATA_CONNECTION_CLOSED = 0;
149e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood    private static final int AGPS_DATA_CONNECTION_OPENING = 1;
150e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood    private static final int AGPS_DATA_CONNECTION_OPEN = 2;
15158bda987665af759c379cd494ff4873ac61acf29Mike Lockwood
1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String PROPERTIES_FILE = "/etc/gps.conf";
1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int mLocationFlags = LOCATION_INVALID;
1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // current status
15715e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood    private int mStatus = LocationProvider.TEMPORARILY_UNAVAILABLE;
1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // time for last status update
1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private long mStatusUpdateTime = SystemClock.elapsedRealtime();
1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // turn off GPS fix icon if we haven't received a fix in 10 seconds
1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final long RECENT_FIX_TIMEOUT = 10 * 1000;
16429c84340a14e70419449628ab193d11b7a609e9aMike Lockwood
16529c84340a14e70419449628ab193d11b7a609e9aMike Lockwood    // number of fixes to receive before disabling GPS
16629c84340a14e70419449628ab193d11b7a609e9aMike Lockwood    private static final int MIN_FIX_COUNT = 10;
1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // true if we are enabled
1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean mEnabled;
1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // true if we have network connectivity
1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean mNetworkAvailable;
1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // true if GPS is navigating
1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean mNavigating;
1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // requested frequency of fixes, in seconds
1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int mFixInterval = 1;
1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
18029c84340a14e70419449628ab193d11b7a609e9aMike Lockwood    // number of fixes we have received since we started navigating
18129c84340a14e70419449628ab193d11b7a609e9aMike Lockwood    private int mFixCount;
18229c84340a14e70419449628ab193d11b7a609e9aMike Lockwood
183105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    private int mPositionMode = GPS_POSITION_MODE_STANDALONE;
184105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // true if we started navigation
1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean mStarted;
1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // for calculating time to first fix
1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private long mFixRequestTime = 0;
1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // time to first fix for most recent session
1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int mTTFF = 0;
1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // time we received our last fix
1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private long mLastFixTime;
1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // properties loaded from PROPERTIES_FILE
1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private Properties mProperties;
1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private String mNtpServer;
1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19915e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood    private final Context mContext;
20015e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood    private final ILocationManager mLocationManager;
2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private Location mLocation = new Location(LocationManager.GPS_PROVIDER);
2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private Bundle mLocationExtras = new Bundle();
2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private ArrayList<Listener> mListeners = new ArrayList<Listener>();
2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private GpsEventThread mEventThread;
2059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private GpsNetworkThread mNetworkThread;
2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private Object mNetworkThreadLock = new Object();
207105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
208105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    private String mSuplHost;
209105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    private int mSuplPort;
210e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood    private String mC2KHost;
211e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood    private int mC2KPort;
212105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    private boolean mSetSuplServer;
213e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood    private boolean mSetC2KServer;
214e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood    private String mAGpsApn;
215e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood    private int mAGpsDataConnectionState;
2162f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood    private final ConnectivityManager mConnMgr;
2172f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood
2180528b9b26a9d64ba43acd0e334638303d514b8ebMike Lockwood    // Wakelocks
2190528b9b26a9d64ba43acd0e334638303d514b8ebMike Lockwood    private final static String WAKELOCK_KEY = "GpsLocationProvider";
2200528b9b26a9d64ba43acd0e334638303d514b8ebMike Lockwood    private final PowerManager.WakeLock mWakeLock;
2210528b9b26a9d64ba43acd0e334638303d514b8ebMike Lockwood
22229c84340a14e70419449628ab193d11b7a609e9aMike Lockwood    // Alarms
22329c84340a14e70419449628ab193d11b7a609e9aMike Lockwood    private final static String ALARM_WAKEUP = "com.android.internal.location.ALARM_WAKEUP";
22429c84340a14e70419449628ab193d11b7a609e9aMike Lockwood    private final AlarmManager mAlarmManager;
22529c84340a14e70419449628ab193d11b7a609e9aMike Lockwood    private final PendingIntent mWakeupIntent;
22629c84340a14e70419449628ab193d11b7a609e9aMike Lockwood
2272f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood    private final IBatteryStats mBatteryStats;
2282f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood    private final SparseIntArray mClientUids = new SparseIntArray();
229105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
2309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // how often to request NTP time, in milliseconds
2319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // current setting 4 hours
2329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final long NTP_INTERVAL = 4*60*60*1000;
2339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // how long to wait if we have a network error in NTP or XTRA downloading
2349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // current setting - 5 minutes
2359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final long RETRY_INTERVAL = 5*60*1000;
2369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
23715e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood    private final IGpsStatusProvider mGpsStatusProvider = new IGpsStatusProvider.Stub() {
23815e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood        public void addGpsStatusListener(IGpsStatusListener listener) throws RemoteException {
23915e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood            if (listener == null) {
24015e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood                throw new NullPointerException("listener is null in addGpsStatusListener");
24115e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood            }
24215e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood
24315e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood            synchronized(mListeners) {
24415e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood                IBinder binder = listener.asBinder();
24515e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood                int size = mListeners.size();
24615e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood                for (int i = 0; i < size; i++) {
24715e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood                    Listener test = mListeners.get(i);
24815e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood                    if (binder.equals(test.mListener.asBinder())) {
24915e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood                        // listener already added
25015e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood                        return;
25115e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood                    }
25215e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood                }
25315e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood
25415e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood                Listener l = new Listener(listener);
25515e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood                binder.linkToDeath(l, 0);
25615e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood                mListeners.add(l);
25715e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood            }
25815e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood        }
25915e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood
26015e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood        public void removeGpsStatusListener(IGpsStatusListener listener) {
26115e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood            if (listener == null) {
26215e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood                throw new NullPointerException("listener is null in addGpsStatusListener");
26315e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood            }
26415e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood
26515e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood            synchronized(mListeners) {
26615e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood                IBinder binder = listener.asBinder();
26715e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood                Listener l = null;
26815e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood                int size = mListeners.size();
26915e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood                for (int i = 0; i < size && l == null; i++) {
27015e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood                    Listener test = mListeners.get(i);
27115e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood                    if (binder.equals(test.mListener.asBinder())) {
27215e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood                        l = test;
27315e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood                    }
27415e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood                }
27515e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood
27615e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood                if (l != null) {
27715e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood                    mListeners.remove(l);
27815e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood                    binder.unlinkToDeath(l, 0);
27915e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood                }
28015e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood            }
28115e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood        }
28215e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood    };
28315e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood
28415e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood    public IGpsStatusProvider getGpsStatusProvider() {
28515e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood        return mGpsStatusProvider;
28615e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood    }
28715e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood
28829c84340a14e70419449628ab193d11b7a609e9aMike Lockwood    private final BroadcastReceiver mBroadcastReciever = new BroadcastReceiver() {
289105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        @Override public void onReceive(Context context, Intent intent) {
290105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            String action = intent.getAction();
291105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
29229c84340a14e70419449628ab193d11b7a609e9aMike Lockwood            if (action.equals(ALARM_WAKEUP)) {
29329c84340a14e70419449628ab193d11b7a609e9aMike Lockwood                if (DEBUG) Log.d(TAG, "ALARM_WAKEUP");
29429c84340a14e70419449628ab193d11b7a609e9aMike Lockwood                startNavigating();
29529c84340a14e70419449628ab193d11b7a609e9aMike Lockwood            } else if (action.equals(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED)) {
296105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                String state = intent.getStringExtra(Phone.STATE_KEY);
297105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                String apnName = intent.getStringExtra(Phone.DATA_APN_KEY);
298105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                String reason = intent.getStringExtra(Phone.STATE_CHANGE_REASON_KEY);
299105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
300105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                if (Config.LOGD) {
301105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                    Log.d(TAG, "state: " + state +  " apnName: " + apnName + " reason: " + reason);
302105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                }
303e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood                // FIXME - might not have an APN on CDMA
304375cbb47ff721a26b62385211b82a7cf26db0395Mike Lockwood                if ("CONNECTED".equals(state) && apnName != null && apnName.length() > 0) {
305e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood                    mAGpsApn = apnName;
306e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood                    if (mAGpsDataConnectionState == AGPS_DATA_CONNECTION_OPENING) {
307e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood                        native_agps_data_conn_open(mAGpsApn);
308e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood                        mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPEN;
30958bda987665af759c379cd494ff4873ac61acf29Mike Lockwood                    }
310105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                }
311105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            }
312105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        }
31329c84340a14e70419449628ab193d11b7a609e9aMike Lockwood    };
314105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
3159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static boolean isSupported() {
3169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return native_is_supported();
3179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3194e50b78bda9cd58be61581d2886c88ff6348a1c1Mike Lockwood    public GpsLocationProvider(Context context, ILocationManager locationManager) {
3209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext = context;
32115e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood        mLocationManager = locationManager;
3229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3230528b9b26a9d64ba43acd0e334638303d514b8ebMike Lockwood        // Create a wake lock
3240528b9b26a9d64ba43acd0e334638303d514b8ebMike Lockwood        PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
3250528b9b26a9d64ba43acd0e334638303d514b8ebMike Lockwood        mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
3260528b9b26a9d64ba43acd0e334638303d514b8ebMike Lockwood
32729c84340a14e70419449628ab193d11b7a609e9aMike Lockwood        mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
32829c84340a14e70419449628ab193d11b7a609e9aMike Lockwood        mWakeupIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_WAKEUP), 0);
32929c84340a14e70419449628ab193d11b7a609e9aMike Lockwood
330105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        IntentFilter intentFilter = new IntentFilter();
33129c84340a14e70419449628ab193d11b7a609e9aMike Lockwood        intentFilter.addAction(ALARM_WAKEUP);
332105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        intentFilter.addAction(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED);
33329c84340a14e70419449628ab193d11b7a609e9aMike Lockwood        context.registerReceiver(mBroadcastReciever, intentFilter);
334105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
33558bda987665af759c379cd494ff4873ac61acf29Mike Lockwood        mConnMgr = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
33658bda987665af759c379cd494ff4873ac61acf29Mike Lockwood
3372f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood        // Battery statistics service to be notified when GPS turns on or off
3382f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood        mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService("batteryinfo"));
3392f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood
3409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mProperties = new Properties();
3419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
3429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            File file = new File(PROPERTIES_FILE);
3439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            FileInputStream stream = new FileInputStream(file);
3449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mProperties.load(stream);
3459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            stream.close();
3469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mNtpServer = mProperties.getProperty("NTP_SERVER", null);
347e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood
348105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            mSuplHost = mProperties.getProperty("SUPL_HOST");
349e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood            String portString = mProperties.getProperty("SUPL_PORT");
350e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood            if (mSuplHost != null && portString != null) {
351105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                try {
352e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood                    mSuplPort = Integer.parseInt(portString);
353105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                    mSetSuplServer = true;
354105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                } catch (NumberFormatException e) {
355e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood                    Log.e(TAG, "unable to parse SUPL_PORT: " + portString);
356e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood                }
357e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood            }
358e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood
359e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood            mC2KHost = mProperties.getProperty("C2K_HOST");
360e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood            portString = mProperties.getProperty("C2K_PORT");
361e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood            if (mC2KHost != null && portString != null) {
362e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood                try {
363e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood                    mC2KPort = Integer.parseInt(portString);
364e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood                    mSetC2KServer = true;
365e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood                } catch (NumberFormatException e) {
366e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood                    Log.e(TAG, "unable to parse C2K_PORT: " + portString);
367105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                }
368105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            }
3699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } catch (IOException e) {
3709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Log.w(TAG, "Could not open GPS configuration file " + PROPERTIES_FILE);
3719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Returns true if the provider requires access to a
3769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * data network (e.g., the Internet), false otherwise.
3779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean requiresNetwork() {
3799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // We want updateNetworkState() to get called when the network state changes
3809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // for XTRA and NTP time injection support.
381e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood        return (mNtpServer != null || native_supports_xtra() ||
382e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood                mSuplHost != null || mC2KHost != null);
3839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void updateNetworkState(int state) {
3869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mNetworkAvailable = (state == LocationProvider.AVAILABLE);
3879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (Config.LOGD) {
3899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Log.d(TAG, "updateNetworkState " + (mNetworkAvailable ? "available" : "unavailable"));
3909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mNetworkAvailable && mNetworkThread != null && mEnabled) {
3939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // signal the network thread when the network becomes available
3949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mNetworkThread.signal();
3959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Returns true if the provider requires access to a
4009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * satellite-based positioning system (e.g., GPS), false
4019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * otherwise.
4029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
4039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean requiresSatellite() {
4049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
4059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
4089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Returns true if the provider requires access to an appropriate
4099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * cellular network (e.g., to make use of cell tower IDs), false
4109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * otherwise.
4119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
4129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean requiresCell() {
4139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return false;
4149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
4179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Returns true if the use of this provider may result in a
4189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * monetary charge to the user, false if use is free.  It is up to
4199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * each provider to give accurate information.
4209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
4219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean hasMonetaryCost() {
4229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return false;
4239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
4269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Returns true if the provider is able to provide altitude
4279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * information, false otherwise.  A provider that reports altitude
4289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * under most circumstances but may occassionally not report it
4299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * should return true.
4309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
4319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean supportsAltitude() {
4329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
4339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
4369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Returns true if the provider is able to provide speed
4379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * information, false otherwise.  A provider that reports speed
4389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * under most circumstances but may occassionally not report it
4399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * should return true.
4409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
4419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean supportsSpeed() {
4429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
4439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
4469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Returns true if the provider is able to provide bearing
4479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * information, false otherwise.  A provider that reports bearing
4489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * under most circumstances but may occassionally not report it
4499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * should return true.
4509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
4519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean supportsBearing() {
4529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
4539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
4569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Returns the power requirement for this provider.
4579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
4589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return the power requirement for this provider, as one of the
4599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * constants Criteria.POWER_REQUIREMENT_*.
4609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
4619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getPowerRequirement() {
4629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return Criteria.POWER_HIGH;
4639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
4669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Returns the horizontal accuracy of this provider
4679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
4689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return the accuracy of location from this provider, as one
4699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * of the constants Criteria.ACCURACY_*.
4709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
4719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getAccuracy() {
4729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return Criteria.ACCURACY_FINE;
4739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
4769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Enables this provider.  When enabled, calls to getStatus()
4774e50b78bda9cd58be61581d2886c88ff6348a1c1Mike Lockwood     * must be handled.  Hardware may be started up
4789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * when the provider is enabled.
4799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
4809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized void enable() {
4819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (Config.LOGD) Log.d(TAG, "enable");
4829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mEnabled) return;
4839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mEnabled = native_init();
4849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mEnabled) {
4869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // run event listener thread while we are enabled
4879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mEventThread = new GpsEventThread();
4889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mEventThread.start();
4899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (requiresNetwork()) {
4919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // run network thread for NTP and XTRA support
4929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (mNetworkThread == null) {
4939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mNetworkThread = new GpsNetworkThread();
4949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mNetworkThread.start();
4959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else {
4969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mNetworkThread.signal();
4979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
4989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
4999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
5009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Log.w(TAG, "Failed to enable location provider");
5019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
5059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Disables this provider.  When disabled, calls to getStatus()
5064e50b78bda9cd58be61581d2886c88ff6348a1c1Mike Lockwood     * need not be handled.  Hardware may be shut
5079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * down while the provider is disabled.
5089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
5099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized void disable() {
5109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (Config.LOGD) Log.d(TAG, "disable");
5119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!mEnabled) return;
5129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mEnabled = false;
5149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        stopNavigating();
5159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        native_disable();
5169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // make sure our event thread exits
5189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mEventThread != null) {
5199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            try {
5209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mEventThread.join();
5219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } catch (InterruptedException e) {
5229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Log.w(TAG, "InterruptedException when joining mEventThread");
5239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mEventThread = null;
5259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mNetworkThread != null) {
5289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mNetworkThread.setDone();
5299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mNetworkThread = null;
5309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
532d654f9f727b415b153c7190832db4b65f6943f32Mike Lockwood        // The GpsEventThread does not wait for the GPS to shutdown
533d654f9f727b415b153c7190832db4b65f6943f32Mike Lockwood        // so we need to report the GPS_STATUS_ENGINE_OFF event here
534d654f9f727b415b153c7190832db4b65f6943f32Mike Lockwood        if (mNavigating) {
535d654f9f727b415b153c7190832db4b65f6943f32Mike Lockwood            reportStatus(GPS_STATUS_ENGINE_OFF);
536d654f9f727b415b153c7190832db4b65f6943f32Mike Lockwood        }
537d654f9f727b415b153c7190832db4b65f6943f32Mike Lockwood
5389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        native_cleanup();
5399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean isEnabled() {
5429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mEnabled;
5439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getStatus(Bundle extras) {
5469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (extras != null) {
5479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            extras.putInt("satellites", mSvCount);
5489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mStatus;
5509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void updateStatus(int status, int svCount) {
5539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (status != mStatus || svCount != mSvCount) {
5549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mStatus = status;
5559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mSvCount = svCount;
5569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mLocationExtras.putInt("satellites", svCount);
5579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mStatusUpdateTime = SystemClock.elapsedRealtime();
5589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public long getStatusUpdateTime() {
5629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mStatusUpdateTime;
5639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void enableLocationTracking(boolean enable) {
5669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (enable) {
5679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mTTFF = 0;
5689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mLastFixTime = 0;
5699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            startNavigating();
5709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
57129c84340a14e70419449628ab193d11b7a609e9aMike Lockwood            mAlarmManager.cancel(mWakeupIntent);
5729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            stopNavigating();
5739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setMinTime(long minTime) {
5779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (Config.LOGD) Log.d(TAG, "setMinTime " + minTime);
5789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (minTime >= 0) {
5809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int interval = (int)(minTime/1000);
5819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (interval < 1) {
5829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                interval = 1;
5839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mFixInterval = interval;
5859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final class Listener implements IBinder.DeathRecipient {
5899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final IGpsStatusListener mListener;
5909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int mSensors = 0;
5929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Listener(IGpsStatusListener listener) {
5949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mListener = listener;
5959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void binderDied() {
5989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (Config.LOGD) Log.d(TAG, "GPS status listener died");
5999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            synchronized(mListeners) {
6019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mListeners.remove(this);
6029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
6039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6062f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood    public void addListener(int uid) {
6072f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood        mClientUids.put(uid, 0);
6082f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood        if (mNavigating) {
6092f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood            try {
6102f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood                mBatteryStats.noteStartGps(uid);
6112f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood            } catch (RemoteException e) {
6122f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood                Log.w(TAG, "RemoteException in addListener");
6132f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood            }
6142f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood        }
6152f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood    }
6162f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood
6172f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood    public void removeListener(int uid) {
6182f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood        mClientUids.delete(uid);
6192f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood        if (mNavigating) {
6202f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood            try {
6212f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood                mBatteryStats.noteStopGps(uid);
6222f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood            } catch (RemoteException e) {
6232f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood                Log.w(TAG, "RemoteException in removeListener");
6242f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood            }
6252f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood        }
6262f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood    }
6272f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood
6289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean sendExtraCommand(String command, Bundle extras) {
6299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if ("delete_aiding_data".equals(command)) {
6319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return deleteAidingData(extras);
6329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Log.w(TAG, "sendExtraCommand: unknown command " + command);
6359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return false;
6369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean deleteAidingData(Bundle extras) {
6399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int flags;
6409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (extras == null) {
6429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            flags = GPS_DELETE_ALL;
6439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
6449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            flags = 0;
6459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (extras.getBoolean("ephemeris")) flags |= GPS_DELETE_EPHEMERIS;
6469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (extras.getBoolean("almanac")) flags |= GPS_DELETE_ALMANAC;
6479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (extras.getBoolean("position")) flags |= GPS_DELETE_POSITION;
6489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (extras.getBoolean("time")) flags |= GPS_DELETE_TIME;
6499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (extras.getBoolean("iono")) flags |= GPS_DELETE_IONO;
6509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (extras.getBoolean("utc")) flags |= GPS_DELETE_UTC;
6519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (extras.getBoolean("health")) flags |= GPS_DELETE_HEALTH;
6529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (extras.getBoolean("svdir")) flags |= GPS_DELETE_SVDIR;
6539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (extras.getBoolean("svsteer")) flags |= GPS_DELETE_SVSTEER;
6549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (extras.getBoolean("sadata")) flags |= GPS_DELETE_SADATA;
6559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (extras.getBoolean("rti")) flags |= GPS_DELETE_RTI;
6569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (extras.getBoolean("celldb-info")) flags |= GPS_DELETE_CELLDB_INFO;
6579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (extras.getBoolean("all")) flags |= GPS_DELETE_ALL;
6589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (flags != 0) {
6619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            native_delete_aiding_data(flags);
6629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return true;
6639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return false;
6669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void startNavigating() {
6699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!mStarted) {
67029c84340a14e70419449628ab193d11b7a609e9aMike Lockwood            if (DEBUG) Log.d(TAG, "startNavigating");
6719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mStarted = true;
672105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            if (!native_start(mPositionMode, false, mFixInterval)) {
6739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mStarted = false;
6749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Log.e(TAG, "native_start failed in startNavigating()");
6759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
6769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // reset SV count to zero
67815e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood            updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE, 0);
67929c84340a14e70419449628ab193d11b7a609e9aMike Lockwood            mFixCount = 0;
68029c84340a14e70419449628ab193d11b7a609e9aMike Lockwood            mFixRequestTime = System.currentTimeMillis();
6819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void stopNavigating() {
68529c84340a14e70419449628ab193d11b7a609e9aMike Lockwood        if (DEBUG) Log.d(TAG, "stopNavigating");
6869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mStarted) {
6879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mStarted = false;
6889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            native_stop();
6899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mTTFF = 0;
6909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mLastFixTime = 0;
6919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mLocationFlags = LOCATION_INVALID;
6929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // reset SV count to zero
69415e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood            updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE, 0);
6959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
6999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * called from native code to update our position.
7009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
7019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void reportLocation(int flags, double latitude, double longitude, double altitude,
7029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            float speed, float bearing, float accuracy, long timestamp) {
70329c84340a14e70419449628ab193d11b7a609e9aMike Lockwood        if (VERBOSE) Log.v(TAG, "reportLocation lat: " + latitude + " long: " + longitude +
7049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                " timestamp: " + timestamp);
7059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mLastFixTime = System.currentTimeMillis();
7079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // report time to first fix
7089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mTTFF == 0 && (flags & LOCATION_HAS_LAT_LONG) == LOCATION_HAS_LAT_LONG) {
7099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mTTFF = (int)(mLastFixTime - mFixRequestTime);
7109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (Config.LOGD) Log.d(TAG, "TTFF: " + mTTFF);
7119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // notify status listeners
7139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            synchronized(mListeners) {
7149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                int size = mListeners.size();
7159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                for (int i = 0; i < size; i++) {
7169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    Listener listener = mListeners.get(i);
7179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    try {
7189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        listener.mListener.onFirstFix(mTTFF);
7199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    } catch (RemoteException e) {
7209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        Log.w(TAG, "RemoteException in stopNavigating");
7219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        mListeners.remove(listener);
7229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        // adjust for size of list changing
7239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        size--;
7249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
7259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
7269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
7279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        synchronized (mLocation) {
7309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mLocationFlags = flags;
7319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if ((flags & LOCATION_HAS_LAT_LONG) == LOCATION_HAS_LAT_LONG) {
7329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mLocation.setLatitude(latitude);
7339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mLocation.setLongitude(longitude);
7349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mLocation.setTime(timestamp);
7359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
7369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if ((flags & LOCATION_HAS_ALTITUDE) == LOCATION_HAS_ALTITUDE) {
7379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mLocation.setAltitude(altitude);
7389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
7399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mLocation.removeAltitude();
7409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
7419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if ((flags & LOCATION_HAS_SPEED) == LOCATION_HAS_SPEED) {
7429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mLocation.setSpeed(speed);
7439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
7449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mLocation.removeSpeed();
7459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
7469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if ((flags & LOCATION_HAS_BEARING) == LOCATION_HAS_BEARING) {
7479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mLocation.setBearing(bearing);
7489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
7499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mLocation.removeBearing();
7509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
7519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if ((flags & LOCATION_HAS_ACCURACY) == LOCATION_HAS_ACCURACY) {
7529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mLocation.setAccuracy(accuracy);
7539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
7549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mLocation.removeAccuracy();
7559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
7569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
75715e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood            try {
758275555c8eb3fb5df6e7320873b88b77cdde85a9eMike Lockwood                mLocationManager.reportLocation(mLocation);
75915e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood            } catch (RemoteException e) {
76015e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood                Log.e(TAG, "RemoteException calling reportLocation");
76115e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood            }
7629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
76415e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood        if (mStarted && mStatus != LocationProvider.AVAILABLE) {
7659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // send an intent to notify that the GPS is receiving fixes.
7669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Intent intent = new Intent(GPS_FIX_CHANGE_ACTION);
7679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            intent.putExtra(EXTRA_ENABLED, true);
7689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mContext.sendBroadcast(intent);
76915e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood            updateStatus(LocationProvider.AVAILABLE, mSvCount);
7709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
77129c84340a14e70419449628ab193d11b7a609e9aMike Lockwood
77229c84340a14e70419449628ab193d11b7a609e9aMike Lockwood        if (mFixCount++ >= MIN_FIX_COUNT && mFixInterval > 1) {
77329c84340a14e70419449628ab193d11b7a609e9aMike Lockwood            if (DEBUG) Log.d(TAG, "exceeded MIN_FIX_COUNT");
77429c84340a14e70419449628ab193d11b7a609e9aMike Lockwood            stopNavigating();
77529c84340a14e70419449628ab193d11b7a609e9aMike Lockwood            mFixCount = 0;
77629c84340a14e70419449628ab193d11b7a609e9aMike Lockwood            mAlarmManager.cancel(mWakeupIntent);
77729c84340a14e70419449628ab193d11b7a609e9aMike Lockwood            long now = SystemClock.elapsedRealtime();
77829c84340a14e70419449628ab193d11b7a609e9aMike Lockwood            mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
77929c84340a14e70419449628ab193d11b7a609e9aMike Lockwood                    SystemClock.elapsedRealtime() + mFixInterval * 1000, mWakeupIntent);
78029c84340a14e70419449628ab193d11b7a609e9aMike Lockwood        }
7819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project   }
7829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
7849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * called from native code to update our status
7859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
7869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void reportStatus(int status) {
78729c84340a14e70419449628ab193d11b7a609e9aMike Lockwood        if (VERBOSE) Log.v(TAG, "reportStatus status: " + status);
7889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean wasNavigating = mNavigating;
7909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mNavigating = (status == GPS_STATUS_SESSION_BEGIN);
7919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (wasNavigating != mNavigating) {
7930528b9b26a9d64ba43acd0e334638303d514b8ebMike Lockwood            if (mNavigating) {
7940528b9b26a9d64ba43acd0e334638303d514b8ebMike Lockwood                if (DEBUG) Log.d(TAG, "Acquiring wakelock");
7950528b9b26a9d64ba43acd0e334638303d514b8ebMike Lockwood                 mWakeLock.acquire();
7960528b9b26a9d64ba43acd0e334638303d514b8ebMike Lockwood            }
7979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            synchronized(mListeners) {
7989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                int size = mListeners.size();
7999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                for (int i = 0; i < size; i++) {
8009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    Listener listener = mListeners.get(i);
8019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    try {
8029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        if (mNavigating) {
8039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            listener.mListener.onGpsStarted();
8049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        } else {
8059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            listener.mListener.onGpsStopped();
8069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
8079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    } catch (RemoteException e) {
8089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        Log.w(TAG, "RemoteException in reportStatus");
8099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        mListeners.remove(listener);
8109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        // adjust for size of list changing
8119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        size--;
8129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
8139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
8149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
8159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8162f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood            try {
8172f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood                // update battery stats
8182f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood                for (int i=mClientUids.size() - 1; i >= 0; i--) {
8192f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood                    int uid = mClientUids.keyAt(i);
8202f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood                    if (mNavigating) {
8212f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood                        mBatteryStats.noteStartGps(uid);
8222f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood                    } else {
8232f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood                        mBatteryStats.noteStopGps(uid);
8242f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood                    }
8252f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood                }
8262f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood            } catch (RemoteException e) {
8272f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood                Log.w(TAG, "RemoteException in reportStatus");
8282f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood            }
8292f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood
8309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // send an intent to notify that the GPS has been enabled or disabled.
8319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Intent intent = new Intent(GPS_ENABLED_CHANGE_ACTION);
8329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            intent.putExtra(EXTRA_ENABLED, mNavigating);
8339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mContext.sendBroadcast(intent);
8340528b9b26a9d64ba43acd0e334638303d514b8ebMike Lockwood
8350528b9b26a9d64ba43acd0e334638303d514b8ebMike Lockwood            if (!mNavigating) {
8360528b9b26a9d64ba43acd0e334638303d514b8ebMike Lockwood                if (DEBUG) Log.d(TAG, "Releasing wakelock");
8370528b9b26a9d64ba43acd0e334638303d514b8ebMike Lockwood                mWakeLock.release();
8380528b9b26a9d64ba43acd0e334638303d514b8ebMike Lockwood            }
8399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
8439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * called from native code to update SV info
8449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
8459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void reportSvStatus() {
8469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int svCount = native_read_sv_status(mSvs, mSnrs, mSvElevations, mSvAzimuths, mSvMasks);
8489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        synchronized(mListeners) {
8509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int size = mListeners.size();
8519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int i = 0; i < size; i++) {
8529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Listener listener = mListeners.get(i);
8539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                try {
8549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    listener.mListener.onSvStatusChanged(svCount, mSvs, mSnrs,
8559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            mSvElevations, mSvAzimuths, mSvMasks[EPHEMERIS_MASK],
8569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            mSvMasks[ALMANAC_MASK], mSvMasks[USED_FOR_FIX_MASK]);
8579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } catch (RemoteException e) {
8589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    Log.w(TAG, "RemoteException in reportSvInfo");
8599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mListeners.remove(listener);
8609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // adjust for size of list changing
8619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    size--;
8629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
8639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
8649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
86629c84340a14e70419449628ab193d11b7a609e9aMike Lockwood        if (VERBOSE) {
86729c84340a14e70419449628ab193d11b7a609e9aMike Lockwood            Log.v(TAG, "SV count: " + svCount +
8689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    " ephemerisMask: " + Integer.toHexString(mSvMasks[EPHEMERIS_MASK]) +
8699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    " almanacMask: " + Integer.toHexString(mSvMasks[ALMANAC_MASK]));
8709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int i = 0; i < svCount; i++) {
87129c84340a14e70419449628ab193d11b7a609e9aMike Lockwood                Log.v(TAG, "sv: " + mSvs[i] +
8729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        " snr: " + (float)mSnrs[i]/10 +
8739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        " elev: " + mSvElevations[i] +
8749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        " azimuth: " + mSvAzimuths[i] +
8759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        ((mSvMasks[EPHEMERIS_MASK] & (1 << (mSvs[i] - 1))) == 0 ? "  " : " E") +
8769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        ((mSvMasks[ALMANAC_MASK] & (1 << (mSvs[i] - 1))) == 0 ? "  " : " A") +
8779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        ((mSvMasks[USED_FOR_FIX_MASK] & (1 << (mSvs[i] - 1))) == 0 ? "" : "U"));
8789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
8799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        updateStatus(mStatus, svCount);
8829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
88315e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood        if (mNavigating && mStatus == LocationProvider.AVAILABLE && mLastFixTime > 0 &&
8849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            System.currentTimeMillis() - mLastFixTime > RECENT_FIX_TIMEOUT) {
8859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // send an intent to notify that the GPS is no longer receiving fixes.
8869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Intent intent = new Intent(GPS_FIX_CHANGE_ACTION);
8879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            intent.putExtra(EXTRA_ENABLED, false);
8889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mContext.sendBroadcast(intent);
88915e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood            updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE, mSvCount);
8909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
89258bda987665af759c379cd494ff4873ac61acf29Mike Lockwood
89358bda987665af759c379cd494ff4873ac61acf29Mike Lockwood    /**
894e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood     * called from native code to update AGPS status
89558bda987665af759c379cd494ff4873ac61acf29Mike Lockwood     */
896e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood    private void reportAGpsStatus(int type, int status) {
89758bda987665af759c379cd494ff4873ac61acf29Mike Lockwood        switch (status) {
898e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood            case GPS_REQUEST_AGPS_DATA_CONN:
89958bda987665af759c379cd494ff4873ac61acf29Mike Lockwood                 int result = mConnMgr.startUsingNetworkFeature(
90058bda987665af759c379cd494ff4873ac61acf29Mike Lockwood                        ConnectivityManager.TYPE_MOBILE, Phone.FEATURE_ENABLE_SUPL);
90158bda987665af759c379cd494ff4873ac61acf29Mike Lockwood                if (result == Phone.APN_ALREADY_ACTIVE) {
902e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood                    native_agps_data_conn_open(mAGpsApn);
903e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood                    mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPEN;
90458bda987665af759c379cd494ff4873ac61acf29Mike Lockwood                } else if (result == Phone.APN_REQUEST_STARTED) {
905e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood                    mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPENING;
90658bda987665af759c379cd494ff4873ac61acf29Mike Lockwood                } else {
907e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood                    native_agps_data_conn_failed();
90858bda987665af759c379cd494ff4873ac61acf29Mike Lockwood                }
90958bda987665af759c379cd494ff4873ac61acf29Mike Lockwood                break;
910e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood            case GPS_RELEASE_AGPS_DATA_CONN:
911e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood                if (mAGpsDataConnectionState != AGPS_DATA_CONNECTION_CLOSED) {
91258bda987665af759c379cd494ff4873ac61acf29Mike Lockwood                    mConnMgr.stopUsingNetworkFeature(
91358bda987665af759c379cd494ff4873ac61acf29Mike Lockwood                            ConnectivityManager.TYPE_MOBILE, Phone.FEATURE_ENABLE_SUPL);
914e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood                    native_agps_data_conn_closed();
915e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood                    mAGpsDataConnectionState = AGPS_DATA_CONNECTION_CLOSED;
91658bda987665af759c379cd494ff4873ac61acf29Mike Lockwood                }
91758bda987665af759c379cd494ff4873ac61acf29Mike Lockwood                break;
918e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood            case GPS_AGPS_DATA_CONNECTED:
919e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood                // Log.d(TAG, "GPS_AGPS_DATA_CONNECTED");
92058bda987665af759c379cd494ff4873ac61acf29Mike Lockwood                break;
921e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood            case GPS_AGPS_DATA_CONN_DONE:
922e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood                // Log.d(TAG, "GPS_AGPS_DATA_CONN_DONE");
92358bda987665af759c379cd494ff4873ac61acf29Mike Lockwood                break;
924e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood            case GPS_AGPS_DATA_CONN_FAILED:
925e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood                // Log.d(TAG, "GPS_AGPS_DATA_CONN_FAILED");
92658bda987665af759c379cd494ff4873ac61acf29Mike Lockwood                break;
92758bda987665af759c379cd494ff4873ac61acf29Mike Lockwood        }
92858bda987665af759c379cd494ff4873ac61acf29Mike Lockwood    }
92958bda987665af759c379cd494ff4873ac61acf29Mike Lockwood
9309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void xtraDownloadRequest() {
9319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (Config.LOGD) Log.d(TAG, "xtraDownloadRequest");
9329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mNetworkThread != null) {
9339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mNetworkThread.xtraDownloadRequest();
9349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
937e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood    private boolean setAGpsServer(int type, String host, int port) {
938e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood        try {
939e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood            InetAddress inetAddress = InetAddress.getByName(host);
940e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood            if (inetAddress != null) {
941e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood                byte[] addrBytes = inetAddress.getAddress();
942e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood                long addr = 0;
943e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood                for (int i = 0; i < addrBytes.length; i++) {
944e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood                    int temp = addrBytes[i];
945e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood                    // signed -> unsigned
946e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood                    if (temp < 0) temp = 256 + temp;
947e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood                    addr = addr * 256 + temp;
948e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood                }
949e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood                // use MS-Based position mode if SUPL support is enabled
950e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood                mPositionMode = GPS_POSITION_MODE_MS_BASED;
951e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood                native_set_agps_server(type, (int)addr, port);
952e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood            }
953e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood        } catch (UnknownHostException e) {
954e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood            Log.e(TAG, "unknown host for server " + host);
955e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood            return false;
956e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood        }
957e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood        return true;
958e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood    }
959e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood
9609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private class GpsEventThread extends Thread {
9619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public GpsEventThread() {
9639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            super("GpsEventThread");
9649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void run() {
9679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (Config.LOGD) Log.d(TAG, "GpsEventThread starting");
968d654f9f727b415b153c7190832db4b65f6943f32Mike Lockwood            // Exit as soon as disable() is called instead of waiting for the GPS to stop.
969d654f9f727b415b153c7190832db4b65f6943f32Mike Lockwood            while (mEnabled) {
9709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // this will wait for an event from the GPS,
9719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // which will be reported via reportLocation or reportStatus
9729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                native_wait_for_event();
9739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
9749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (Config.LOGD) Log.d(TAG, "GpsEventThread exiting");
9759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private class GpsNetworkThread extends Thread {
9799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private long mNextNtpTime = 0;
9819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private long mNextXtraTime = 0;
9829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private boolean mXtraDownloadRequested = false;
9839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private boolean mDone = false;
9849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public GpsNetworkThread() {
9869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            super("GpsNetworkThread");
9879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void run() {
9909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            synchronized (mNetworkThreadLock) {
9919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (!mDone) {
9929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    runLocked();
9939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
9949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
9959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void runLocked() {
9989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (Config.LOGD) Log.d(TAG, "NetworkThread starting");
9999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            SntpClient client = new SntpClient();
10019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            GpsXtraDownloader xtraDownloader = null;
10029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (native_supports_xtra()) {
10049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                xtraDownloader = new GpsXtraDownloader(mContext, mProperties);
10059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
10069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // thread exits after disable() is called
10089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            while (!mDone) {
10099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                long waitTime = getWaitTime();
10109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                do {
10119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    synchronized (this) {
10129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        try {
10139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            if (!mNetworkAvailable) {
10149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                if (Config.LOGD) Log.d(TAG,
10159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                        "NetworkThread wait for network");
10169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                wait();
10179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            } else if (waitTime > 0) {
10189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                if (Config.LOGD) {
10199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                    Log.d(TAG, "NetworkThread wait for " +
10209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                            waitTime + "ms");
10219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                }
10229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                wait(waitTime);
10239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            }
10249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        } catch (InterruptedException e) {
10259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            if (Config.LOGD) {
10269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                Log.d(TAG, "InterruptedException in GpsNetworkThread");
10279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            }
10289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
10299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
10309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    waitTime = getWaitTime();
1031e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood                } while (!mDone && ((!mXtraDownloadRequested &&
1032e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood                        !mSetSuplServer && !mSetC2KServer && waitTime > 0)
10339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        || !mNetworkAvailable));
10349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (Config.LOGD) Log.d(TAG, "NetworkThread out of wake loop");
10359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (!mDone) {
10379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (mNtpServer != null &&
10389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            mNextNtpTime <= System.currentTimeMillis()) {
10399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        if (Config.LOGD) {
10409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            Log.d(TAG, "Requesting time from NTP server " + mNtpServer);
10419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
10429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        if (client.requestTime(mNtpServer, 10000)) {
10439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            long time = client.getNtpTime();
10449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            long timeReference = client.getNtpTimeReference();
10459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            int certainty = (int)(client.getRoundTripTime()/2);
10469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            if (Config.LOGD) Log.d(TAG, "calling native_inject_time: " +
10489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                    time + " reference: " + timeReference
10499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                    + " certainty: " + certainty);
10509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            native_inject_time(time, timeReference, certainty);
10529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            mNextNtpTime = System.currentTimeMillis() + NTP_INTERVAL;
10539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        } else {
10549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            if (Config.LOGD) Log.d(TAG, "requestTime failed");
10559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            mNextNtpTime = System.currentTimeMillis() + RETRY_INTERVAL;
10569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
10579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
10589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1059e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood                    // Set the AGPS server addresses if we have not yet
1060105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                    if (mSetSuplServer) {
1061e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood                        if (setAGpsServer(AGPS_TYPE_SUPL, mSuplHost, mSuplPort)) {
1062e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood                            mSetSuplServer = false;
1063e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood                        }
1064e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood                    }
1065e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood                    if (mSetC2KServer) {
1066e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood                        if (setAGpsServer(AGPS_TYPE_C2K, mC2KHost, mC2KPort)) {
1067e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood                            mSetC2KServer = false;
1068105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                        }
1069105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                    }
1070105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
10719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if ((mXtraDownloadRequested ||
10729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            (mNextXtraTime > 0 && mNextXtraTime <= System.currentTimeMillis()))
10739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            && xtraDownloader != null) {
10749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        byte[] data = xtraDownloader.downloadXtraData();
10759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        if (data != null) {
10769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            if (Config.LOGD) {
10779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                Log.d(TAG, "calling native_inject_xtra_data");
10789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            }
10799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            native_inject_xtra_data(data, data.length);
10809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            mNextXtraTime = 0;
10819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            mXtraDownloadRequested = false;
10829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        } else {
10839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            mNextXtraTime = System.currentTimeMillis() + RETRY_INTERVAL;
10849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
10859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
10869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
10879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
10889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (Config.LOGD) Log.d(TAG, "NetworkThread exiting");
10899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        synchronized void xtraDownloadRequest() {
10929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mXtraDownloadRequested = true;
10939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            notify();
10949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        synchronized void signal() {
10979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            notify();
10989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        synchronized void setDone() {
11019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (Config.LOGD) Log.d(TAG, "stopping NetworkThread");
11029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mDone = true;
11039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            notify();
11049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private long getWaitTime() {
11079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            long now = System.currentTimeMillis();
11089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            long waitTime = Long.MAX_VALUE;
11099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mNtpServer != null) {
11109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                waitTime = mNextNtpTime - now;
11119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
11129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mNextXtraTime != 0) {
11139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                long xtraWaitTime = mNextXtraTime - now;
11149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (xtraWaitTime < waitTime) {
11159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    waitTime = xtraWaitTime;
11169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
11179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
11189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (waitTime < 0) {
11199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                waitTime = 0;
11209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
11219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return waitTime;
11229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // for GPS SV statistics
11269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int MAX_SVS = 32;
11279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int EPHEMERIS_MASK = 0;
11289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int ALMANAC_MASK = 1;
11299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int USED_FOR_FIX_MASK = 2;
11309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // preallocated arrays, to avoid memory allocation in reportStatus()
11329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int mSvs[] = new int[MAX_SVS];
11339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private float mSnrs[] = new float[MAX_SVS];
11349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private float mSvElevations[] = new float[MAX_SVS];
11359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private float mSvAzimuths[] = new float[MAX_SVS];
11369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int mSvMasks[] = new int[3];
11379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int mSvCount;
11389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    static { class_init_native(); }
11409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static native void class_init_native();
11419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static native boolean native_is_supported();
11429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private native boolean native_init();
11449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private native void native_disable();
11459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private native void native_cleanup();
1146105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    private native boolean native_start(int positionMode, boolean singleFix, int fixInterval);
11479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private native boolean native_stop();
11489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private native void native_set_fix_frequency(int fixFrequency);
11499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private native void native_delete_aiding_data(int flags);
11509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private native void native_wait_for_event();
11519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // returns number of SVs
11529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // mask[0] is ephemeris mask and mask[1] is almanac mask
11539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private native int native_read_sv_status(int[] svs, float[] snrs,
11549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            float[] elevations, float[] azimuths, int[] masks);
11559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // XTRA Support
11579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private native void native_inject_time(long time, long timeReference, int uncertainty);
11589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private native boolean native_supports_xtra();
11599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private native void native_inject_xtra_data(byte[] data, int length);
1160105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
1161e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood    // AGPS Support
1162e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood    private native void native_agps_data_conn_open(String apn);
1163e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood    private native void native_agps_data_conn_closed();
1164e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood    private native void native_agps_data_conn_failed();
1165e3635c9693c4cd9650684f14e19dcabcea0d488aMike Lockwood    private native void native_set_agps_server(int type, int addr, int port);
11669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1167