/*
* 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;
import android.os.Bundle;
import android.preference.PreferenceManager;
import ca.rmen.android.networkmonitor.Constants;
import ca.rmen.android.networkmonitor.app.prefs.NetMonPreferences;
import ca.rmen.android.networkmonitor.provider.NetMonColumns;
import ca.rmen.android.networkmonitor.util.Log;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GoogleApiAvailability;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.GoogleApiClient.ConnectionCallbacks;
import com.google.android.gms.common.api.GoogleApiClient.OnConnectionFailedListener;
import com.google.android.gms.location.LocationServices;
/**
* Retrieves the device's location, using Google Play Services if it is available, or one of the location providers otherwise.
*/
public class DeviceLocationDataSource implements NetMonDataSource {
private static final String TAG = Constants.TAG + DeviceLocationDataSource.class.getSimpleName();
private NetMonDataSource mDeviceLocationDataSourceImpl;
private GoogleApiClient mGoogleApiClient;
private Context mContext;
public DeviceLocationDataSource() {}
@Override
public void onCreate(Context context) {
Log.v(TAG, "onCreate");
mContext = context;
mGoogleApiClient = new GoogleApiClient.Builder(mContext)
.addConnectionCallbacks(mConnectionCallbacks)
.addOnConnectionFailedListener(mConnectionFailedListener)
.addApi(LocationServices.API)
.build();
mGoogleApiClient.connect();
PreferenceManager.getDefaultSharedPreferences(mContext).registerOnSharedPreferenceChangeListener(mSharedPreferenceChangeListener);
}
/**
* @return the last location the device recorded in a ContentValues with keys {@link NetMonColumns#DEVICE_LATITUDE} and
* {@link NetMonColumns#DEVICE_LONGITUDE}. Tries to use Google Play Services if available. Otherwise falls back
* to the most recently retrieved location among all the providers.
*/
@Override
public ContentValues getContentValues() {
Log.v(TAG, "getContentValues");
if (mDeviceLocationDataSourceImpl != null) return mDeviceLocationDataSourceImpl.getContentValues();
else {
Log.w(TAG, "No data source available to get location");
return new ContentValues();
}
}
@Override
public void onDestroy() {
Log.v(TAG, "onDestroy");
mGoogleApiClient.disconnect();
if (mDeviceLocationDataSourceImpl != null) mDeviceLocationDataSourceImpl.onDestroy();
PreferenceManager.getDefaultSharedPreferences(mContext).unregisterOnSharedPreferenceChangeListener(mSharedPreferenceChangeListener);
}
/**
* Choose the {@link GmsDeviceLocationDataSource} if Google Play Services is available. Otherwise choose {@link StandardDeviceLocationDataSource}.
*/
private void selectLocationDataSource() {
Log.v(TAG, "selectLocationDataSource");
if (mDeviceLocationDataSourceImpl != null) mDeviceLocationDataSourceImpl.onDestroy();
mDeviceLocationDataSourceImpl = null;
NetMonPreferences.LocationFetchingStrategy strategy = NetMonPreferences.getInstance(mContext).getLocationFetchingStrategy();
if (strategy == NetMonPreferences.LocationFetchingStrategy.HIGH_ACCURACY_GMS
|| strategy == NetMonPreferences.LocationFetchingStrategy.SAVE_POWER_GMS) {
GoogleApiAvailability api = GoogleApiAvailability.getInstance();
int playServicesAvailable = api.isGooglePlayServicesAvailable(mContext);
if (playServicesAvailable == ConnectionResult.SUCCESS) {
mDeviceLocationDataSourceImpl = new GmsDeviceLocationDataSource(mGoogleApiClient);
} else {
NetMonPreferences.getInstance(mContext).forceFossLocationFetchingStrategy();
}
}
if (mDeviceLocationDataSourceImpl == null) {
mDeviceLocationDataSourceImpl = new StandardDeviceLocationDataSource();
}
Log.v(TAG, "selectLocationDataSource: using " + mDeviceLocationDataSourceImpl);
mDeviceLocationDataSourceImpl.onCreate(mContext);
}
private final ConnectionCallbacks mConnectionCallbacks = new ConnectionCallbacks() {
@Override
public void onConnected(Bundle bundle) {
Log.v(TAG, "onConnected: " + bundle);
selectLocationDataSource();
}
@Override
public void onConnectionSuspended(int i) {
Log.v(TAG, "onConnectionSuspended: " + i);
mGoogleApiClient.connect();
}
};
private final OnConnectionFailedListener mConnectionFailedListener = result -> {
Log.v(TAG, "onConnectionFailed: " + result);
selectLocationDataSource();
};
private final SharedPreferences.OnSharedPreferenceChangeListener mSharedPreferenceChangeListener
= (sharedPreferences, key) -> {
if(NetMonPreferences.PREF_LOCATION_FETCHING_STRATEGY.equals(key)) {
selectLocationDataSource();
}
};
}