/* * Copyright (C) 2013 Sylvain Maucourt (smaucourt@gmail.com) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * */ package net.sylvek.sharemyposition; import com.google.android.gms.common.ConnectionResult; import com.google.android.gms.common.GooglePlayServicesClient.ConnectionCallbacks; import com.google.android.gms.common.GooglePlayServicesClient.OnConnectionFailedListener; import com.google.android.gms.location.LocationClient; import com.google.android.gms.location.LocationRequest; import org.apache.http.HttpResponse; import org.apache.http.NameValuePair; import org.apache.http.client.HttpClient; import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.HttpPost; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.message.BasicNameValuePair; import org.apache.http.params.BasicHttpParams; import org.apache.http.params.HttpParams; import org.apache.http.params.HttpProtocolParams; import java.util.ArrayList; import java.util.List; import java.util.concurrent.Executors; import android.app.IntentService; import android.app.NotificationManager; import android.app.PendingIntent; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.location.Location; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.os.Build; import android.os.Bundle; import android.os.IBinder; import android.os.PowerManager; import android.os.PowerManager.WakeLock; import android.util.Log; /** * @author sylvek * */ public class ShareByTracking extends IntentService { private static final String PARAMETER_POSITION = "pos"; private static final String PARAMETER_UUID = "uuid"; private static final String LOG = "ShareByTracking"; private static final long INTERVAL = 15000L; private static final float SMALLEST_DISPLACEMENT = 50; private static final int PRIORITY = LocationRequest.PRIORITY_HIGH_ACCURACY; private static final String UPDATE_LOCATION = ShareMyPosition.HOST + "service/update"; static final String UUID = ".uuid"; private final HttpParams params = new BasicHttpParams(); private ConnectivityManager cm; private PowerManager pm; private WakeLock wl; protected static final ConnectionCallbacks connectionCallbacks = new ConnectionCallbacks() { @Override public void onDisconnected() { } @Override public void onConnected(Bundle arg0) { } }; protected static final OnConnectionFailedListener onConnectionFailedListener = new OnConnectionFailedListener() { @Override public void onConnectionFailed(ConnectionResult arg0) { } }; public static class StopTracking extends BroadcastReceiver { @Override public void onReceive(final Context context, final Intent intent) { final NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); final LocationClient locationClient = new LocationClient(context, connectionCallbacks, onConnectionFailedListener); locationClient.registerConnectionCallbacks(new ConnectionCallbacks() { @Override public void onDisconnected() { Log.d(LOG, "StopTracking.onDisconnected"); } @Override public void onConnected(Bundle arg0) { final PendingIntent service = PendingIntent.getService(context, 0, new Intent(context, ShareByTracking.class), PendingIntent.FLAG_UPDATE_CURRENT); locationClient.removeLocationUpdates(service); locationClient.disconnect(); notificationManager.cancel(R.string.app_name); Log.d(LOG, "StopTracking.onConnected"); } }); locationClient.connect(); } } public static class StartTracking extends BroadcastReceiver { @Override public void onReceive(final Context context, final Intent intent) { if (intent.getExtras().containsKey(UUID)) { final String uuid = intent.getStringExtra(UUID); final LocationClient locationClient = new LocationClient(context, connectionCallbacks, onConnectionFailedListener); locationClient.registerConnectionCallbacks(new ConnectionCallbacks() { @Override public void onDisconnected() { Log.d(LOG, "StartTracking.onDisconnected"); } @Override public void onConnected(Bundle arg0) { final LocationRequest locationRequest = LocationRequest.create() .setSmallestDisplacement(SMALLEST_DISPLACEMENT) .setInterval(INTERVAL) .setPriority(PRIORITY); final PendingIntent service = PendingIntent.getService(context, 0, new Intent(context, ShareByTracking.class).putExtra(UUID, uuid), PendingIntent.FLAG_UPDATE_CURRENT); locationClient.requestLocationUpdates(locationRequest, service); locationClient.disconnect(); Log.d(LOG, "StartTracking.onConnected"); } }); locationClient.connect(); } } } public ShareByTracking() { super(LOG); } @Override public IBinder onBind(Intent arg0) { return null; } @Override public void onCreate() { super.onCreate(); cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); pm = (PowerManager) getSystemService(Context.POWER_SERVICE); HttpProtocolParams.setUserAgent(params, "Android/" + Build.DISPLAY + "/version:" + ShareMyPosition.VERSION); } public void share(final Location location, final String uuid) { Log.d(LOG, "share(" + uuid + "): " + location); final String position = location.getLatitude() + "," + location.getLongitude(); Executors.newCachedThreadPool().execute(new Runnable() { @Override public void run() { try { final HttpClient client = new DefaultHttpClient(params); final HttpPost post = new HttpPost(UPDATE_LOCATION); final List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(2); nameValuePairs.add(new BasicNameValuePair(PARAMETER_UUID, uuid)); nameValuePairs.add(new BasicNameValuePair(PARAMETER_POSITION, position)); post.setEntity(new UrlEncodedFormEntity(nameValuePairs)); final HttpResponse response = client.execute(post); if (200 != response.getStatusLine().getStatusCode()) { Log.w(LOG, "status code is not 200"); } } catch (final Exception e) { Log.e(LOG, e.getMessage()); } } }); } @Override public void onDestroy() { Log.d(LOG, "onDestroy"); synchronized (this.wl) { if (this.wl.isHeld()) { this.wl.release(); } } } @Override protected void onHandleIntent(final Intent intent) { Log.d(LOG, "onHandleIntent"); this.wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, LOG); synchronized (this.wl) { this.wl.setReferenceCounted(false); this.wl.acquire(); } if (intent.hasExtra(LocationClient.KEY_LOCATION_CHANGED) && intent.hasExtra(UUID)) { final NetworkInfo activeNetwork = cm.getActiveNetworkInfo(); if (activeNetwork != null && activeNetwork.isConnectedOrConnecting()) { final Bundle extras = intent.getExtras(); final Location location = (Location) (extras.get(LocationClient.KEY_LOCATION_CHANGED)); share(location, extras.getString(UUID)); } } } }