[android] #2421 - Initial build out of Telemetry Location infrastructure

This commit is contained in:
Brad Leege
2016-01-29 14:24:31 -06:00
parent 20be32f217
commit cf107d85bf
2 changed files with 236 additions and 0 deletions

View File

@@ -0,0 +1,74 @@
package com.mapbox.mapboxsdk.telemetry;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.location.Location;
import android.location.LocationManager;
import android.media.AudioManager;
import android.media.ToneGenerator;
import android.os.Handler;
import android.util.Log;
public class TelemetryLocationReceiver extends BroadcastReceiver {
private static final String TAG = "TelemLocationReceiver";
/**
* Default Constructor
*/
public TelemetryLocationReceiver() {
super();
}
/**
* This method is called when the BroadcastReceiver is receiving an Intent
* broadcast. During this time you can use the other methods on
* BroadcastReceiver to view/modify the current result values. This method
* is always called within the main thread of its process, unless you
* explicitly asked for it to be scheduled on a different thread using
* {@link Context#registerReceiver(BroadcastReceiver,
* IntentFilter, String, Handler)}. When it runs on the main
* thread you should
* never perform long-running operations in it (there is a timeout of
* 10 seconds that the system allows before considering the receiver to
* be blocked and a candidate to be killed). You cannot launch a popup dialog
* in your implementation of onReceive().
* <p/>
* <p><b>If this BroadcastReceiver was launched through a &lt;receiver&gt; tag,
* then the object is no longer alive after returning from this
* function.</b> This means you should not perform any operations that
* return a result to you asynchronously -- in particular, for interacting
* with services, you should use
* {@link Context#startService(Intent)} instead of
* {@link Context#bindService(Intent, ServiceConnection, int)}. If you wish
* to interact with a service that is already running, you can use
* {@link #peekService}.
* <p/>
* <p>The Intent filters used in {@link Context#registerReceiver}
* and in application manifests are <em>not</em> guaranteed to be exclusive. They
* are hints to the operating system about how to find suitable recipients. It is
* possible for senders to force delivery to specific recipients, bypassing filter
* resolution. For this reason, {@link #onReceive(Context, Intent) onReceive()}
* implementations should respond only to known actions, ignoring any unexpected
* Intents that they may receive.
*
* @param context The Context in which the receiver is running.
* @param intent The Intent being received.
*/
@Override
public void onReceive(Context context, Intent intent) {
Location location = (Location)intent.getExtras().get(LocationManager.KEY_LOCATION_CHANGED);
if (location != null) {
Log.i(TAG, "location received = " + location);
final ToneGenerator tg = new ToneGenerator(AudioManager.STREAM_NOTIFICATION, 100);
tg.startTone(ToneGenerator.TONE_PROP_BEEP);
tg.stopTone();
tg.release();
} else {
Log.i(TAG, "location NOT received");
}
}
}

View File

@@ -0,0 +1,162 @@
package com.mapbox.mapboxsdk.telemetry;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ServiceInfo;
import android.os.AsyncTask;
import android.os.IBinder;
import android.os.PowerManager;
import android.support.annotation.Nullable;
import android.util.Log;
public class TelemetryService extends Service {
private static final String TAG = "TelemetryService";
private TelemetryLocationReceiver telemetryLocationReceiver = null;
private PendingIntent locationPendingIntent = null;
private PowerManager.WakeLock telemetryWakeLock;
/**
* Return the communication channel to the service. May return null if
* clients can not bind to the service. The returned
* {@link IBinder} is usually for a complex interface
* that has been <a href="{@docRoot}guide/components/aidl.html">described using
* aidl</a>.
* <p/>
* <p><em>Note that unlike other application components, calls on to the
* IBinder interface returned here may not happen on the main thread
* of the process</em>. More information about the main thread can be found in
* <a href="{@docRoot}guide/topics/fundamentals/processes-and-threads.html">Processes and
* Threads</a>.</p>
*
* @param intent The Intent that was used to bind to this service,
* as given to {@link Context#bindService
* Context.bindService}. Note that any extras that were included with
* the Intent at that point will <em>not</em> be seen here.
* @return Return an IBinder through which clients can call on to the
* service.
*/
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
/**
* Called by the system when the service is first created. Do not call this method directly.
*/
@Override
public void onCreate() {
super.onCreate();
// Enable Location Listening for lifecycle of app
IntentFilter filter = new IntentFilter("com.mapbox.mapboxsdk.telemetry.TelemetryLocationReceiver");
telemetryLocationReceiver = new TelemetryLocationReceiver();
registerReceiver(telemetryLocationReceiver, filter);
}
/**
* Called by the system to notify a Service that it is no longer used and is being removed. The
* service should clean up any resources it holds (threads, registered
* receivers, etc) at this point. Upon return, there will be no more calls
* in to this Service object and it is effectively dead. Do not call this method directly.
*/
@Override
public void onDestroy() {
shutdownTelemetry();
super.onDestroy();
}
/**
* This is called if the service is currently running and the user has
* removed a task that comes from the service's application. If you have
* set {@link ServiceInfo#FLAG_STOP_WITH_TASK ServiceInfo.FLAG_STOP_WITH_TASK}
* then you will not receive this callback; instead, the service will simply
* be stopped.
*
* @param rootIntent The original root Intent that was used to launch
* the task that is being removed.
*/
@Override
public void onTaskRemoved(Intent rootIntent) {
shutdownTelemetry();
super.onTaskRemoved(rootIntent);
}
/**
* Called by the system every time a client explicitly starts the service by calling
* {@link Context#startService}, providing the arguments it supplied and a
* unique integer token representing the start request. Do not call this method directly.
* <p/>
* <p>For backwards compatibility, the default implementation calls
* {@link #onStart} and returns either {@link #START_STICKY}
* or {@link #START_STICKY_COMPATIBILITY}.
* <p/>
* <p>If you need your application to run on platform versions prior to API
* level 5, you can use the following model to handle the older {@link #onStart}
* callback in that case. The <code>handleCommand</code> method is implemented by
* you as appropriate:
* <p/>
* {@sample development/samples/ApiDemos/src/com/example/android/apis/app/ForegroundService.java
* start_compatibility}
* <p/>
* <p class="caution">Note that the system calls this on your
* service's main thread. A service's main thread is the same
* thread where UI operations take place for Activities running in the
* same process. You should always avoid stalling the main
* thread's event loop. When doing long-running operations,
* network calls, or heavy disk I/O, you should kick off a new
* thread, or use {@link AsyncTask}.</p>
*
* @param intent The Intent supplied to {@link Context#startService},
* as given. This may be null if the service is being restarted after
* its process has gone away, and it had previously returned anything
* except {@link #START_STICKY_COMPATIBILITY}.
* @param flags Additional data about this start request. Currently either
* 0, {@link #START_FLAG_REDELIVERY}, or {@link #START_FLAG_RETRY}.
* @param startId A unique integer representing this specific request to
* start. Use with {@link #stopSelfResult(int)}.
* @return The return value indicates what semantics the system should
* use for the service's current started state. It may be one of the
* constants associated with the {@link #START_CONTINUATION_MASK} bits.
* @see #stopSelfResult(int)
*/
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// Start WakeLock to keep Location Data working when device sleeps
PowerManager mgr = (PowerManager)getSystemService(Context.POWER_SERVICE);
telemetryWakeLock = mgr.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "TelemetryWakeLock");
telemetryWakeLock.acquire();
// Start Ambient Location Listening
// TODO
Intent locIntent = new Intent("com.mapbox.hermes.LocationReceiver");
locationPendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 14872, locIntent, PendingIntent.FLAG_CANCEL_CURRENT);
try {
// Request Location Updates to be delivered to PendingIntent
// Currently Not supported in LOST
// TODO
// locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000, 3.0f, mLocationPendingIntent);
} catch (SecurityException e) {
Log.e(TAG, "Permissions Not Authorized For Location Updates: " + e);
}
return START_NOT_STICKY;
}
private void shutdownTelemetry() {
// TODO
// locationManager.removeUpdates(mLocationPendingIntent);
locationPendingIntent.cancel();
unregisterReceiver(telemetryLocationReceiver);
telemetryWakeLock.release();
}
}