/******************************************************************************* * Created by Carlos Yaconi * Copyright 2015 Prey Inc. All rights reserved. * License: GPLv3 * Full license at "/LICENSE" ******************************************************************************/ package com.prey.services; import android.app.IntentService; import android.app.PendingIntent; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.location.Location; import android.util.Log; import com.google.android.gms.common.ConnectionResult; import com.google.android.gms.common.api.GoogleApiClient; import com.google.android.gms.location.FusedLocationProviderApi; import com.google.android.gms.location.LocationRequest; import com.google.android.gms.location.LocationServices; import com.prey.PreyConfig; import com.prey.PreyLogger; import java.util.concurrent.TimeUnit; import static com.google.android.gms.location.LocationServices.FusedLocationApi; /** * A utility IntentService, used for a variety of asynchronous background * operations that do not necessarily need to be tied to a UI. */ public class UtilityService extends IntentService { private static final String ACTION_LOCATION_UPDATED = "location_updated"; private static final String ACTION_REQUEST_LOCATION = "request_location"; /* * Constants for location update parameters */ // Milliseconds per second public static final int MILLISECONDS_PER_SECOND = 1000; // The update interval public static final int UPDATE_INTERVAL_IN_SECONDS = 10; // A fast interval ceiling public static final int FAST_CEILING_IN_SECONDS = 1; // Update interval in milliseconds public static final long UPDATE_INTERVAL_IN_MILLISECONDS = MILLISECONDS_PER_SECOND * UPDATE_INTERVAL_IN_SECONDS; // A fast ceiling of update intervals, used when the app is visible public static final long FAST_INTERVAL_CEILING_IN_MILLISECONDS = MILLISECONDS_PER_SECOND * FAST_CEILING_IN_SECONDS; private LocationRequest mLocationRequest; public static IntentFilter getLocationUpdatedIntentFilter() { return new IntentFilter(UtilityService.ACTION_LOCATION_UPDATED); } public static void requestLocation(Context context) { Intent intent = new Intent(context, UtilityService.class); intent.setAction(UtilityService.ACTION_REQUEST_LOCATION); context.startService(intent); } public UtilityService() { super(PreyConfig.TAG); } @Override protected void onHandleIntent(Intent intent) { String action = intent != null ? intent.getAction() : null; if (ACTION_REQUEST_LOCATION.equals(action)) { requestLocationInternal(); } else if (ACTION_LOCATION_UPDATED.equals(action)) { locationUpdated(intent); } } public static final int GOOGLE_API_CLIENT_TIMEOUT_S = 10; // 10 seconds public static final String GOOGLE_API_CLIENT_ERROR_MSG = "Failed to connect to GoogleApiClient (error code = %d)"; /** * Called when a location update is requested */ private void requestLocationInternal() { PreyLogger.d(ACTION_REQUEST_LOCATION); GoogleApiClient googleApiClient = new GoogleApiClient.Builder(this) .addApi(LocationServices.API) .build(); // It's OK to use blockingConnect() here as we are running in an // IntentService that executes work on a separate (background) thread. ConnectionResult connectionResult = googleApiClient.blockingConnect( GOOGLE_API_CLIENT_TIMEOUT_S, TimeUnit.SECONDS); if (connectionResult.isSuccess() && googleApiClient.isConnected()) { Intent locationUpdatedIntent = new Intent(this, UtilityService.class); locationUpdatedIntent.setAction(ACTION_LOCATION_UPDATED); // Send last known location out first if available Location location = FusedLocationApi.getLastLocation(googleApiClient); if (location != null) { Intent lastLocationIntent = new Intent(locationUpdatedIntent); lastLocationIntent.putExtra( FusedLocationProviderApi.KEY_LOCATION_CHANGED, location); startService(lastLocationIntent); } // Request new location LocationRequest mLocationRequest = new LocationRequest() .setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY); FusedLocationApi.requestLocationUpdates( googleApiClient, mLocationRequest, PendingIntent.getService(this, 0, locationUpdatedIntent, 0)); googleApiClient.disconnect(); } else { PreyLogger.i(String.format(GOOGLE_API_CLIENT_ERROR_MSG, connectionResult.getErrorCode())); } } /** * Called when the location has been updated */ private void locationUpdated(Intent intent) { PreyLogger.d( ACTION_LOCATION_UPDATED); // Extra new location Location location = intent.getParcelableExtra(FusedLocationProviderApi.KEY_LOCATION_CHANGED); } public Location getLastLocation() { return null; } }