-
-
Save blackcj/20efe2ac885c7297a676 to your computer and use it in GitHub Desktop.
Background location services.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* | |
* BackgroundLocationService used for tracking user location in the background. | |
* @author cblack | |
*/ | |
public class BackgroundLocationService extends Service implements | |
GoogleApiClient.ConnectionCallbacks, | |
GoogleApiClient.OnConnectionFailedListener, | |
LocationListener { | |
IBinder mBinder = new LocalBinder(); | |
private GoogleApiClient mGoogleApiClient; | |
private PowerManager.WakeLock mWakeLock; | |
private LocationRequest mLocationRequest; | |
// Flag that indicates if a request is underway. | |
private boolean mInProgress; | |
private Boolean servicesAvailable = false; | |
public class LocalBinder extends Binder { | |
public BackgroundLocationService getServerInstance() { | |
return BackgroundLocationService.this; | |
} | |
} | |
@Override | |
public void onCreate() { | |
super.onCreate(); | |
mInProgress = false; | |
// Create the LocationRequest object | |
mLocationRequest = LocationRequest.create(); | |
// Use high accuracy | |
mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY); | |
// Set the update interval to 5 seconds | |
mLocationRequest.setInterval(Constants.UPDATE_INTERVAL); | |
// Set the fastest update interval to 1 second | |
mLocationRequest.setFastestInterval(Constants.FASTEST_INTERVAL); | |
servicesAvailable = servicesConnected(); | |
/* | |
* Create a new location client, using the enclosing class to | |
* handle callbacks. | |
*/ | |
setUpLocationClientIfNeeded(); | |
} | |
/* | |
* Create a new location client, using the enclosing class to | |
* handle callbacks. | |
*/ | |
protected synchronized void buildGoogleApiClient() { | |
this.mGoogleApiClient = new GoogleApiClient.Builder(this) | |
.addConnectionCallbacks(this) | |
.addOnConnectionFailedListener(this) | |
.addApi(LocationServices.API) | |
.build(); | |
} | |
private boolean servicesConnected() { | |
// Check that Google Play services is available | |
int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this); | |
// If Google Play services is available | |
if (ConnectionResult.SUCCESS == resultCode) { | |
return true; | |
} else { | |
return false; | |
} | |
} | |
public int onStartCommand (Intent intent, int flags, int startId) | |
{ | |
super.onStartCommand(intent, flags, startId); | |
PowerManager mgr = (PowerManager)getSystemService(Context.POWER_SERVICE); | |
/* | |
WakeLock is reference counted so we don't want to create multiple WakeLocks. So do a check before initializing and acquiring. | |
This will fix the "java.lang.Exception: WakeLock finalized while still held: MyWakeLock" error that you may find. | |
*/ | |
if (this.mWakeLock == null) { //**Added this | |
this.mWakeLock = mgr.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MyWakeLock"); | |
} | |
if (!this.mWakeLock.isHeld()) { //**Added this | |
this.mWakeLock.acquire(); | |
} | |
if(!servicesAvailable || mGoogleApiClient.isConnected() || mInProgress) | |
return START_STICKY; | |
setUpLocationClientIfNeeded(); | |
if(!mGoogleApiClient.isConnected() || !mGoogleApiClient.isConnecting() && !mInProgress) | |
{ | |
appendLog(DateFormat.getDateTimeInstance().format(new Date()) + ": Started", Constants.LOG_FILE); | |
mInProgress = true; | |
mGoogleApiClient.connect(); | |
} | |
return START_STICKY; | |
} | |
private void setUpLocationClientIfNeeded() | |
{ | |
if(mGoogleApiClient == null) | |
buildGoogleApiClient(); | |
} | |
// Define the callback method that receives location updates | |
@Override | |
public void onLocationChanged(Location location) { | |
// Report to the UI that the location was updated | |
String msg = Double.toString(location.getLatitude()) + "," + | |
Double.toString(location.getLongitude()); | |
Log.d("debug", msg); | |
// Toast.makeText(this, msg, Toast.LENGTH_SHORT).show(); | |
appendLog(DateFormat.getDateTimeInstance().format(new Date()) + ":" + msg, Constants.LOCATION_FILE); | |
} | |
@Override | |
public IBinder onBind(Intent intent) { | |
return mBinder; | |
} | |
public String getTime() { | |
SimpleDateFormat mDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); | |
return mDateFormat.format(new Date()); | |
} | |
public void appendLog(String text, String filename) | |
{ | |
File logFile = new File(filename); | |
if (!logFile.exists()) | |
{ | |
try | |
{ | |
logFile.createNewFile(); | |
} | |
catch (IOException e) | |
{ | |
// TODO Auto-generated catch block | |
e.printStackTrace(); | |
} | |
} | |
try | |
{ | |
//BufferedWriter for performance, true to set append to file flag | |
BufferedWriter buf = new BufferedWriter(new FileWriter(logFile, true)); | |
buf.append(text); | |
buf.newLine(); | |
buf.close(); | |
} | |
catch (IOException e) | |
{ | |
// TODO Auto-generated catch block | |
e.printStackTrace(); | |
} | |
} | |
@Override | |
public void onDestroy() { | |
// Turn off the request flag | |
this.mInProgress = false; | |
if (this.servicesAvailable && this.mGoogleApiClient != null) { | |
this.mGoogleApiClient.unregisterConnectionCallbacks(this); | |
this.mGoogleApiClient.unregisterConnectionFailedListener(this); | |
this.mGoogleApiClient.disconnect(); | |
// Destroy the current location client | |
this.mGoogleApiClient = null; | |
} | |
// Display the connection status | |
// Toast.makeText(this, DateFormat.getDateTimeInstance().format(new Date()) + ": | |
// Disconnected. Please re-connect.", Toast.LENGTH_SHORT).show(); | |
if (this.mWakeLock != null) { | |
this.mWakeLock.release(); | |
this.mWakeLock = null; | |
} | |
super.onDestroy(); | |
} | |
/* | |
* Called by Location Services when the request to connect the | |
* client finishes successfully. At this point, you can | |
* request the current location or start periodic updates | |
*/ | |
@Override | |
public void onConnected(Bundle bundle) { | |
// Request location updates using static settings | |
Intent intent = new Intent(this, LocationReceiver.class); | |
LocationServices.FusedLocationApi.requestLocationUpdates(this.mGoogleApiClient, | |
mLocationRequest, this); // This is the changed line. | |
appendLog(DateFormat.getDateTimeInstance().format(new Date()) + ": Connected", Constants.LOG_FILE); | |
} | |
/* | |
* Called by Location Services if the connection to the | |
* location client drops because of an error. | |
*/ | |
@Override | |
public void onConnectionSuspended(int i) { | |
// Turn off the request flag | |
mInProgress = false; | |
// Destroy the current location client | |
mGoogleApiClient = null; | |
// Display the connection status | |
// Toast.makeText(this, DateFormat.getDateTimeInstance().format(new Date()) + ": Disconnected. Please re-connect.", Toast.LENGTH_SHORT).show(); | |
appendLog(DateFormat.getDateTimeInstance().format(new Date()) + ": Disconnected", Constants.LOG_FILE); | |
} | |
/* | |
* Called by Location Services if the attempt to | |
* Location Services fails. | |
*/ | |
@Override | |
public void onConnectionFailed(ConnectionResult connectionResult) { | |
mInProgress = false; | |
/* | |
* Google Play services can resolve some errors it detects. | |
* If the error has a resolution, try sending an Intent to | |
* start a Google Play services activity that can resolve | |
* error. | |
*/ | |
if (connectionResult.hasResolution()) { | |
// If no resolution is available, display an error dialog | |
} else { | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
apply plugin: 'com.android.application' | |
android { | |
compileSdkVersion 22 | |
buildToolsVersion "22.0.1" | |
defaultConfig { | |
applicationId "com.blackcj.locationtracker" | |
minSdkVersion 18 | |
targetSdkVersion 22 | |
versionCode 1 | |
versionName "1.0" | |
} | |
buildTypes { | |
release { | |
minifyEnabled false | |
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' | |
} | |
} | |
} | |
dependencies { | |
compile fileTree(dir: 'libs', include: ['*.jar']) | |
testCompile 'junit:junit:4.12' | |
compile 'com.android.support:appcompat-v7:22.2.1' | |
compile 'com.google.android.gms:play-services-location:8.4.0' | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public final class Constants { | |
// Milliseconds per second | |
private static final int MILLISECONDS_PER_SECOND = 1000; | |
// Update frequency in seconds | |
private static final int UPDATE_INTERVAL_IN_SECONDS = 60; | |
// Update frequency in milliseconds | |
public static final long UPDATE_INTERVAL = MILLISECONDS_PER_SECOND * UPDATE_INTERVAL_IN_SECONDS; | |
// The fastest update frequency, in seconds | |
private static final int FASTEST_INTERVAL_IN_SECONDS = 60; | |
// A fast frequency ceiling in milliseconds | |
public static final long FASTEST_INTERVAL = MILLISECONDS_PER_SECOND * FASTEST_INTERVAL_IN_SECONDS; | |
// Stores the lat / long pairs in a text file | |
public static final String LOCATION_FILE = "sdcard/location.txt"; | |
// Stores the connect / disconnect data in a text file | |
public static final String LOG_FILE = "sdcard/log.txt"; | |
public static final String RUNNING = "runningInBackground"; // Recording data in background | |
public static final String APP_PACKAGE_NAME = "com.blackcj.locationtracker"; | |
/** | |
* Suppress default constructor for noninstantiability | |
*/ | |
private Constants() { | |
throw new AssertionError(); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class LocationLoggerServiceManager extends BroadcastReceiver { | |
private SharedPreferences mPrefs; | |
public static final String TAG = "LLoggerServiceManager"; | |
@Override | |
public void onReceive(Context context, Intent intent) { | |
// Make sure we are getting the right intent | |
if( "android.intent.action.BOOT_COMPLETED".equals(intent.getAction())) { | |
boolean mUpdatesRequested = false; | |
// Open the shared preferences | |
mPrefs = context.getSharedPreferences( | |
Constants.APP_PACKAGE_NAME, Context.MODE_PRIVATE); | |
/* | |
* Get any previous setting for location updates | |
* Gets "false" if an error occurs | |
*/ | |
if (mPrefs.contains(Constants.RUNNING)) { | |
mUpdatesRequested = mPrefs.getBoolean(Constants.RUNNING, false); | |
} | |
if(mUpdatesRequested){ | |
ComponentName comp = new ComponentName(context.getPackageName(), BackgroundLocationService.class.getName()); | |
ComponentName service = context.startService(new Intent().setComponent(comp)); | |
if (null == service){ | |
// something really wrong here | |
Log.e(TAG, "Could not start service " + comp.toString()); | |
} | |
} | |
} else { | |
Log.e(TAG, "Received unexpected intent " + intent.toString()); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="utf-8"?> | |
<manifest xmlns:android="http://schemas.android.com/apk/res/android" | |
package="com.blackcj.locationtracker"> | |
<!-- Used to start logging after re-boot --> | |
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> | |
<uses-permission android:name="android.permission.INTERNET" /> | |
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> | |
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> | |
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> | |
<uses-permission android:name="android.permission.WAKE_LOCK" /> | |
<application | |
android:allowBackup="true" | |
android:icon="@mipmap/ic_launcher" | |
android:label="@string/app_name" | |
android:supportsRtl="true" | |
android:theme="@style/AppTheme"> | |
<activity android:name=".MainActivity"> | |
<intent-filter> | |
<action android:name="android.intent.action.MAIN" /> | |
<category android:name="android.intent.category.LAUNCHER" /> | |
</intent-filter> | |
</activity> | |
<receiver android:name=".LocationLoggerServiceManager" | |
android:enabled="true" | |
android:exported="false" | |
android:label="LocationLoggerServiceManager"> | |
<intent-filter> | |
<action android:name="android.intent.action.BOOT_COMPLETED" /> | |
</intent-filter> | |
</receiver> | |
<service android:name=".BackgroundLocationService" | |
android:enabled="true" | |
android:exported="true" > | |
<intent-filter> | |
<action | |
android:name="com.google.android.gms.wearable.BIND_LISTENER" /> | |
</intent-filter> | |
</service> | |
</application> | |
</manifest> |
Hello there, how come when i implemented this, background service when i use stopService(i) // i = intent
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Use this
GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(context)
instead of thisGooglePlayServicesUtil.isGooglePlayServicesAvailable(this);