diff options
Diffstat (limited to 'tests/LocationTracker/src/com/google/android/locationtracker/TrackerService.java')
-rw-r--r-- | tests/LocationTracker/src/com/google/android/locationtracker/TrackerService.java | 445 |
1 files changed, 445 insertions, 0 deletions
diff --git a/tests/LocationTracker/src/com/google/android/locationtracker/TrackerService.java b/tests/LocationTracker/src/com/google/android/locationtracker/TrackerService.java new file mode 100644 index 0000000..e7fdc494 --- /dev/null +++ b/tests/LocationTracker/src/com/google/android/locationtracker/TrackerService.java @@ -0,0 +1,445 @@ +/* + * Copyright (C) 2008 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.android.locationtracker; + +import com.google.android.locationtracker.data.TrackerDataHelper; + +import android.app.Service; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.SharedPreferences; +import android.content.SharedPreferences.OnSharedPreferenceChangeListener; +import android.location.Location; +import android.location.LocationListener; +import android.location.LocationManager; +import android.net.ConnectivityManager; +import android.net.wifi.ScanResult; +import android.net.wifi.WifiManager; +import android.os.Bundle; +import android.os.IBinder; +import android.preference.PreferenceManager; +import android.telephony.CellLocation; +import android.telephony.PhoneStateListener; +import android.telephony.SignalStrength; +import android.telephony.TelephonyManager; +import android.telephony.cdma.CdmaCellLocation; +import android.telephony.gsm.GsmCellLocation; +import android.util.Log; +import android.widget.Toast; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * Location Tracking service + * + * Records location updates for all registered location providers, and cell + * location updates + */ +public class TrackerService extends Service { + + private List<LocationTrackingListener> mListeners; + + private static final String LOG_TAG = TrackerActivity.LOG_TAG; + + // controls which location providers to track + private Set<String> mTrackedProviders; + + private TrackerDataHelper mTrackerData; + + private TelephonyManager mTelephonyManager; + private Location mNetworkLocation; + + // Handlers and Receivers for phone and network state + private NetworkStateBroadcastReceiver mNetwork; + private static final String CELL_PROVIDER_TAG = "cell"; + // signal strength updates + private static final String SIGNAL_PROVIDER_TAG = "signal"; + private static final String WIFI_PROVIDER_TAG = "wifi"; + // tracking tag for data connectivity issues + private static final String DATA_CONN_PROVIDER_TAG = "data"; + + // preference constants + private static final String MIN_TIME_PREF = "mintime_preference"; + private static final String MIN_DIS_PREF = "mindistance_preference"; + private static final String GPS_PREF = "gps_preference"; + private static final String NETWORK_PREF = "network_preference"; + private static final String SIGNAL_PREF = "signal_preference"; + private static final String DEBUG_PREF = "advanced_log_preference"; + + private PreferenceListener mPrefListener; + + public TrackerService() { + } + + @Override + public IBinder onBind(Intent intent) { + // ignore - nothing to do + return null; + } + + /** + * registers location listeners + * + * @param intent + * @param startId + */ + @Override + public void onStart(Intent intent, int startId) { + super.onStart(intent, startId); + mNetworkLocation = null; + + initLocationListeners(); + Toast.makeText(this, "Tracking service started", Toast.LENGTH_SHORT); + } + + private synchronized void initLocationListeners() { + mTrackerData = new TrackerDataHelper(this); + LocationManager lm = getLocationManager(); + + mTrackedProviders = getTrackedProviders(); + + List<String> locationProviders = lm.getAllProviders(); + mListeners = new ArrayList<LocationTrackingListener>( + locationProviders.size()); + + long minUpdateTime = getLocationUpdateTime(); + float minDistance = getLocationMinDistance(); + + for (String providerName : locationProviders) { + if (mTrackedProviders.contains(providerName)) { + Log.d(LOG_TAG, "Adding location listener for provider " + + providerName); + if (doDebugLogging()) { + mTrackerData.writeEntry("init", String.format( + "start listening to %s : %d ms; %f meters", + providerName, minUpdateTime, minDistance)); + } + LocationTrackingListener listener = + new LocationTrackingListener(); + lm.requestLocationUpdates(providerName, minUpdateTime, + minDistance, listener); + mListeners.add(listener); + } + } + mTelephonyManager = (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE); + + if (doDebugLogging()) { + // register for cell location updates + mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CELL_LOCATION); + + // Register for Network (Wifi or Mobile) updates + mNetwork = new NetworkStateBroadcastReceiver(); + IntentFilter mIntentFilter; + mIntentFilter = new IntentFilter(); + mIntentFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION); + mIntentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); + mIntentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); + Log.d(LOG_TAG, "registering receiver"); + registerReceiver(mNetwork, mIntentFilter); + } + + if (trackSignalStrength()) { + mTelephonyManager.listen(mPhoneStateListener, + PhoneStateListener.LISTEN_SIGNAL_STRENGTHS); + } + + // register for preference changes, so we can restart listeners on + // pref changes + mPrefListener = new PreferenceListener(); + getPreferences().registerOnSharedPreferenceChangeListener(mPrefListener); + } + + private Set<String> getTrackedProviders() { + Set<String> providerSet = new HashSet<String>(); + + if (trackGPS()) { + providerSet.add(LocationManager.GPS_PROVIDER); + } + if (trackNetwork()) { + providerSet.add(LocationManager.NETWORK_PROVIDER); + } + return providerSet; + } + + private SharedPreferences getPreferences() { + return PreferenceManager.getDefaultSharedPreferences(this); + } + + private boolean trackNetwork() { + return getPreferences().getBoolean(NETWORK_PREF, true); + } + + private boolean trackGPS() { + return getPreferences().getBoolean(GPS_PREF, true); + } + + private boolean doDebugLogging() { + return getPreferences().getBoolean(DEBUG_PREF, true); + } + + private boolean trackSignalStrength() { + return getPreferences().getBoolean(SIGNAL_PREF, true); + } + + private float getLocationMinDistance() { + try { + String disString = getPreferences().getString(MIN_DIS_PREF, "0"); + return Float.parseFloat(disString); + } + catch (NumberFormatException e) { + Log.e(LOG_TAG, "Invalid preference for location min distance", e); + } + return 0; + } + + private long getLocationUpdateTime() { + try { + String timeString = getPreferences().getString(MIN_TIME_PREF, "0"); + long secondsTime = Long.valueOf(timeString); + return secondsTime * 1000; + } + catch (NumberFormatException e) { + Log.e(LOG_TAG, "Invalid preference for location min time", e); + } + return 0; + } + + /** + * Shuts down this service + */ + @Override + public void onDestroy() { + super.onDestroy(); + Log.d(LOG_TAG, "Removing location listeners"); + stopListeners(); + Toast.makeText(this, "Tracking service stopped", Toast.LENGTH_SHORT); + } + + /** + * De-registers all location listeners, closes persistent storage + */ + protected synchronized void stopListeners() { + LocationManager lm = getLocationManager(); + if (mListeners != null) { + for (LocationTrackingListener listener : mListeners) { + lm.removeUpdates(listener); + } + mListeners.clear(); + } + mListeners = null; + + // stop cell state listener + if (mTelephonyManager != null) { + mTelephonyManager.listen(mPhoneStateListener, 0); + } + + // stop network/wifi listener + if (mNetwork != null) { + unregisterReceiver(mNetwork); + } + mNetwork = null; + + mTrackerData = null; + if (mPrefListener != null) { + getPreferences().unregisterOnSharedPreferenceChangeListener(mPrefListener); + mPrefListener = null; + } + } + + private LocationManager getLocationManager() { + return (LocationManager) getSystemService(Context.LOCATION_SERVICE); + } + + /** + * Determine the current distance from given location to the last + * approximated network location + * + * @param location - new location + * + * @return float distance in meters + */ + private synchronized float getDistanceFromNetwork(Location location) { + float value = 0; + if (mNetworkLocation != null) { + value = location.distanceTo(mNetworkLocation); + } + if (LocationManager.NETWORK_PROVIDER.equals(location.getProvider())) { + mNetworkLocation = location; + } + return value; + } + + private class LocationTrackingListener implements LocationListener { + + /** + * Writes details of location update to tracking file, including + * recording the distance between this location update and the last + * network location update + * + * @param location - new location + */ + public void onLocationChanged(Location location) { + if (location == null) { + return; + } + float distance = getDistanceFromNetwork(location); + mTrackerData.writeEntry(location, distance); + } + + /** + * Writes update to tracking file + * + * @param provider - name of disabled provider + */ + public void onProviderDisabled(String provider) { + if (doDebugLogging()) { + mTrackerData.writeEntry(provider, "provider disabled"); + } + } + + /** + * Writes update to tracking file + * + * @param provider - name of enabled provider + */ + public void onProviderEnabled(String provider) { + if (doDebugLogging()) { + mTrackerData.writeEntry(provider, "provider enabled"); + } + } + + /** + * Writes update to tracking file + * + * @param provider - name of provider whose status changed + * @param status - new status + * @param extras - optional set of extra status messages + */ + public void onStatusChanged(String provider, int status, Bundle extras) { + if (doDebugLogging()) { + mTrackerData.writeEntry(provider, "status change: " + status); + } + } + } + + PhoneStateListener mPhoneStateListener = new PhoneStateListener() { + @Override + public void onCellLocationChanged(CellLocation location) { + try { + if (location instanceof GsmCellLocation) { + GsmCellLocation cellLocation = (GsmCellLocation)location; + String updateMsg = "cid=" + cellLocation.getCid() + + ", lac=" + cellLocation.getLac(); + mTrackerData.writeEntry(CELL_PROVIDER_TAG, updateMsg); + } else if (location instanceof CdmaCellLocation) { + CdmaCellLocation cellLocation = (CdmaCellLocation)location; + String updateMsg = "BID=" + cellLocation.getBaseStationId() + + ", SID=" + cellLocation.getSystemId() + + ", NID=" + cellLocation.getNetworkId() + + ", lat=" + cellLocation.getBaseStationLatitude() + + ", long=" + cellLocation.getBaseStationLongitude() + + ", SID=" + cellLocation.getSystemId() + + ", NID=" + cellLocation.getNetworkId(); + mTrackerData.writeEntry(CELL_PROVIDER_TAG, updateMsg); + } + } catch (Exception e) { + Log.e(LOG_TAG, "Exception in CellStateHandler.handleMessage:", e); + } + } + + public void onSignalStrengthsChanged(SignalStrength signalStrength) { + if (mTelephonyManager.getPhoneType() == TelephonyManager.PHONE_TYPE_CDMA) { + String updateMsg = "cdma dBM=" + signalStrength.getCdmaDbm(); + mTrackerData.writeEntry(SIGNAL_PROVIDER_TAG, updateMsg); + } else if (mTelephonyManager.getPhoneType() == TelephonyManager.PHONE_TYPE_GSM) { + String updateMsg = "gsm signal=" + signalStrength.getGsmSignalStrength(); + mTrackerData.writeEntry(SIGNAL_PROVIDER_TAG, updateMsg); + } + } + }; + + /** + * Listener + recorder for mobile or wifi updates + */ + private class NetworkStateBroadcastReceiver extends BroadcastReceiver { + @Override + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + + if (action.equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) { + WifiManager wifiManager = + (WifiManager) context.getSystemService(Context.WIFI_SERVICE); + List<ScanResult> wifiScanResults = wifiManager.getScanResults(); + String updateMsg = "num scan results=" + + (wifiScanResults == null ? "0" : wifiScanResults.size()); + mTrackerData.writeEntry(WIFI_PROVIDER_TAG, updateMsg); + + } else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) { + String updateMsg; + boolean noConnectivity = + intent.getBooleanExtra( + ConnectivityManager.EXTRA_NO_CONNECTIVITY, false); + if (noConnectivity) { + updateMsg = "no connectivity"; + } + else { + updateMsg = "connection available"; + } + mTrackerData.writeEntry(DATA_CONN_PROVIDER_TAG, updateMsg); + + } else if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) { + int state = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, + WifiManager.WIFI_STATE_UNKNOWN); + + String stateString = "unknown"; + switch (state) { + case WifiManager.WIFI_STATE_DISABLED: + stateString = "disabled"; + break; + case WifiManager.WIFI_STATE_DISABLING: + stateString = "disabling"; + break; + case WifiManager.WIFI_STATE_ENABLED: + stateString = "enabled"; + break; + case WifiManager.WIFI_STATE_ENABLING: + stateString = "enabling"; + break; + } + mTrackerData.writeEntry(WIFI_PROVIDER_TAG, + "state = " + stateString); + } + } + } + + private class PreferenceListener implements OnSharedPreferenceChangeListener { + + public void onSharedPreferenceChanged( + SharedPreferences sharedPreferences, String key) { + Log.d(LOG_TAG, "restarting listeners due to preference change"); + synchronized (TrackerService.this) { + stopListeners(); + initLocationListeners(); + } + } + } +} |