19d10b341a0ba46f108cb96e46691197d778cbc06San Mehat/* 29d10b341a0ba46f108cb96e46691197d778cbc06San Mehat * Copyright (C) 2008 The Android Open Source Project 39d10b341a0ba46f108cb96e46691197d778cbc06San Mehat * 49d10b341a0ba46f108cb96e46691197d778cbc06San Mehat * Licensed under the Apache License, Version 2.0 (the "License"); 59d10b341a0ba46f108cb96e46691197d778cbc06San Mehat * you may not use this file except in compliance with the License. 69d10b341a0ba46f108cb96e46691197d778cbc06San Mehat * You may obtain a copy of the License at 79d10b341a0ba46f108cb96e46691197d778cbc06San Mehat * 89d10b341a0ba46f108cb96e46691197d778cbc06San Mehat * http://www.apache.org/licenses/LICENSE-2.0 99d10b341a0ba46f108cb96e46691197d778cbc06San Mehat * 109d10b341a0ba46f108cb96e46691197d778cbc06San Mehat * Unless required by applicable law or agreed to in writing, software 119d10b341a0ba46f108cb96e46691197d778cbc06San Mehat * distributed under the License is distributed on an "AS IS" BASIS, 129d10b341a0ba46f108cb96e46691197d778cbc06San Mehat * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 139d10b341a0ba46f108cb96e46691197d778cbc06San Mehat * See the License for the specific language governing permissions and 149d10b341a0ba46f108cb96e46691197d778cbc06San Mehat * limitations under the License. 159d10b341a0ba46f108cb96e46691197d778cbc06San Mehat */ 169d10b341a0ba46f108cb96e46691197d778cbc06San Mehat 179d10b341a0ba46f108cb96e46691197d778cbc06San Mehatpackage com.android.locationtracker; 189d10b341a0ba46f108cb96e46691197d778cbc06San Mehat 1918737845d3c6a60edd6f75ac441a1b3fed6d66a7San Mehatimport com.android.locationtracker.data.TrackerDataHelper; 2018737845d3c6a60edd6f75ac441a1b3fed6d66a7San Mehat 219d10b341a0ba46f108cb96e46691197d778cbc06San Mehatimport android.app.Service; 229d10b341a0ba46f108cb96e46691197d778cbc06San Mehatimport android.content.BroadcastReceiver; 2318737845d3c6a60edd6f75ac441a1b3fed6d66a7San Mehatimport android.content.Context; 2418737845d3c6a60edd6f75ac441a1b3fed6d66a7San Mehatimport android.content.Intent; 2518737845d3c6a60edd6f75ac441a1b3fed6d66a7San Mehatimport android.content.IntentFilter; 269d10b341a0ba46f108cb96e46691197d778cbc06San Mehatimport android.content.SharedPreferences; 279d10b341a0ba46f108cb96e46691197d778cbc06San Mehatimport android.content.SharedPreferences.OnSharedPreferenceChangeListener; 289d10b341a0ba46f108cb96e46691197d778cbc06San Mehatimport android.location.Location; 299d10b341a0ba46f108cb96e46691197d778cbc06San Mehatimport android.location.LocationListener; 309d10b341a0ba46f108cb96e46691197d778cbc06San Mehatimport android.location.LocationManager; 319d10b341a0ba46f108cb96e46691197d778cbc06San Mehatimport android.net.ConnectivityManager; 329d10b341a0ba46f108cb96e46691197d778cbc06San Mehatimport android.net.wifi.ScanResult; 339d10b341a0ba46f108cb96e46691197d778cbc06San Mehatimport android.net.wifi.WifiManager; 349d10b341a0ba46f108cb96e46691197d778cbc06San Mehatimport android.os.Bundle; 359d10b341a0ba46f108cb96e46691197d778cbc06San Mehatimport android.os.IBinder; 369d10b341a0ba46f108cb96e46691197d778cbc06San Mehatimport android.preference.PreferenceManager; 379d10b341a0ba46f108cb96e46691197d778cbc06San Mehatimport android.telephony.CellLocation; 389d10b341a0ba46f108cb96e46691197d778cbc06San Mehatimport android.telephony.PhoneStateListener; 399d10b341a0ba46f108cb96e46691197d778cbc06San Mehatimport android.telephony.SignalStrength; 409d10b341a0ba46f108cb96e46691197d778cbc06San Mehatimport android.telephony.TelephonyManager; 419d10b341a0ba46f108cb96e46691197d778cbc06San Mehatimport android.telephony.cdma.CdmaCellLocation; 429d10b341a0ba46f108cb96e46691197d778cbc06San Mehatimport android.telephony.gsm.GsmCellLocation; 439d10b341a0ba46f108cb96e46691197d778cbc06San Mehatimport android.util.Log; 449d10b341a0ba46f108cb96e46691197d778cbc06San Mehatimport android.widget.Toast; 459d10b341a0ba46f108cb96e46691197d778cbc06San Mehat 469d10b341a0ba46f108cb96e46691197d778cbc06San Mehatimport java.util.ArrayList; 479d10b341a0ba46f108cb96e46691197d778cbc06San Mehatimport java.util.HashSet; 489d10b341a0ba46f108cb96e46691197d778cbc06San Mehatimport java.util.List; 499d10b341a0ba46f108cb96e46691197d778cbc06San Mehatimport java.util.Set; 509d10b341a0ba46f108cb96e46691197d778cbc06San Mehat 519d10b341a0ba46f108cb96e46691197d778cbc06San Mehat/** 529d10b341a0ba46f108cb96e46691197d778cbc06San Mehat * Location Tracking service 539d10b341a0ba46f108cb96e46691197d778cbc06San Mehat * 549d10b341a0ba46f108cb96e46691197d778cbc06San Mehat * Records location updates for all registered location providers, and cell 559d10b341a0ba46f108cb96e46691197d778cbc06San Mehat * location updates 569d10b341a0ba46f108cb96e46691197d778cbc06San Mehat */ 579d10b341a0ba46f108cb96e46691197d778cbc06San Mehatpublic class TrackerService extends Service { 589d10b341a0ba46f108cb96e46691197d778cbc06San Mehat 599d10b341a0ba46f108cb96e46691197d778cbc06San Mehat private List<LocationTrackingListener> mListeners; 609d10b341a0ba46f108cb96e46691197d778cbc06San Mehat 619d10b341a0ba46f108cb96e46691197d778cbc06San Mehat private static final String LOG_TAG = TrackerActivity.LOG_TAG; 629d10b341a0ba46f108cb96e46691197d778cbc06San Mehat 639d10b341a0ba46f108cb96e46691197d778cbc06San Mehat // controls which location providers to track 649d10b341a0ba46f108cb96e46691197d778cbc06San Mehat private Set<String> mTrackedProviders; 659d10b341a0ba46f108cb96e46691197d778cbc06San Mehat 669d10b341a0ba46f108cb96e46691197d778cbc06San Mehat private TrackerDataHelper mTrackerData; 679d10b341a0ba46f108cb96e46691197d778cbc06San Mehat 689d10b341a0ba46f108cb96e46691197d778cbc06San Mehat private TelephonyManager mTelephonyManager; 699d10b341a0ba46f108cb96e46691197d778cbc06San Mehat private Location mNetworkLocation; 709d10b341a0ba46f108cb96e46691197d778cbc06San Mehat 719d10b341a0ba46f108cb96e46691197d778cbc06San Mehat // Handlers and Receivers for phone and network state 729d10b341a0ba46f108cb96e46691197d778cbc06San Mehat private NetworkStateBroadcastReceiver mNetwork; 739d10b341a0ba46f108cb96e46691197d778cbc06San Mehat private static final String CELL_PROVIDER_TAG = "cell"; 749d10b341a0ba46f108cb96e46691197d778cbc06San Mehat // signal strength updates 759d10b341a0ba46f108cb96e46691197d778cbc06San Mehat private static final String SIGNAL_PROVIDER_TAG = "signal"; 769d10b341a0ba46f108cb96e46691197d778cbc06San Mehat private static final String WIFI_PROVIDER_TAG = "wifi"; 779d10b341a0ba46f108cb96e46691197d778cbc06San Mehat // tracking tag for data connectivity issues 789d10b341a0ba46f108cb96e46691197d778cbc06San Mehat private static final String DATA_CONN_PROVIDER_TAG = "data"; 799d10b341a0ba46f108cb96e46691197d778cbc06San Mehat 809d10b341a0ba46f108cb96e46691197d778cbc06San Mehat // preference constants 819d10b341a0ba46f108cb96e46691197d778cbc06San Mehat private static final String MIN_TIME_PREF = "mintime_preference"; 829d10b341a0ba46f108cb96e46691197d778cbc06San Mehat private static final String MIN_DIS_PREF = "mindistance_preference"; 839d10b341a0ba46f108cb96e46691197d778cbc06San Mehat private static final String GPS_PREF = "gps_preference"; 849d10b341a0ba46f108cb96e46691197d778cbc06San Mehat private static final String NETWORK_PREF = "network_preference"; 859d10b341a0ba46f108cb96e46691197d778cbc06San Mehat private static final String SIGNAL_PREF = "signal_preference"; 869d10b341a0ba46f108cb96e46691197d778cbc06San Mehat private static final String DEBUG_PREF = "advanced_log_preference"; 879d10b341a0ba46f108cb96e46691197d778cbc06San Mehat 889d10b341a0ba46f108cb96e46691197d778cbc06San Mehat private PreferenceListener mPrefListener; 899d10b341a0ba46f108cb96e46691197d778cbc06San Mehat 909d10b341a0ba46f108cb96e46691197d778cbc06San Mehat public TrackerService() { 919d10b341a0ba46f108cb96e46691197d778cbc06San Mehat } 929d10b341a0ba46f108cb96e46691197d778cbc06San Mehat 939d10b341a0ba46f108cb96e46691197d778cbc06San Mehat @Override 949d10b341a0ba46f108cb96e46691197d778cbc06San Mehat public IBinder onBind(Intent intent) { 959d10b341a0ba46f108cb96e46691197d778cbc06San Mehat // ignore - nothing to do 969d10b341a0ba46f108cb96e46691197d778cbc06San Mehat return null; 979d10b341a0ba46f108cb96e46691197d778cbc06San Mehat } 989d10b341a0ba46f108cb96e46691197d778cbc06San Mehat 999d10b341a0ba46f108cb96e46691197d778cbc06San Mehat /** 1009d10b341a0ba46f108cb96e46691197d778cbc06San Mehat * registers location listeners 1019d10b341a0ba46f108cb96e46691197d778cbc06San Mehat * 1029d10b341a0ba46f108cb96e46691197d778cbc06San Mehat * @param intent 1039d10b341a0ba46f108cb96e46691197d778cbc06San Mehat * @param startId 1049d10b341a0ba46f108cb96e46691197d778cbc06San Mehat */ 1059d10b341a0ba46f108cb96e46691197d778cbc06San Mehat @Override 1069d10b341a0ba46f108cb96e46691197d778cbc06San Mehat public void onStart(Intent intent, int startId) { 1079d10b341a0ba46f108cb96e46691197d778cbc06San Mehat super.onStart(intent, startId); 1089d10b341a0ba46f108cb96e46691197d778cbc06San Mehat mNetworkLocation = null; 1099d10b341a0ba46f108cb96e46691197d778cbc06San Mehat 1109d10b341a0ba46f108cb96e46691197d778cbc06San Mehat initLocationListeners(); 1119d10b341a0ba46f108cb96e46691197d778cbc06San Mehat Toast.makeText(this, "Tracking service started", Toast.LENGTH_SHORT); 1129d10b341a0ba46f108cb96e46691197d778cbc06San Mehat } 1139d10b341a0ba46f108cb96e46691197d778cbc06San Mehat 1149d10b341a0ba46f108cb96e46691197d778cbc06San Mehat private synchronized void initLocationListeners() { 1159d10b341a0ba46f108cb96e46691197d778cbc06San Mehat mTrackerData = new TrackerDataHelper(this); 1169d10b341a0ba46f108cb96e46691197d778cbc06San Mehat LocationManager lm = getLocationManager(); 1179d10b341a0ba46f108cb96e46691197d778cbc06San Mehat 1189d10b341a0ba46f108cb96e46691197d778cbc06San Mehat mTrackedProviders = getTrackedProviders(); 1199d10b341a0ba46f108cb96e46691197d778cbc06San Mehat 1209d10b341a0ba46f108cb96e46691197d778cbc06San Mehat List<String> locationProviders = lm.getAllProviders(); 1219d10b341a0ba46f108cb96e46691197d778cbc06San Mehat mListeners = new ArrayList<LocationTrackingListener>( 1229d10b341a0ba46f108cb96e46691197d778cbc06San Mehat locationProviders.size()); 1239d10b341a0ba46f108cb96e46691197d778cbc06San Mehat 1249d10b341a0ba46f108cb96e46691197d778cbc06San Mehat long minUpdateTime = getLocationUpdateTime(); 1259d10b341a0ba46f108cb96e46691197d778cbc06San Mehat float minDistance = getLocationMinDistance(); 1269d10b341a0ba46f108cb96e46691197d778cbc06San Mehat 1279d10b341a0ba46f108cb96e46691197d778cbc06San Mehat for (String providerName : locationProviders) { 1289d10b341a0ba46f108cb96e46691197d778cbc06San Mehat if (mTrackedProviders.contains(providerName)) { 1299d10b341a0ba46f108cb96e46691197d778cbc06San Mehat Log.d(LOG_TAG, "Adding location listener for provider " + 1309d10b341a0ba46f108cb96e46691197d778cbc06San Mehat providerName); 1319d10b341a0ba46f108cb96e46691197d778cbc06San Mehat if (doDebugLogging()) { 1329d10b341a0ba46f108cb96e46691197d778cbc06San Mehat mTrackerData.writeEntry("init", String.format( 1339d10b341a0ba46f108cb96e46691197d778cbc06San Mehat "start listening to %s : %d ms; %f meters", 1349d10b341a0ba46f108cb96e46691197d778cbc06San Mehat providerName, minUpdateTime, minDistance)); 1359d10b341a0ba46f108cb96e46691197d778cbc06San Mehat } 1369d10b341a0ba46f108cb96e46691197d778cbc06San Mehat LocationTrackingListener listener = 1379d10b341a0ba46f108cb96e46691197d778cbc06San Mehat new LocationTrackingListener(); 1389d10b341a0ba46f108cb96e46691197d778cbc06San Mehat lm.requestLocationUpdates(providerName, minUpdateTime, 1399d10b341a0ba46f108cb96e46691197d778cbc06San Mehat minDistance, listener); 1409d10b341a0ba46f108cb96e46691197d778cbc06San Mehat mListeners.add(listener); 1419d10b341a0ba46f108cb96e46691197d778cbc06San Mehat } 1429d10b341a0ba46f108cb96e46691197d778cbc06San Mehat } 1439d10b341a0ba46f108cb96e46691197d778cbc06San Mehat mTelephonyManager = (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE); 1449d10b341a0ba46f108cb96e46691197d778cbc06San Mehat 1459d10b341a0ba46f108cb96e46691197d778cbc06San Mehat if (doDebugLogging()) { 1469d10b341a0ba46f108cb96e46691197d778cbc06San Mehat // register for cell location updates 1479d10b341a0ba46f108cb96e46691197d778cbc06San Mehat mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CELL_LOCATION); 1489d10b341a0ba46f108cb96e46691197d778cbc06San Mehat 1499d10b341a0ba46f108cb96e46691197d778cbc06San Mehat // Register for Network (Wifi or Mobile) updates 1509d10b341a0ba46f108cb96e46691197d778cbc06San Mehat mNetwork = new NetworkStateBroadcastReceiver(); 1519d10b341a0ba46f108cb96e46691197d778cbc06San Mehat IntentFilter mIntentFilter; 1529d10b341a0ba46f108cb96e46691197d778cbc06San Mehat mIntentFilter = new IntentFilter(); 1539d10b341a0ba46f108cb96e46691197d778cbc06San Mehat mIntentFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION); 1549d10b341a0ba46f108cb96e46691197d778cbc06San Mehat mIntentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); 1559d10b341a0ba46f108cb96e46691197d778cbc06San Mehat mIntentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); 1569d10b341a0ba46f108cb96e46691197d778cbc06San Mehat Log.d(LOG_TAG, "registering receiver"); 1579d10b341a0ba46f108cb96e46691197d778cbc06San Mehat registerReceiver(mNetwork, mIntentFilter); 1589d10b341a0ba46f108cb96e46691197d778cbc06San Mehat } 15918737845d3c6a60edd6f75ac441a1b3fed6d66a7San Mehat 1609d10b341a0ba46f108cb96e46691197d778cbc06San Mehat if (trackSignalStrength()) { 1619d10b341a0ba46f108cb96e46691197d778cbc06San Mehat mTelephonyManager.listen(mPhoneStateListener, 1629d10b341a0ba46f108cb96e46691197d778cbc06San Mehat PhoneStateListener.LISTEN_SIGNAL_STRENGTHS); 16318737845d3c6a60edd6f75ac441a1b3fed6d66a7San Mehat } 1649d10b341a0ba46f108cb96e46691197d778cbc06San Mehat 1659d10b341a0ba46f108cb96e46691197d778cbc06San Mehat // register for preference changes, so we can restart listeners on 1669d10b341a0ba46f108cb96e46691197d778cbc06San Mehat // pref changes 1679d10b341a0ba46f108cb96e46691197d778cbc06San Mehat mPrefListener = new PreferenceListener(); 1689d10b341a0ba46f108cb96e46691197d778cbc06San Mehat getPreferences().registerOnSharedPreferenceChangeListener(mPrefListener); 1699d10b341a0ba46f108cb96e46691197d778cbc06San Mehat } 1709d10b341a0ba46f108cb96e46691197d778cbc06San Mehat 1719d10b341a0ba46f108cb96e46691197d778cbc06San Mehat private Set<String> getTrackedProviders() { 1729d10b341a0ba46f108cb96e46691197d778cbc06San Mehat Set<String> providerSet = new HashSet<String>(); 1739d10b341a0ba46f108cb96e46691197d778cbc06San Mehat 1749d10b341a0ba46f108cb96e46691197d778cbc06San Mehat if (trackGPS()) { 1759d10b341a0ba46f108cb96e46691197d778cbc06San Mehat providerSet.add(LocationManager.GPS_PROVIDER); 1769d10b341a0ba46f108cb96e46691197d778cbc06San Mehat } 1779d10b341a0ba46f108cb96e46691197d778cbc06San Mehat if (trackNetwork()) { 1789d10b341a0ba46f108cb96e46691197d778cbc06San Mehat providerSet.add(LocationManager.NETWORK_PROVIDER); 1799d10b341a0ba46f108cb96e46691197d778cbc06San Mehat } 1809d10b341a0ba46f108cb96e46691197d778cbc06San Mehat return providerSet; 1819d10b341a0ba46f108cb96e46691197d778cbc06San Mehat } 1829d10b341a0ba46f108cb96e46691197d778cbc06San Mehat 1839d10b341a0ba46f108cb96e46691197d778cbc06San Mehat private SharedPreferences getPreferences() { 1849d10b341a0ba46f108cb96e46691197d778cbc06San Mehat return PreferenceManager.getDefaultSharedPreferences(this); 1859d10b341a0ba46f108cb96e46691197d778cbc06San Mehat } 1869d10b341a0ba46f108cb96e46691197d778cbc06San Mehat 1879d10b341a0ba46f108cb96e46691197d778cbc06San Mehat private boolean trackNetwork() { 1889d10b341a0ba46f108cb96e46691197d778cbc06San Mehat return getPreferences().getBoolean(NETWORK_PREF, true); 1899d10b341a0ba46f108cb96e46691197d778cbc06San Mehat } 1909d10b341a0ba46f108cb96e46691197d778cbc06San Mehat 1919d10b341a0ba46f108cb96e46691197d778cbc06San Mehat private boolean trackGPS() { 1929d10b341a0ba46f108cb96e46691197d778cbc06San Mehat return getPreferences().getBoolean(GPS_PREF, true); 1939d10b341a0ba46f108cb96e46691197d778cbc06San Mehat } 1949d10b341a0ba46f108cb96e46691197d778cbc06San Mehat 1959d10b341a0ba46f108cb96e46691197d778cbc06San Mehat private boolean doDebugLogging() { 1969d10b341a0ba46f108cb96e46691197d778cbc06San Mehat return getPreferences().getBoolean(DEBUG_PREF, false); 1979d10b341a0ba46f108cb96e46691197d778cbc06San Mehat } 1989d10b341a0ba46f108cb96e46691197d778cbc06San Mehat 1999d10b341a0ba46f108cb96e46691197d778cbc06San Mehat private boolean trackSignalStrength() { 2009d10b341a0ba46f108cb96e46691197d778cbc06San Mehat return getPreferences().getBoolean(SIGNAL_PREF, false); 2019d10b341a0ba46f108cb96e46691197d778cbc06San Mehat } 2029d10b341a0ba46f108cb96e46691197d778cbc06San Mehat 2039d10b341a0ba46f108cb96e46691197d778cbc06San Mehat private float getLocationMinDistance() { 2049d10b341a0ba46f108cb96e46691197d778cbc06San Mehat try { 2059d10b341a0ba46f108cb96e46691197d778cbc06San Mehat String disString = getPreferences().getString(MIN_DIS_PREF, "0"); 2069d10b341a0ba46f108cb96e46691197d778cbc06San Mehat return Float.parseFloat(disString); 2079d10b341a0ba46f108cb96e46691197d778cbc06San Mehat } 2089d10b341a0ba46f108cb96e46691197d778cbc06San Mehat catch (NumberFormatException e) { 2099d10b341a0ba46f108cb96e46691197d778cbc06San Mehat Log.e(LOG_TAG, "Invalid preference for location min distance", e); 2109d10b341a0ba46f108cb96e46691197d778cbc06San Mehat } 2119d10b341a0ba46f108cb96e46691197d778cbc06San Mehat return 0; 2129d10b341a0ba46f108cb96e46691197d778cbc06San Mehat } 2139d10b341a0ba46f108cb96e46691197d778cbc06San Mehat 2149d10b341a0ba46f108cb96e46691197d778cbc06San Mehat private long getLocationUpdateTime() { 2159d10b341a0ba46f108cb96e46691197d778cbc06San Mehat try { 2169d10b341a0ba46f108cb96e46691197d778cbc06San Mehat String timeString = getPreferences().getString(MIN_TIME_PREF, "0"); 2179d10b341a0ba46f108cb96e46691197d778cbc06San Mehat long secondsTime = Long.valueOf(timeString); 2189d10b341a0ba46f108cb96e46691197d778cbc06San Mehat return secondsTime * 1000; 2199d10b341a0ba46f108cb96e46691197d778cbc06San Mehat } 2209d10b341a0ba46f108cb96e46691197d778cbc06San Mehat catch (NumberFormatException e) { 2219d10b341a0ba46f108cb96e46691197d778cbc06San Mehat Log.e(LOG_TAG, "Invalid preference for location min time", e); 2229d10b341a0ba46f108cb96e46691197d778cbc06San Mehat } 2239d10b341a0ba46f108cb96e46691197d778cbc06San Mehat return 0; 2249d10b341a0ba46f108cb96e46691197d778cbc06San Mehat } 2259d10b341a0ba46f108cb96e46691197d778cbc06San Mehat 2269d10b341a0ba46f108cb96e46691197d778cbc06San Mehat /** 2279d10b341a0ba46f108cb96e46691197d778cbc06San Mehat * Shuts down this service 2289d10b341a0ba46f108cb96e46691197d778cbc06San Mehat */ 2299d10b341a0ba46f108cb96e46691197d778cbc06San Mehat @Override 2309d10b341a0ba46f108cb96e46691197d778cbc06San Mehat public void onDestroy() { 231 super.onDestroy(); 232 Log.d(LOG_TAG, "Removing location listeners"); 233 stopListeners(); 234 Toast.makeText(this, "Tracking service stopped", Toast.LENGTH_SHORT); 235 } 236 237 /** 238 * De-registers all location listeners, closes persistent storage 239 */ 240 protected synchronized void stopListeners() { 241 LocationManager lm = getLocationManager(); 242 if (mListeners != null) { 243 for (LocationTrackingListener listener : mListeners) { 244 lm.removeUpdates(listener); 245 } 246 mListeners.clear(); 247 } 248 mListeners = null; 249 250 // stop cell state listener 251 if (mTelephonyManager != null) { 252 mTelephonyManager.listen(mPhoneStateListener, 0); 253 } 254 255 // stop network/wifi listener 256 if (mNetwork != null) { 257 unregisterReceiver(mNetwork); 258 } 259 mNetwork = null; 260 261 mTrackerData = null; 262 if (mPrefListener != null) { 263 getPreferences().unregisterOnSharedPreferenceChangeListener(mPrefListener); 264 mPrefListener = null; 265 } 266 } 267 268 private LocationManager getLocationManager() { 269 return (LocationManager) getSystemService(Context.LOCATION_SERVICE); 270 } 271 272 /** 273 * Determine the current distance from given location to the last 274 * approximated network location 275 * 276 * @param location - new location 277 * 278 * @return float distance in meters 279 */ 280 private synchronized float getDistanceFromNetwork(Location location) { 281 float value = 0; 282 if (mNetworkLocation != null) { 283 value = location.distanceTo(mNetworkLocation); 284 } 285 if (LocationManager.NETWORK_PROVIDER.equals(location.getProvider())) { 286 mNetworkLocation = location; 287 } 288 return value; 289 } 290 291 private class LocationTrackingListener implements LocationListener { 292 293 /** 294 * Writes details of location update to tracking file, including 295 * recording the distance between this location update and the last 296 * network location update 297 * 298 * @param location - new location 299 */ 300 public void onLocationChanged(Location location) { 301 if (location == null) { 302 return; 303 } 304 float distance = getDistanceFromNetwork(location); 305 mTrackerData.writeEntry(location, distance); 306 } 307 308 /** 309 * Writes update to tracking file 310 * 311 * @param provider - name of disabled provider 312 */ 313 public void onProviderDisabled(String provider) { 314 if (doDebugLogging()) { 315 mTrackerData.writeEntry(provider, "provider disabled"); 316 } 317 } 318 319 /** 320 * Writes update to tracking file 321 * 322 * @param provider - name of enabled provider 323 */ 324 public void onProviderEnabled(String provider) { 325 if (doDebugLogging()) { 326 mTrackerData.writeEntry(provider, "provider enabled"); 327 } 328 } 329 330 /** 331 * Writes update to tracking file 332 * 333 * @param provider - name of provider whose status changed 334 * @param status - new status 335 * @param extras - optional set of extra status messages 336 */ 337 public void onStatusChanged(String provider, int status, Bundle extras) { 338 if (doDebugLogging()) { 339 mTrackerData.writeEntry(provider, "status change: " + status); 340 } 341 } 342 } 343 344 PhoneStateListener mPhoneStateListener = new PhoneStateListener() { 345 @Override 346 public void onCellLocationChanged(CellLocation location) { 347 try { 348 if (location instanceof GsmCellLocation) { 349 GsmCellLocation cellLocation = (GsmCellLocation)location; 350 String updateMsg = "cid=" + cellLocation.getCid() + 351 ", lac=" + cellLocation.getLac(); 352 mTrackerData.writeEntry(CELL_PROVIDER_TAG, updateMsg); 353 } else if (location instanceof CdmaCellLocation) { 354 CdmaCellLocation cellLocation = (CdmaCellLocation)location; 355 String updateMsg = "BID=" + cellLocation.getBaseStationId() + 356 ", SID=" + cellLocation.getSystemId() + 357 ", NID=" + cellLocation.getNetworkId() + 358 ", lat=" + cellLocation.getBaseStationLatitude() + 359 ", long=" + cellLocation.getBaseStationLongitude() + 360 ", SID=" + cellLocation.getSystemId() + 361 ", NID=" + cellLocation.getNetworkId(); 362 mTrackerData.writeEntry(CELL_PROVIDER_TAG, updateMsg); 363 } 364 } catch (Exception e) { 365 Log.e(LOG_TAG, "Exception in CellStateHandler.handleMessage:", e); 366 } 367 } 368 369 public void onSignalStrengthsChanged(SignalStrength signalStrength) { 370 if (mTelephonyManager.getPhoneType() == TelephonyManager.PHONE_TYPE_CDMA) { 371 String updateMsg = "cdma dBM=" + signalStrength.getCdmaDbm(); 372 mTrackerData.writeEntry(SIGNAL_PROVIDER_TAG, updateMsg); 373 } else if (mTelephonyManager.getPhoneType() == TelephonyManager.PHONE_TYPE_GSM) { 374 String updateMsg = "gsm signal=" + signalStrength.getGsmSignalStrength(); 375 mTrackerData.writeEntry(SIGNAL_PROVIDER_TAG, updateMsg); 376 } 377 } 378 }; 379 380 /** 381 * Listener + recorder for mobile or wifi updates 382 */ 383 private class NetworkStateBroadcastReceiver extends BroadcastReceiver { 384 @Override 385 public void onReceive(Context context, Intent intent) { 386 String action = intent.getAction(); 387 388 if (action.equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) { 389 WifiManager wifiManager = 390 (WifiManager) context.getSystemService(Context.WIFI_SERVICE); 391 List<ScanResult> wifiScanResults = wifiManager.getScanResults(); 392 String updateMsg = "num scan results=" + 393 (wifiScanResults == null ? "0" : wifiScanResults.size()); 394 mTrackerData.writeEntry(WIFI_PROVIDER_TAG, updateMsg); 395 396 } else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) { 397 String updateMsg; 398 boolean noConnectivity = 399 intent.getBooleanExtra( 400 ConnectivityManager.EXTRA_NO_CONNECTIVITY, false); 401 if (noConnectivity) { 402 updateMsg = "no connectivity"; 403 } 404 else { 405 updateMsg = "connection available"; 406 } 407 mTrackerData.writeEntry(DATA_CONN_PROVIDER_TAG, updateMsg); 408 409 } else if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) { 410 int state = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, 411 WifiManager.WIFI_STATE_UNKNOWN); 412 413 String stateString = "unknown"; 414 switch (state) { 415 case WifiManager.WIFI_STATE_DISABLED: 416 stateString = "disabled"; 417 break; 418 case WifiManager.WIFI_STATE_DISABLING: 419 stateString = "disabling"; 420 break; 421 case WifiManager.WIFI_STATE_ENABLED: 422 stateString = "enabled"; 423 break; 424 case WifiManager.WIFI_STATE_ENABLING: 425 stateString = "enabling"; 426 break; 427 } 428 mTrackerData.writeEntry(WIFI_PROVIDER_TAG, 429 "state = " + stateString); 430 } 431 } 432 } 433 434 private class PreferenceListener implements OnSharedPreferenceChangeListener { 435 436 public void onSharedPreferenceChanged( 437 SharedPreferences sharedPreferences, String key) { 438 Log.d(LOG_TAG, "restarting listeners due to preference change"); 439 synchronized (TrackerService.this) { 440 stopListeners(); 441 initLocationListeners(); 442 } 443 } 444 } 445} 446