/**
* Copyright (C) 2013 Romain Guefveneu.
*
* This file is part of naonedbus.
*
* Naonedbus is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Naonedbus is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.naonedbus.provider.impl;
import java.io.IOException;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import net.naonedbus.BuildConfig;
import android.content.Context;
import android.location.Address;
import android.location.Geocoder;
import android.location.Location;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesClient;
import com.google.android.gms.location.LocationClient;
import com.google.android.gms.location.LocationRequest;
public class NaoLocationManager implements GooglePlayServicesClient.ConnectionCallbacks,
GooglePlayServicesClient.OnConnectionFailedListener, com.google.android.gms.location.LocationListener {
private static final String LOG_TAG = "NaoLocationManager";
private static final boolean DBG = BuildConfig.DEBUG;
private static final int TIMEOUT = 10000;
public static interface NaoLocationListener {
void onConnecting();
void onLocationChanged(Location location);
void onDisconnected();
void onLocationTimeout();
}
/** New Google API. */
private LocationClient mLocationClient;
/** Android API, to know if location service is enabled. */
private LocationManager mLocationManager;
/** Geo coder. */
private final Geocoder mGeoCoder;
/** Location listeners. */
private Set<NaoLocationListener> mListenerList;
/** Current service status. */
private boolean mServiceEnabled;
/** Last location. */
private Location mLastLocation;
/** Timeout handler. */
private Handler mHandler;
private Runnable mTimeOutRunnable = new Runnable() {
@Override
public void run() {
if (mLastLocation == null) {
dispatchOnLocationTimeout();
}
}
};
public NaoLocationManager(final Context context) {
mLocationClient = new LocationClient(context, this, this);
mLocationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
mListenerList = new HashSet<NaoLocationListener>();
mGeoCoder = new Geocoder(context, new Locale("fr", "FR"));
mHandler = new Handler();
}
public void addListener(final NaoLocationListener locationListener) {
if (DBG)
Log.d(LOG_TAG, "addListener " + locationListener.getClass().getSimpleName());
mListenerList.add(locationListener);
if (isEnabled()) {
if (!mLocationClient.isConnected() && !mLocationClient.isConnecting()) {
connect();
} else {
Location lastLocation = getLastLocation();
if (lastLocation != null) {
locationListener.onLocationChanged(lastLocation);
}
}
} else {
locationListener.onDisconnected();
}
}
public void removeListener(final NaoLocationListener locationListener) {
if (DBG)
Log.d(LOG_TAG, "removeListener " + locationListener.getClass().getSimpleName());
mListenerList.remove(locationListener);
if (mListenerList.isEmpty()) {
disconnect();
}
}
public void onResume() {
mHandler.removeCallbacks(mTimeOutRunnable);
boolean isEnabled = isEnabled();
if (mServiceEnabled != isEnabled) {
if (isEnabled) {
if (!mLocationClient.isConnecting()) {
mLocationClient.connect();
dispatchOnConnecting();
}
} else {
dispatchOnDisconnect();
}
mServiceEnabled = isEnabled;
}
}
public void connect() {
if (isEnabled()) {
if (!mLocationClient.isConnecting()) {
mLocationClient.connect();
dispatchOnConnecting();
mServiceEnabled = true;
}
} else {
mServiceEnabled = false;
}
}
public void disconnect() {
mLocationClient.disconnect();
}
public boolean isEnabled() {
return mLocationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)
|| mLocationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
}
public Location getLastLocation() {
if (mLocationClient.isConnected()) {
final Location lastLocation = mLocationClient.getLastLocation();
return (lastLocation == null) ? mLastLocation : lastLocation;
} else {
return mLastLocation;
}
}
@Override
public void onConnected(Bundle connectionHint) {
if (DBG)
Log.d(LOG_TAG, "onConnected");
final LocationRequest request = new LocationRequest();
request.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
request.setSmallestDisplacement(20f);
request.setFastestInterval(4000);
request.setInterval(15000);
mLocationClient.requestLocationUpdates(request, this);
Location lastLocation = mLocationClient.getLastLocation();
onLocationChanged(lastLocation);
mHandler.postDelayed(mTimeOutRunnable, TIMEOUT);
}
@Override
public void onConnectionFailed(ConnectionResult result) {
if (DBG)
Log.e(LOG_TAG, "onConnectionFailed " + result.getErrorCode());
dispatchOnDisconnect();
}
@Override
public void onLocationChanged(Location location) {
if (DBG)
Log.d(LOG_TAG, "onLocationChanged " + location);
if (location != null) {
dispatchOnLocationChanged(location);
mLastLocation = location;
}
}
@Override
public void onDisconnected() {
dispatchOnDisconnect();
}
private void dispatchOnLocationChanged(Location location) {
for (NaoLocationListener l : mListenerList) {
l.onLocationChanged(location);
}
}
private void dispatchOnDisconnect() {
for (NaoLocationListener l : mListenerList) {
l.onDisconnected();
}
}
private void dispatchOnConnecting() {
for (NaoLocationListener l : mListenerList) {
l.onConnecting();
}
}
private void dispatchOnLocationTimeout() {
for (NaoLocationListener l : mListenerList) {
l.onLocationTimeout();
}
}
/**
* Récupérer l'adresse de la dernière position courante
*/
public Address getLastKnownAddress() {
if (DBG)
Log.d(LOG_TAG, "getLastKnownAddress");
final Location lastKnowLocation = getLastLocation();
Address result = null;
try {
if (lastKnowLocation != null) {
final List<Address> addresses = mGeoCoder.getFromLocation(lastKnowLocation.getLatitude(),
lastKnowLocation.getLongitude(), 1);
if (addresses != null && addresses.size() > 0) {
result = addresses.get(0);
}
}
} catch (final IOException e) {
if (DBG)
Log.w(LOG_TAG, "Erreur lors de la récupération de l'adresse.", e);
}
return result;
}
}