/* * This source is part of the * _____ ___ ____ * __ / / _ \/ _ | / __/___ _______ _ * / // / , _/ __ |/ _/_/ _ \/ __/ _ `/ * \___/_/|_/_/ |_/_/ (_)___/_/ \_, / * /___/ * repository. * * Copyright (C) 2014-2015 Carmen Alvarez (c@rmen.ca) * * 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 ca.rmen.android.networkmonitor.app.service.datasources; import android.content.ContentValues; import android.content.Context; import android.content.SharedPreferences.OnSharedPreferenceChangeListener; import android.location.Location; import android.location.LocationListener; import android.location.LocationManager; import android.os.Bundle; import android.preference.PreferenceManager; import java.util.List; import ca.rmen.android.networkmonitor.Constants; import ca.rmen.android.networkmonitor.app.prefs.NetMonPreferences; import ca.rmen.android.networkmonitor.app.prefs.NetMonPreferences.LocationFetchingStrategy; import ca.rmen.android.networkmonitor.provider.NetMonColumns; import ca.rmen.android.networkmonitor.util.Log; import ca.rmen.android.networkmonitor.util.PermissionUtil; /** * Retrieves the device's location, using the most recent Location retrieved among all of the available the location providers. */ public class StandardDeviceLocationDataSource implements NetMonDataSource { private static final String TAG = Constants.TAG + StandardDeviceLocationDataSource.class.getSimpleName(); private LocationManager mLocationManager; private volatile Location mMostRecentLocation; private Context mContext; StandardDeviceLocationDataSource() {} @Override public void onCreate(Context context) { Log.v(TAG, "onCreate"); mContext = context; mLocationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE); PreferenceManager.getDefaultSharedPreferences(context).registerOnSharedPreferenceChangeListener(mPreferenceListener); registerLocationListener(); } /** * @return the last location the device recorded in a ContentValues with keys {@link NetMonColumns#DEVICE_LATITUDE} and * Uses the most recently retrieved location among all the providers. */ @Override public ContentValues getContentValues() { Log.v(TAG, "getContentValues"); ContentValues values = new ContentValues(3); if (!PermissionUtil.hasLocationPermission(mContext)) { Log.v(TAG, "No location permission"); return values; } Location mostRecentLocation = null; List<String> providers = mLocationManager.getProviders(true); for (String provider : providers) { @SuppressWarnings("MissingPermission") Location location = mLocationManager.getLastKnownLocation(provider); Log.v(TAG, "Location for provider " + provider + ": " + location); if (isBetter(mostRecentLocation, location)) mostRecentLocation = location; } Log.v(TAG, "Most recent location: " + mostRecentLocation); if (mostRecentLocation != null) { values.put(NetMonColumns.DEVICE_LATITUDE, mostRecentLocation.getLatitude()); values.put(NetMonColumns.DEVICE_LONGITUDE, mostRecentLocation.getLongitude()); values.put(NetMonColumns.DEVICE_POSITION_ACCURACY, mostRecentLocation.getAccuracy()); values.put(NetMonColumns.DEVICE_SPEED, mostRecentLocation.getSpeed()); } mMostRecentLocation = mostRecentLocation; return values; } @Override @SuppressWarnings("MissingPermission") public void onDestroy() { Log.v(TAG, "onDestroy"); PreferenceManager.getDefaultSharedPreferences(mContext).unregisterOnSharedPreferenceChangeListener(mPreferenceListener); if (PermissionUtil.hasLocationPermission(mContext)) { mLocationManager.removeUpdates(mLocationListener); } } @SuppressWarnings("MissingPermission") private void registerLocationListener() { LocationFetchingStrategy locationFetchingStrategy = NetMonPreferences.getInstance(mContext).getLocationFetchingStrategy(); Log.v(TAG, "registerLocationListener: strategy = " + locationFetchingStrategy); if (!PermissionUtil.hasLocationPermission(mContext)) { Log.d(TAG, "No location permissions"); return; } mLocationManager.removeUpdates(mLocationListener); if (locationFetchingStrategy == LocationFetchingStrategy.HIGH_ACCURACY) { int pollingFrequency = NetMonPreferences.getInstance(mContext).getUpdateInterval(); if (pollingFrequency < NetMonPreferences.PREF_MIN_POLLING_INTERVAL) pollingFrequency = NetMonPreferences.PREF_MIN_POLLING_INTERVAL; List<String> providers = mLocationManager.getProviders(true); for (String provider : providers) { mLocationManager.requestLocationUpdates(provider, pollingFrequency, 0f, mLocationListener); Log.v(TAG, "registered location listener for provider " + provider); } } } /** * @return true if location1 is better than location2. * For now, we just use the most recent location. */ private boolean isBetter(Location location1, Location location2) { if (location1 == null && location2 == null) return false; if (location1 == null) return true; //noinspection SimplifiableIfStatement if (location2 == null) return false; return location2.getTime() > location1.getTime(); } private final LocationListener mLocationListener = new LocationListener() { @Override public void onStatusChanged(String provider, int status, Bundle extras) { extras.isEmpty(); Log.v(TAG, "onStatusChanged: provider = " + provider + ", status = " + status + ", extras = " + extras); } @Override public void onProviderEnabled(String provider) { Log.v(TAG, "onProviderEnabled: " + provider); registerLocationListener(); } @Override public void onProviderDisabled(String provider) { Log.v(TAG, "onProviderDisabled: " + provider); registerLocationListener(); } @Override public void onLocationChanged(Location location) { Log.v(TAG, "onLocationChanged, location = " + location); if (isBetter(mMostRecentLocation, location)) mMostRecentLocation = location; } }; private final OnSharedPreferenceChangeListener mPreferenceListener = (sharedPreferences, key) -> { Log.v(TAG, "onSharedPreferenceChanged: key = " + key); if (NetMonPreferences.PREF_LOCATION_FETCHING_STRATEGY.equals(key) || NetMonPreferences.PREF_UPDATE_INTERVAL.equals(key)) { registerLocationListener(); } }; }