Implementing Dwell in Geofence when user exits the region - java

MainActivity.java
import android.Manifest;
import android.app.PendingIntent;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.location.Location;
import android.location.LocationManager;
import android.os.Bundle;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesUtil;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.ResultCallback;
import com.google.android.gms.common.api.Status;
import com.google.android.gms.location.Geofence;
import com.google.android.gms.location.GeofencingRequest;
import com.google.android.gms.location.LocationListener;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationServices;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
public class MainActivity extends AppCompatActivity implements LocationListener {
PendingIntent mGeofencePendingIntent;
public static final int CONNECTION_FAILURE_RESOLUTION_REQUEST = 100;
private List<Geofence> mGeofenceList;
private GoogleApiClient mGoogleApiClient;
public static final String TAG = "Activity";
LocationRequest mLocationRequest;
double currentLatitude =12.9141 , currentLongitude = 77.6233;
Boolean locationFound;
protected LocationManager locationManager;
protected LocationListener locationListener;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
if (savedInstanceState == null) {
mGeofenceList = new ArrayList<Geofence>();
int resp = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
if (resp == ConnectionResult.SUCCESS) {
initGoogleAPIClient();
createGeofences(currentLatitude, currentLongitude);
} else {
Log.e(TAG, "Your Device doesn't support Google Play Services.");
}
// Create the LocationRequest object
mLocationRequest = LocationRequest.create()
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
.setInterval(1 * 1000) // 10 seconds, in milliseconds
.setFastestInterval(1 * 1000); // 1 second, in milliseconds
}
}
public void initGoogleAPIClient() {
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addApi(LocationServices.API)
.addConnectionCallbacks(connectionAddListener)
.addOnConnectionFailedListener(connectionFailedListener)
.build();
mGoogleApiClient.connect();
}
private GoogleApiClient.ConnectionCallbacks connectionAddListener =
new GoogleApiClient.ConnectionCallbacks() {
#Override
public void onConnected(Bundle bundle) {
Log.i(TAG, "onConnected");
Location location = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
if (location == null) {
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, MainActivity.this);
} else {
//If everything went fine lets get latitude and longitude
currentLatitude = location.getLatitude();
currentLongitude = location.getLongitude();
Log.i(TAG, currentLatitude + " WORKS " + currentLongitude);
//createGeofences(currentLatitude, currentLongitude);
//registerGeofences(mGeofenceList);
}
try{
LocationServices.GeofencingApi.addGeofences(
mGoogleApiClient,
getGeofencingRequest(),
getGeofencePendingIntent()
).setResultCallback(new ResultCallback<Status>() {
#Override
public void onResult(Status status) {
if (status.isSuccess()) {
Log.i(TAG, "Saving Geofence");
} else {
Log.e(TAG, "Registering geofence failed: " + status.getStatusMessage() +
" : " + status.getStatusCode());
}
}
});
} catch (SecurityException securityException) {
// Catch exception generated if the app does not use ACCESS_FINE_LOCATION permission.
Log.e(TAG, "Error");
}
}
#Override
public void onConnectionSuspended(int i) {
Log.e(TAG, "onConnectionSuspended");
}
};
private GoogleApiClient.OnConnectionFailedListener connectionFailedListener =
new GoogleApiClient.OnConnectionFailedListener() {
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
Log.e(TAG, "onConnectionFailed");
}
};
/**
* Create a Geofence list
*/
public void createGeofences(double latitude, double longitude) {
String id = UUID.randomUUID().toString();
Geofence fence = new Geofence.Builder()
.setRequestId(id)
.setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER | Geofence.GEOFENCE_TRANSITION_EXIT)
.setCircularRegion(latitude, longitude, 200)
.setExpirationDuration(Geofence.NEVER_EXPIRE)
.build();
mGeofenceList.add(fence);
}
private GeofencingRequest getGeofencingRequest() {
GeofencingRequest.Builder builder = new GeofencingRequest.Builder();
builder.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER);
builder.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_DWELL);
builder.addGeofences(mGeofenceList);
return builder.build();
}
private PendingIntent getGeofencePendingIntent() {
// Reuse the PendingIntent if we already have it.
if (mGeofencePendingIntent != null) {
return mGeofencePendingIntent;
}
Intent intent = new Intent(this, GeofenceTransitionsIntentService.class);
// We use FLAG_UPDATE_CURRENT so that we get the same pending intent back when
// calling addGeofences() and removeGeofences().
return PendingIntent.getService(this, 0, intent, PendingIntent.
FLAG_UPDATE_CURRENT);
}
#Override
public void onLocationChanged(Location location) {
currentLatitude = location.getLatitude();
currentLongitude = location.getLongitude();
Log.i(TAG, "onLocationChanged");
}
}
GeoTransitionsIntentservices.java
import android.app.IntentService;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.support.v4.app.NotificationCompat;
import android.util.Log;
import com.google.android.gms.location.Geofence;
import com.google.android.gms.location.GeofencingEvent;
public class GeofenceTransitionsIntentService extends IntentService {
private static final String TAG = "GeofenceTransitions";
public GeofenceTransitionsIntentService() {
super("GeofenceTransitionsIntentService");
}
#Override
protected void onHandleIntent(Intent intent) {
Log.i(TAG, "onHandleIntent");
GeofencingEvent geofencingEvent = GeofencingEvent.fromIntent(intent);
if (geofencingEvent.hasError()) {
//String errorMessage = GeofenceErrorMessages.getErrorString(this,
// geofencingEvent.getErrorCode());
Log.e(TAG, "Goefencing Error " + geofencingEvent.getErrorCode());
return;
}
// Get the transition type.
int geofenceTransition = geofencingEvent.getGeofenceTransition();
Log.i(TAG, "geofenceTransition = " + geofenceTransition + " Enter : " + Geofence.GEOFENCE_TRANSITION_ENTER + "Exit : " + Geofence.GEOFENCE_TRANSITION_EXIT);
if (geofenceTransition == Geofence.GEOFENCE_TRANSITION_ENTER || geofenceTransition == Geofence.GEOFENCE_TRANSITION_DWELL){
showNotification("Entered the location", "Entered the Location");
}
else if(geofenceTransition == Geofence.GEOFENCE_TRANSITION_EXIT) {
Log.i(TAG, "Showing Notification...");
showNotification("Exited", "Exited the Location");
} else {
// Log the error.
showNotification("Error", "Error");
Log.e(TAG, "Error ");
}
}
public void showNotification(String text, String bigText) {
// 1. Create a NotificationManager
NotificationManager notificationManager =
(NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);
// 2. Create a PendingIntent for AllGeofencesActivity
Intent intent = new Intent(this, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pendingNotificationIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
// 3. Create and send a notification
Notification notification = new NotificationCompat.Builder(this)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle("Geofence Monitor")
.setContentText(text)
.setContentIntent(pendingNotificationIntent)
.setStyle(new NotificationCompat.BigTextStyle().bigText(bigText))
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setAutoCancel(true)
.build();
notificationManager.notify(0, notification);
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
new NotificationCompat.Builder(this).setSmallIcon(R.mipmap.ic_launcher);
} else {
new NotificationCompat.Builder(this) .setSmallIcon(R.mipmap.ic_launcher);
}
}
}
I want to implement Dwell when user exits the region. I have developed the geofence notification when user exits and entry the region and now I want to implement it has to monitor for a certain period of time and after exiting.
It should make toast message and if I implement I am getting error message.

In your IntentService use toaster like this, it will not give error
private void sendNotification(String notificationDetails) {
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
Toast.makeText(getApplicationContext(), "here is your toast msg", Toast.LENGTH_LONG).show();
}
});
// Create an explicit content Intent that starts the main Activity.
Intent notificationIntent = new Intent(getApplicationContext(), MainActivity.class);
// Construct a task stack.
TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
// Add the main Activity to the task stack as the parent.
stackBuilder.addParentStack(MainActivity.class);
// Push the content Intent onto the stack.
stackBuilder.addNextIntent(notificationIntent);
// Get a PendingIntent containing the entire back stack.
PendingIntent notificationPendingIntent =
stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
// Get a notification builder that's compatible with platform versions >= 4
NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
// Define the notification settings.
builder.setSmallIcon(R.drawable.ic_launcher)
// In a real app, you may want to use a library like Volley
// to decode the Bitmap.
.setLargeIcon(BitmapFactory.decodeResource(getResources(),
R.drawable.ic_launcher))
.setColor(Color.RED)
.setContentTitle(notificationDetails)
.setContentText(getString(R.string.geofence_transition_notification_text))
.setContentIntent(notificationPendingIntent);
// Dismiss notification once the user touches it.
builder.setAutoCancel(true);
// Get an instance of the Notification manager
NotificationManager mNotificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
// Issue the notification
mNotificationManager.notify(0, builder.build());
}
And in
#Override
protected void onHandleIntent(Intent intent) {
// Get the transition type.
int geofenceTransition = geofencingEvent.getGeofenceTransition();
// Test that the reported transition was of interest.
if (geofenceTransition == Geofence.GEOFENCE_TRANSITION_EXIT){
sendNotification("your notification details");
sendAPICall("some token","body","my call");
}
}
//// Api call
public void sendAPICall(final String reg_token, final String body, final String title) {
new AsyncTask<Void, Void, Void>() {
#Override
protected Void doInBackground(Void... params) {
try {
OkHttpClient client = new OkHttpClient();
JSONObject json = new JSONObject();
JSONObject dataJson = new JSONObject();
dataJson.put("body", body);
dataJson.put("title", title);
json.put("notification", dataJson);
json.put("to", reg_token);
RequestBody body = RequestBody.create(JSON, json.toString());
Request request = new Request.Builder()
.header("Authorization", "key=" + Constants.GCM_AUTH_KEY)
.url("http://learnologic.com/send")
.post(body)
.build();
okhttp3.Response response = client.newCall(request).execute();
String finalResponse = response.body().string();
Logger.showDebugLog(finalResponse);
} catch (Exception e) {
Logger.showErrorLog(e.toString());
}
return null;
}
}.execute();
}
// stop monitor geofence
public void stopMonitoringGeofences() {
if (!mGoogleApiClient.isConnected()) {
Toast.makeText(this, getString(R.string.not_connected), Toast.LENGTH_SHORT).show();
return;
}
try {
// Remove geofences.
LocationServices.GeofencingApi.removeGeofences(
mGoogleApiClient,
// This is the same pending intent that was used in addGeofences().
getGeofencePendingIntent()
).setResultCallback(this); // Result processed in onResult().
} catch (SecurityException securityException) {
// Catch exception generated if the app does not use ACCESS_FINE_LOCATION permission.
logSecurityException(securityException);
}
}
private PendingIntent getGeofencePendingIntent() {
// Reuse the PendingIntent if we already have it.
if (mGeofencePendingIntent != null) {
return mGeofencePendingIntent;
}
Intent intent = new Intent(this, GeofenceTransitionsIntentService.class);
// We use FLAG_UPDATE_CURRENT so that we get the same pending intent back when calling
// addGeofences() and removeGeofences().
return PendingIntent.getService(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
}

Related

Continuously get user location when app is paused or killed in android

I want to continuously get location updates in the background using service even app is paused I tried much but when the app is paused it won't get any of the user's locations.
Here is my service.java
package com.app.testservices;
import android.app.AlarmManager;
import android.app.Notification;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.location.Location;
import android.os.IBinder;
import android.os.Looper;
import android.os.SystemClock;
import android.util.Log;
import androidx.annotation.Nullable;
import androidx.core.app.NotificationCompat;
import com.google.android.gms.location.FusedLocationProviderClient;
import com.google.android.gms.location.LocationCallback;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationResult;
import com.google.android.gms.location.LocationServices;
import com.google.android.gms.location.LocationSettingsRequest;
public class MyService extends Service {
private static final long UPDATE_INTERVAL_IN_MILLISECONDS = 3000;
private FusedLocationProviderClient mFusedLocationClient;
private LocationRequest locationRequest;
private LocationSettingsRequest locationSettingsRequest;
Notification notification;
NotificationCompat.Builder builder;
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
prepareNotification(intent);
startLocationUpdates();
return START_STICKY;
}
#Override
public void onCreate() {
super.onCreate();
initData();
}
//Location Callback
private LocationCallback locationCallback = new LocationCallback() {
#Override
public void onLocationResult(LocationResult locationResult) {
super.onLocationResult(locationResult);
Location currentLocation = locationResult.getLastLocation();
Log.d("Locations", currentLocation.getLatitude() + "," + currentLocation.getLongitude());
//Share/Publish Location
builder.setContentText(currentLocation.getLatitude() + "," + currentLocation.getLongitude());
Notification nm = builder.build();
startForeground(2, nm);
}
};
private void startLocationUpdates() {
mFusedLocationClient.requestLocationUpdates(this.locationRequest,
this.locationCallback, Looper.getMainLooper());
}
public void prepareNotification(Intent intent) {
String input = intent.getStringExtra("input");
Intent notificationIntent = new Intent(this, MyService.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this,
0, notificationIntent, 0);
builder = new NotificationCompat.Builder(this, MyChannel.CHANNEL_ID)
.setContentTitle("My notification")
.setContentText(input)
.setSmallIcon(R.drawable.ic_android_black_24dp)
.setContentIntent(pendingIntent);
notification = builder.build();
startForeground(1, notification);
}
#Override
public void onDestroy() {
super.onDestroy();
Intent broadcastIntent = new Intent();
broadcastIntent.setAction("restartservice");
broadcastIntent.setClass(this, Restarter.class);
this.sendBroadcast(broadcastIntent);
}
private void initData() {
locationRequest = LocationRequest.create();
locationRequest.setInterval(UPDATE_INTERVAL_IN_MILLISECONDS);
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
locationRequest.setNumUpdates(Integer.MAX_VALUE);
mFusedLocationClient = LocationServices.getFusedLocationProviderClient(getApplicationContext());
}
#Override
public void onTaskRemoved(Intent rootIntent){
Intent restartServiceIntent = new Intent(getApplicationContext(), this.getClass());
restartServiceIntent.setPackage(getPackageName());
PendingIntent restartServicePendingIntent = PendingIntent.getService(getApplicationContext(), 1, restartServiceIntent, PendingIntent.FLAG_ONE_SHOT);
AlarmManager alarmService = (AlarmManager) getApplicationContext().getSystemService(Context.ALARM_SERVICE);
alarmService.set(
AlarmManager.ELAPSED_REALTIME,
SystemClock.elapsedRealtime() + 10,
restartServicePendingIntent);
super.onTaskRemoved(rootIntent);
}
}
Channel.java
package com.app.testservices;
import android.app.Application;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.os.Build;
public class MyChannel extends Application {
public static final String CHANNEL_ID = "serviceChannel";
#Override
public void onCreate() {
super.onCreate();
createNotificationChannel();
}
private void createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel serviceChannel = new NotificationChannel(
CHANNEL_ID,
"Notification service",
NotificationManager.IMPORTANCE_DEFAULT
);
NotificationManager manager = getSystemService(NotificationManager.class);
manager.createNotificationChannel(serviceChannel);
}
}
}
I also tried to write a restarter to restart the service to fetch the location Restarter.java
package com.app.testservices;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.util.Log;
import android.widget.Toast;
public class Restarter extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Log.i("Broadcast Listened", "Service tried to stop");
Toast.makeText(context, "Service restarted", Toast.LENGTH_SHORT).show();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
context.startForegroundService(new Intent(context, MyService.class));
} else {
context.startService(new Intent(context, MyService.class));
}
}
}
Here is my MainActivity.java
package com.app.testservices;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import android.Manifest;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.IntentSender;
import android.content.pm.PackageManager;
import android.location.Location;
import android.location.LocationManager;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.os.Looper;
import android.provider.Settings;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import com.google.android.gms.common.api.ResolvableApiException;
import com.google.android.gms.location.FusedLocationProviderClient;
import com.google.android.gms.location.LocationCallback;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationResult;
import com.google.android.gms.location.LocationServices;
import com.google.android.gms.location.LocationSettingsRequest;
import com.google.android.gms.location.LocationSettingsResponse;
import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.Task;
public class MainActivity extends AppCompatActivity {
private EditText etInput;
protected static final int REQUEST_CHECK_SETTINGS = 0x1;
FusedLocationProviderClient mFusedLocationClient;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
etInput = findViewById(R.id.et_input_text);
if (ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
// TODO: Consider calling
// ActivityCompat#requestPermissions
ActivityCompat.requestPermissions(MainActivity.this, new String[]{
Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION
}, 1);
return;
}
}
public void startService(View view) {
String input = etInput.getText().toString();
Intent serviceIntent = new Intent(this, MyService.class);
serviceIntent.putExtra("input", input);
startService(serviceIntent);
}
public void stopService(View view) {
Intent serviceIntent = new Intent(this, MyService.class);
stopService(serviceIntent);
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
// If request is cancelled, the result arrays are empty.
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
mFusedLocationClient = LocationServices.getFusedLocationProviderClient(MainActivity.this);
if (ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
mFusedLocationClient.getLastLocation().addOnCompleteListener(new OnCompleteListener<Location>() {
#Override
public void onComplete(#NonNull Task<Location> task) {
Location location = task.getResult();
LocationCallback mLocationCallback = new LocationCallback() {
#Override
public void onLocationResult(LocationResult locationResult) {
Location mLastLocation = locationResult.getLastLocation();
}
};
if (location == null) {
LocationRequest mLocationRequest = new LocationRequest();
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
mLocationRequest.setInterval(5);
mLocationRequest.setFastestInterval(0);
mLocationRequest.setNumUpdates(2);
mFusedLocationClient = LocationServices.getFusedLocationProviderClient(MainActivity.this);
if (ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
// TODO: Consider calling
// ActivityCompat#requestPermissions
ActivityCompat.requestPermissions(MainActivity.this, new String[]{
Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION
}, 1);
return;
}
mFusedLocationClient.requestLocationUpdates(mLocationRequest, mLocationCallback, Looper.myLooper());
} else {
System.out.println("Location: " + location);
}
}
});
}
}
}
public void enableLocationSettings() {
LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
if (!locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
LocationRequest locationRequest = LocationRequest.create()
.setInterval(5)
.setFastestInterval(0)
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder().addLocationRequest(locationRequest);
LocationServices.getSettingsClient(this).checkLocationSettings(builder.build())
.addOnSuccessListener(this, (LocationSettingsResponse response) -> {
mFusedLocationClient = LocationServices.getFusedLocationProviderClient(MainActivity.this);
if (ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
mFusedLocationClient.getLastLocation().addOnCompleteListener(task -> {
Location location = task.getResult();
LocationCallback mLocationCallback = new LocationCallback() {
#Override
public void onLocationResult(LocationResult locationResult) {
Location mLastLocation = locationResult.getLastLocation();
}
};
if (location == null) {
LocationRequest mLocationRequest = new LocationRequest();
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
mLocationRequest.setInterval(5);
mLocationRequest.setFastestInterval(0);
mLocationRequest.setNumUpdates(2);
mFusedLocationClient = LocationServices.getFusedLocationProviderClient(MainActivity.this);
if (ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
// TODO: Consider calling
// ActivityCompat#requestPermissions
ActivityCompat.requestPermissions(MainActivity.this, new String[]{
Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION
}, 1);
return;
}
mFusedLocationClient.requestLocationUpdates(mLocationRequest, mLocationCallback, Looper.myLooper());
} else {
System.out.println("Location: " + location);
}
});
}
}).addOnFailureListener(this, ex -> {
if (ex instanceof ResolvableApiException) {
// Location settings are NOT satisfied, but this can be fixed by showing the user a dialog.
try {
startActivityForResult(new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS), 1);
ResolvableApiException resolvable = (ResolvableApiException) ex;
resolvable.startResolutionForResult(MainActivity.this, REQUEST_CHECK_SETTINGS);
} catch (IntentSender.SendIntentException sendEx) {
// Ignore the error.
}
}
});
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, #Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (REQUEST_CHECK_SETTINGS == requestCode) {
if (Activity.RESULT_OK == resultCode) {
}
}
}
}
Any help or guidance will be appreciated. Moreover,
I also tried Android How to get user location continuously even your app is killed
this but it didn't work for me.
You need to keep a foreground service always running. You need to start it when the app is in the foreground and then keep it running all the time even when the app is in the background.
You should use a Foreground Service with a partial wakelock, in order to prevent the phone from sleeping.
Here below an example of Foreground Service Class that implements a Wakelock:
public class ICService extends Service {
private static final int ID = 1; // The id of the notification
private NotificationCompat.Builder builder;
private NotificationManager mNotificationManager;
private PowerManager.WakeLock wakeLock; // PARTIAL_WAKELOCK
/**
* Returns the instance of the service
*/
public class LocalBinder extends Binder {
public ICService getServiceInstance(){
return ICService.this;
}
}
private final IBinder mBinder = new LocalBinder(); // IBinder
#Override
public void onCreate() {
super.onCreate();
// PARTIAL_WAKELOCK
PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE);
wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,"INSERT_YOUR_APP_NAME:wakelock");
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
startForeground(ID, getNotification());
return START_NOT_STICKY;
}
#SuppressLint("WakelockTimeout")
#Override
public IBinder onBind(Intent intent) {
if (wakeLock != null && !wakeLock.isHeld()) {
wakeLock.acquire();
}
return mBinder;
}
#Override
public void onDestroy() {
// PARTIAL_WAKELOCK
if (wakeLock != null && wakeLock.isHeld()) {
wakeLock.release();
}
super.onDestroy();
}
private Notification getNotification() {
final String CHANNEL_ID = "YOUR_SERVICE_CHANNEL";
builder = new NotificationCompat.Builder(this, CHANNEL_ID);
//builder.setSmallIcon(R.drawable.ic_notification_24dp)
builder.setSmallIcon(R.mipmap.YOUR_RESOURCE_ICON)
.setColor(getResources().getColor(R.color.colorPrimaryLight))
.setContentTitle(getString(R.string.app_name))
.setShowWhen(false)
.setPriority(NotificationCompat.PRIORITY_LOW)
.setCategory(NotificationCompat.CATEGORY_SERVICE)
.setOngoing(true)
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
.setContentText(composeContentText());
final Intent startIntent = new Intent(getApplicationContext(), ICActivity.class);
startIntent.setAction(Intent.ACTION_MAIN);
startIntent.addCategory(Intent.CATEGORY_LAUNCHER);
startIntent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
PendingIntent contentIntent = PendingIntent.getActivity(getApplicationContext(), 1, startIntent, 0);
builder.setContentIntent(contentIntent);
return builder.build();
}
}
Obviously you still have also to disable battery optimization for your app.
You can browse a real working example of this service on a GPS Logging app here.
Don't forget to declare your service type as "location" into your AndroidManifest.xml, in order to allow your application to receive the GPS updates also after a momentary signal loss when running in background, and to add the FOREGROUND_SERVICE and WAKE_LOCK permissions:
In your manifest you should declare:
...
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
...
<!-- Recommended for Android 9 (API level 28) and lower. -->
<!-- Required for Android 10 (API level 29) and higher. -->
<service
android:name="MyGPSService"
android:foregroundServiceType="location" ... >
</service>
...
As a note, if the location requests start when the app is in the foreground, you don't need to request the android.permission.ACCESS_BACKGROUND_LOCATION permission to continue to receive locations in background, also in case of momentary signal loss. the android.permission.ACCESS_FINE_LOCATION (and, if you target API31, also android.permission.ACCESS_COARSE_LOCATION) is enough for your use.

foreground location service with doze mode not working as expected

I have created a sample foreground service to check if it's possible to fetch location from background after every 15 mins or 30 mins. With introduction to doze mode alarm manager does not work at exact time.
In foreground service I have tried using handler post delay but that also does not work as I am getting intervals of upto 3 hrs. In the below code I have used ScheduledThreadPoolExecutor and it performed even worse. I got delay of upto 12 hours. I have tested this on android 6.0 as of now.
Can anyone suggest a work around for this?
package com.hitec16.foregroundservicetest;
import android.app.Notification;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.location.Location;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Looper;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.NotificationCompat;
import android.util.Log;
import android.widget.Toast;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.PendingResult;
import com.google.android.gms.common.api.Status;
import com.google.android.gms.location.FusedLocationProviderApi;
import com.google.android.gms.location.LocationListener;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationServices;
import java.text.DateFormat;
import java.util.Date;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class MyService extends Service
implements LocationListener, GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener {
private static final String TAG = "MyService";
private static final long INTERVAL = 1000 * 10;
private static final long FASTEST_INTERVAL = 1000 * 5;
private static final long WAIT_INTERVAL = 1000 * 30;
private ScheduledThreadPoolExecutor mExecutor;
private int mCounter = 0;
private FusedLocationProviderApi fusedLocationProviderApi = LocationServices.FusedLocationApi;
LocationRequest mLocationRequest;
GoogleApiClient mGoogleApiClient;
Location mCurrentLocation;
private String mLastUpdateTime;
public MyService() {
}
#Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
// throw new UnsupportedOperationException("Not yet implemented");
return null;
}
#Override
public void onCreate() {
super.onCreate();
}
#Override
public int onStartCommand(final Intent intent, final int flags, final int startId) {
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
Looper.prepare();
onStart_(intent, flags, startId);
Looper.loop();
}
});
thread.start();
// onStart_(intent,flags,startId);
return START_STICKY;
}
private void onStart_(Intent intent, int flags, int startId) {
if (intent.getAction().equals(Constants.STARTFOREGROUND_ACTION)) {
Logger.d("Received Start Foreground Intent ");
createLocationRequest();
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addApi(LocationServices.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
connectToGoogleApi();
showNotification();
Toast.makeText(getApplicationContext(), "Service Started!", Toast.LENGTH_SHORT).show();
Logger.d("work finished");
// fetchLocationAgain();
mExecutor = (ScheduledThreadPoolExecutor) Executors.newScheduledThreadPool(2);
mExecutor.scheduleWithFixedDelay(new Runnable() {
#Override
public void run() {
try {
startLocationUpdates();
} catch (Exception e) {
Log.d(getClass().getSimpleName(), "Exception caught: " + e.getMessage());
}
Log.d("Test", "test");
}
}, 30, 60 * 15, TimeUnit.SECONDS);
}
}
private void showNotification() {
Intent notificationIntent = new Intent(this, MainActivity.class);
notificationIntent.setAction(Constants.MAIN_ACTION);
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_CLEAR_TASK);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
notificationIntent, 0);
Notification notification = new NotificationCompat.Builder(this)
.setContentTitle("Fused Location Service")
.setTicker("ticker text")
.setContentText("My Location")
.setSmallIcon(R.mipmap.ic_launcher)
.setContentIntent(pendingIntent)
.setContentIntent(pendingIntent)
.setOngoing(true)
.build();
startForeground(Constants.NOTIFICATION_ID.FOREGROUND_SERVICE,
notification);
}
protected void createLocationRequest() {
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(INTERVAL);
mLocationRequest.setFastestInterval(FASTEST_INTERVAL);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
}
protected void stopLocationUpdates() {
LocationServices.FusedLocationApi.removeLocationUpdates(
mGoogleApiClient, MyService.this);
mCounter = 0;
Logger.d("Location update stopped .......................");
}
#Override
public void onConnected(#Nullable Bundle bundle) {
Logger.d("onConnected - isConnected ...............: " + mGoogleApiClient.isConnected());
try {
startLocationUpdates();
} catch (Exception e) {
Log.d(getClass().getSimpleName(), "Exception caught: " + e.getMessage());
}
}
#Override
public void onConnectionSuspended(int i) {
}
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
Logger.d("Connection failed: " + connectionResult.toString());
}
#Override
public void onLocationChanged(Location location) {
if (mCounter < 3) {
Log.d(getClass().getSimpleName(), "returned....");
mCounter++;
return;
}
Logger.d("Firing onLocationChanged..............................................");
mCurrentLocation = location;
mLastUpdateTime = DateFormat.getTimeInstance().format(new Date());
Logger.d("Location latitude and longitude :" + location.getLatitude() + " ," + location.getLongitude()
+ " , Accuracy : " + location.getAccuracy() + ", location provider : " + location.getProvider() + "Time : " + mLastUpdateTime);
stopLocationUpdates();
}
protected void startLocationUpdates() throws Exception {
PendingResult<Status> pendingResult = LocationServices.FusedLocationApi.requestLocationUpdates(
mGoogleApiClient, mLocationRequest, this, Looper.getMainLooper());
Logger.d("Location update started ..............: ");
}
#Override
public void onDestroy() {
disconnectFromGoogleApi();
Log.d(getClass().getSimpleName(), "on destroy called");
mExecutor.shutdown();
super.onDestroy();
}
private void connectToGoogleApi() {
Logger.d("connectToGoogleApi fired ..............");
mGoogleApiClient.connect();
}
private void disconnectFromGoogleApi() {
Logger.d("disConnectFromGoogleApi fired ..............");
mGoogleApiClient.disconnect();
}
}

Using IntentService instead of AsyncTask for Broadcast Receiver?

I am in the process of trying to get an email sent using BroadcastReceiver, the code is working correct using AsyncTask when using onClick but does not work when AlarmReceiver is being called.
Would it be better to use IntentService for this method? If so, what is the best way to write this?
Can anyone help with this problem? I am still new to java and want to help improve my knowledge. :)
Any help would be appreciated! Thank you!
AlarmReceiver.java
import android.app.Activity;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.support.v4.app.NotificationCompat;
import android.content.BroadcastReceiver;
import android.os.AsyncTask;
import android.util.Log;
import android.widget.Toast;
import static android.graphics.Color.GREEN;
public class AlarmReceiver extends BroadcastReceiver {
Context cxt;
Activity context;
#Override
public void onReceive(Context arg0, Intent arg1) {
cxt = arg0;
addNotification();
new SendMail().execute();
}
private class SendMail extends AsyncTask<String, Integer, Void> {
protected Void doInBackground(String... params) {
Mail m = new Mail("youremail#gmail.com", "password");
String[] toArr = {"toemail#outlook.com"};
m.setTo(toArr);
m.setFrom("fromemail#gmail.com");
m.setSubject("Achieve Alert!");
m.setBody("This is a reminder about your upcoming assignment or examination!");
try {
if(m.send()) {
Toast.makeText(context.getApplicationContext(), "Email was sent successfully.", Toast.LENGTH_LONG).show();
} else {
Toast.makeText(context.getApplicationContext(), "Email was not sent.", Toast.LENGTH_LONG).show();
}
} catch(Exception e) {
Log.e("MailApp", "Could not send email", e);
}
return null;
}
}
}
First start Intent service from Alarm manager :
private void setAlarm(Calendar targetCal){
/* HERE */ Intent intent = new Intent(getBaseContext(), AlarmService.class);
final int _id = (int) System.currentTimeMillis();
/* HERE */ PendingIntent pendingIntent = PendingIntent.getService(this,_id,intent,PendingIntent.FLAG_ONE_SHOT);
AlarmManager alarmManager = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
......
.....
Now Intent Service class:
public class AlarmService extends IntentService {
PowerManager powerManager;
PowerManager.WakeLock wakeLock;
public AlarmService() {
super("");
}
#Override
protected void onHandleIntent(Intent intent) {
powerManager = (PowerManager) getSystemService(POWER_SERVICE);
wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "FCFCFCFC");
wakeLock.acquire();
addNotification();
sendMAIL();
}
public void addNotification() {
NotificationCompat.Builder builder =
new NotificationCompat.Builder(getApplicationContext())
.setSmallIcon(R.drawable.icon_transperent)
.setLights(GREEN, 700, 700)
.setContentTitle("Achieve - Alert!")
.setContentText("This is a reminder for your deadline!");
Intent notificationIntent = new Intent(getApplicationContext(), MainMenu.class);
PendingIntent contentIntent = PendingIntent.getActivity(getApplicationContext(), 0, notificationIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
builder.setContentIntent(contentIntent);
// Add as notification
NotificationManager manager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
builder.setVibrate(new long[] { 0, 1000, 1000, 1000, 1000 });
manager.notify(0, builder.build());
}
public void sendMAIL(){
Mail m = new Mail("youremail#gmail.com", "password");
String[] toArr = {"toemail#outlook.com"};
m.setTo(toArr);
m.setFrom("fromemail#gmail.com");
m.setSubject("Achieve Alert!");
m.setBody("This is a reminder about your upcoming assignment or examination!");
try {
if(m.send()) {
Toast.makeText(getApplicationContext(), "Email was sent successfully.", Toast.LENGTH_LONG).show();
} else {
Toast.makeText(getApplicationContext(), "Email was not sent.", Toast.LENGTH_LONG).show();
}
} catch(Exception e) {
Log.e("MailApp", "Could not send email", e);
}
wakeLock.release();
}
#Override
public void onDestroy() {
super.onDestroy();
}
}
Now, Manifest add:
<uses-permission android:name="com.android.alarm.permission.SET_ALARM"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<service android:name=".AlarmService" android:exported="true" android:enabled="true"/>

Lock Screen Player Controls and Meta Data

I'm trying to use MediaSessionCompat in order to add lock screen player controls and meta data for my app. Everything I tried doesn't work. The lock screen doesn't show any controls or meta data while playing. Please see my current code below and any help is appreciated.
StreamService.java:
public class StreamService extends Service implements MediaPlayer.OnCuePointReceivedListener, MediaPlayer.OnStateChangedListener,
MediaPlayer.OnInfoListener, AudioManager.OnAudioFocusChangeListener {
private WifiManager.WifiLock wifiLock;
private static String LOG_TAG = "StreamService";
public static final String BROADCAST_PLAYER_STATE = "com.test.BROADCAST_PLAYER_STATE";
public static final String BROADCAST_PLAYER_META = "com.test.BROADCAST_PLAYER_META";
public static final String BROADCAST_PLAYER_ALBUM = "com.test.BROADCAST_PLAYER_ALBUM";
public static final int NOTIFICATION_ID = 999999;
private MediaSessionCompat mediaSession;
private boolean audioInterrupted = false;
public StreamService() {
}
#Override
public void onCreate(){
super.onCreate();
setupMediaPlayer();
setupMediaSession();
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public boolean onUnbind(Intent intent){
releasePlayer();
return false;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_NOT_STICKY;
}
private void setupMediaPlayer() {
// Recreate player
Bundle playerSettings = (BrandedApplication.getContext().getmTritonPlayer() == null) ? null : BrandedApplication.getContext().getmTritonPlayer().getSettings();
Bundle inputSettings = createPlayerSettings();
if (!Utility.bundleEquals(inputSettings, playerSettings)) {
releasePlayer();
createPlayer(inputSettings);
}
// Start the playback
play();
}
private void setupMediaSession() {
ComponentName receiver = new ComponentName(getPackageName(), RemoteReceiver.class.getName());
mediaSession = new MediaSessionCompat(this, "StreamService", receiver, null);
mediaSession.setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS |
MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS);
mediaSession.setPlaybackState(new PlaybackStateCompat.Builder()
.setState(PlaybackStateCompat.STATE_PAUSED, 0, 0)
.setActions(PlaybackStateCompat.ACTION_PLAY_PAUSE | PlaybackStateCompat.ACTION_PLAY | PlaybackStateCompat.ACTION_PAUSE)
.build());
mediaSession.setMetadata(new MediaMetadataCompat.Builder()
.putString(MediaMetadataCompat.METADATA_KEY_ARTIST, "Test Artist")
.putString(MediaMetadataCompat.METADATA_KEY_ALBUM, "Test Album")
.putString(MediaMetadataCompat.METADATA_KEY_TITLE, "Test Track Name")
.putLong(MediaMetadataCompat.METADATA_KEY_DURATION, 10000)
.putBitmap(MediaMetadataCompat.METADATA_KEY_ALBUM_ART,
BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher))
//.putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_TITLE, "Test Artist")
.build());
AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
audioManager.requestAudioFocus(new AudioManager.OnAudioFocusChangeListener() {
#Override
public void onAudioFocusChange(int focusChange) {
// Ignore
}
}, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
mediaSession.setActive(true);
}
synchronized private void play() {
audioInterrupted = false;
BrandedApplication.getContext().getmTritonPlayer().play();
if(wifiLock != null) {
wifiLock.acquire();
}
if(mediaSession != null) {
mediaSession.setPlaybackState(new PlaybackStateCompat.Builder()
.setState(PlaybackStateCompat.STATE_PLAYING, 0, 1.0f)
.setActions(PlaybackStateCompat.ACTION_PLAY_PAUSE).build());
}
}
synchronized private void stop() {
BrandedApplication.getContext().getmTritonPlayer().stop();
if(wifiLock != null) {
wifiLock.release();
}
if(mediaSession != null) {
mediaSession.setPlaybackState(new PlaybackStateCompat.Builder()
.setState(PlaybackStateCompat.STATE_PAUSED, 0, 0.0f)
.setActions(PlaybackStateCompat.ACTION_PLAY_PAUSE).build());
}
}
private void createPlayer(Bundle settings)
{
BrandedApplication.getContext().setmTritonPlayer(new TritonPlayer(this, settings));
wifiLock = ((WifiManager) getSystemService(Context.WIFI_SERVICE))
.createWifiLock(WifiManager.WIFI_MODE_FULL, "mylock");
AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
int result = audioManager.requestAudioFocus(this, AudioManager.STREAM_MUSIC,
AudioManager.AUDIOFOCUS_GAIN);
BrandedApplication.getContext().getmTritonPlayer().setOnCuePointReceivedListener(this);
BrandedApplication.getContext().getmTritonPlayer().setOnInfoListener(this);
BrandedApplication.getContext().getmTritonPlayer().setOnStateChangedListener(this);
}
protected void releasePlayer() {
if (BrandedApplication.getContext().getmTritonPlayer() != null) {
if(BrandedApplication.getContext().isPlaying()) {
stop();
}
BrandedApplication.getContext().getmTritonPlayer().release();
BrandedApplication.getContext().setmTritonPlayer(null);
}
stopForeground(true);
}
protected Bundle createPlayerSettings() {
// Player Settings
Bundle settings = new Bundle();
// AAC
settings.putString(TritonPlayer.SETTINGS_STATION_MOUNT, getResources().getString(R.string.station_stream_mount) + "AAC");
// MP3
//settings.putString(TritonPlayer.SETTINGS_STATION_MOUNT, mountID);
settings.putString(TritonPlayer.SETTINGS_STATION_BROADCASTER, getResources().getString(R.string.app_name));
settings.putString(TritonPlayer.SETTINGS_STATION_NAME, getResources().getString(R.string.app_name));
return settings;
}
#Override
public void onCuePointReceived(MediaPlayer mediaPlayer, Bundle bundle) {
//System.out.println("TRITON PLAYER BUNDLE " + bundle);
String trackName = "";
String artistName = "";
if(bundle != null) {
if(bundle.containsKey("cue_title") && bundle.containsKey("track_artist_name")) {
if (!bundle.getString("cue_title").isEmpty()) {
trackName = bundle.getString("cue_title");
}
if (!bundle.getString("track_artist_name").isEmpty()) {
artistName = bundle.getString("track_artist_name");
}
}
}
// broadcast out the meta data
Intent i = new Intent(BROADCAST_PLAYER_META);
i.putExtra("trackName", trackName);
i.putExtra("artistName", artistName);
sendBroadcast(i);
// send notification and start as foreground service
PendingIntent pi = PendingIntent.getActivity(getApplicationContext(), 0, new Intent(getApplicationContext(), MainActivity.class), PendingIntent.FLAG_UPDATE_CURRENT);
Bitmap icon = BitmapFactory.decodeResource(getResources(),
R.drawable.logo);
String tickerString = "";
String contentString = "Playing";
if(!artistName.isEmpty() && !trackName.isEmpty()) {
tickerString = artistName + " - " + trackName;
contentString += ": " + artistName + " - " + trackName;
}
Intent pauseIntent = new Intent(BROADCAST_PLAYER_PAUSE);
PendingIntent pausePendingIntent = PendingIntent.getBroadcast(this, 0, pauseIntent, 0);
NotificationCompat.Builder notification = new NotificationCompat.Builder(this)
.setContentTitle(getResources().getString(R.string.app_name))
.setTicker(tickerString)
.setContentText(contentString)
.setSmallIcon(R.drawable.ic_launcher)
//.setAutoCancel(true)
//.setLargeIcon(
// Bitmap.createScaledBitmap(icon, 128, 128, false))
.addAction(R.drawable.ic_media_pause, "Pause", pausePendingIntent)
.setContentIntent(pi)
.setStyle(new android.support.v7.app.NotificationCompat.MediaStyle()
//.setShowActionsInCompactView(0)
.setMediaSession(mediaSession.getSessionToken()))
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
.setOngoing(true);
//notification.setPriority(Notification.PRIORITY_MIN);
notification.setPriority(Notification.PRIORITY_DEFAULT);
startForeground(NOTIFICATION_ID, notification.build());
}
#Override
public void onInfo(MediaPlayer mediaPlayer, int i, int i1) {
}
#Override
public void onStateChanged(MediaPlayer mediaPlayer, int state) {
Log.i(LOG_TAG, "onStateChanged: " + TritonPlayer.debugStateToStr(state));
// broadcast out the player state
Intent i = new Intent(BROADCAST_PLAYER_STATE);
i.putExtra("state", state);
sendBroadcast(i);
}
#Override
public void onAudioFocusChange(int focusChange) {
switch (focusChange) {
case AudioManager.AUDIOFOCUS_GAIN:
// resume playback
System.out.println("AUDIO FOCUS GAIN");
if(audioInterrupted) {
audioInterrupted = false;
if (BrandedApplication.getContext().getmTritonPlayer() == null) {
setupMediaPlayer();
} else if (!BrandedApplication.getContext().isPlaying()) {
setupMediaPlayer();
}
}
break;
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
case AudioManager.AUDIOFOCUS_LOSS:
System.out.println("AUDIO FOCUS LOSS");
// Lost focus for an unbounded amount of time: stop playback and release media player
if (BrandedApplication.getContext().isPlaying()) {
audioInterrupted = true;
releasePlayer();
}
break;
}
}
#Override
public void onDestroy() {
System.out.println("SERVICE STOPPED");
releasePlayer();
mediaSession.release();
}
}
And here's RemoteReceiver.java:
public class RemoteReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (Intent.ACTION_MEDIA_BUTTON.equals(intent.getAction())) {
final KeyEvent event = intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT);
if (event != null && event.getAction() == KeyEvent.ACTION_DOWN) {
switch (event.getKeyCode()) {
case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
context.startService(new Intent(context, StreamService.class));
break;
}
}
}
}
}
Okay, from the additional information you provided, I believe I know what the issue is. In Android 5.0 Lock Screen Controls were removed. They are now implemented via the Notification API. So try adding the following to your notification builder.
notification.setStyle(new NotificationCompat.MediaStyle()
.setShowActionsInCompactView(0)
.setMediaSession(mediaSession));
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
That should place it on your lock screen. I would also suggest changing the Notification.PRIORITY_DEFAULT as well as include an action to your notification otherwise you won't be able to control the playback.
I know this post is late but if anyone is still facing the issue.This will show up in your lock screen also.
Here is the code for notification builder class-
import android.annotation.SuppressLint;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.graphics.BitmapFactory;
import android.media.MediaPlayer;
import android.media.session.MediaSessionManager;
import android.os.Build;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.annotation.RequiresApi;
import android.support.v4.app.NotificationCompat;
import android.support.v4.media.session.MediaControllerCompat;
import android.support.v4.media.session.MediaSessionCompat;
import android.util.Log;
import org.json.JSONException;
public class MediaPlayerService extends Service {
private static final String CHANNEL_ID = "my_channel_01";
public static final String ACTION_PLAY = "action_play";
public static final String ACTION_PAUSE = "action_pause";
public static final String ACTION_NEXT = "action_next";
public static final String ACTION_PREVIOUS = "action_previous";
public static final String ACTION_STOP = "action_stop";
public static final String ACTION_NOTHING = "action_previous";
private NotificationManager notificationManager;
NotificationManager mNotificationManager;
private MediaPlayer mMediaPlayer;
private MediaSessionManager mManager;
private MediaSessionCompat mSession;
private MediaControllerCompat mController;
private MediaPlayerService mService;
String title = null;
String description = null;
#Override
public IBinder onBind(Intent intent) {
return null;
}
private void handleIntent(Intent intent) {
if (intent == null || intent.getAction() == null)
return;
String action = intent.getAction();
if (action.equalsIgnoreCase(ACTION_PLAY)) {
mController.getTransportControls().play();
} else if (action.equalsIgnoreCase(ACTION_PAUSE)) {
mController.getTransportControls().pause();
} else if (action.equalsIgnoreCase(ACTION_PREVIOUS)) {
mController.getTransportControls().skipToPrevious();
} else if (action.equalsIgnoreCase(ACTION_NEXT)) {
mController.getTransportControls().skipToNext();
} else if (action.equalsIgnoreCase(ACTION_STOP)) {
mController.getTransportControls().stop();
}
}
private NotificationCompat.Action generateAction(int icon, String title, String intentAction) {
Intent intent = new Intent(getApplicationContext(), MediaPlayerService.class);
intent.setAction(intentAction);
PendingIntent pendingIntent = PendingIntent.getService(getApplicationContext(), 1, intent, 0);
return new NotificationCompat.Action.Builder(icon, title, pendingIntent).build();
}
#SuppressLint("ServiceCast")
private void buildNotification(NotificationCompat.Action action) {
title = ""; // add variable to get current playing song title here
description =""; // add variable to get current playing song description here
Intent notificationIntent = new Intent(getApplicationContext(), HomeActivity.class); //specify which activity should be opened when widget is clicked (other than buttons)
PendingIntent contentIntent = PendingIntent.getActivity(getApplicationContext(), 0, notificationIntent, 0);
notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
// Notification channels are only supported on Android O+.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
{
//method to create channel if android version is android. Descrition below
createNotificationChannel();
}
Intent intent = new Intent(getApplicationContext(), MediaPlayerService.class);
intent.setAction(ACTION_STOP);
PendingIntent pendingIntent = PendingIntent.getService(getApplicationContext(), 1, intent, 0);
final NotificationCompat.Builder builder;
//condition to check if music is playing
//if music is playing widget cant be dismissed on swipe
if(<add your method to check play status here>)
{
builder = new NotificationCompat.Builder(this, CHANNEL_ID)
.setSmallIcon(R.drawable.logo2b)
.setLargeIcon(BitmapFactory.decodeResource(getApplication().getResources(), R.mipmap.ic_launcher))
.setContentTitle(title)
.setContentText(description)
.setDeleteIntent(pendingIntent)
.setContentIntent(contentIntent)
.setChannelId(CHANNEL_ID)
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
.setOnlyAlertOnce(true)
.setColor(getResources().getColor(R.color.colorPrimary))
.setOngoing(true) //set this to true if music is playing widget cant be dismissed on swipe
.setStyle(new android.support.v4.media.app.NotificationCompat.MediaStyle()
// show only play/pause in compact view
.setShowActionsInCompactView(0, 1, 2));
}
//else if music is not playing widget can be dismissed on swipe
else
{
builder = new NotificationCompat.Builder(this, CHANNEL_ID)
.setSmallIcon(R.drawable.logo2b)
.setLargeIcon(BitmapFactory.decodeResource(getApplication().getResources(), R.mipmap.ic_launcher))
.setContentTitle(title)
.setContentText(description)
.setDeleteIntent(pendingIntent)
.setContentIntent(contentIntent)
.setChannelId(CHANNEL_ID)
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
.setOnlyAlertOnce(true)
.setColor(getResources().getColor(R.color.colorPrimary))
.setStyle(new android.support.v4.media.app.NotificationCompat.MediaStyle()
// show only play/pause in compact view
.setShowActionsInCompactView(0, 1, 2));
}
builder.addAction(generateAction(R.drawable.ic_skip_previous_white_24dp, "Previous", ACTION_PREVIOUS));
builder.addAction(action);
builder.addAction(generateAction(R.drawable.ic_skip_next_white_24dp, "Next", ACTION_NEXT));
//style.setShowActionsInCompactView(0,1,2);
// builder.setColor(getResources().getColor(R.color.app_orange_color));
notificationManager.notify(1, builder.build());
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (mManager == null) {
try {
initMediaSessions();
} catch (RemoteException e) {
e.printStackTrace();
}
}
handleIntent(intent);
return super.onStartCommand(intent, flags, startId);
}
private void initMediaSessions() throws RemoteException {
mMediaPlayer = new MediaPlayer();
mSession = new MediaSessionCompat(getApplicationContext(), "simple player session");
mController = new MediaControllerCompat(getApplicationContext(), mSession.getSessionToken());
mSession.setCallback(new MediaSessionCompat.Callback() {
#Override
public void onPlay() {
super.onPlay();
//add you code for play button click here
//replace your drawable id that shows pauseicon buildNotification(generateAction(R.drawable.uamp_ic_pause_white_24dp, "Pause", ACTION_PAUSE));
}
#Override
public void onPause() {
super.onPause();
//add you code for pause button click here
//replace your drawable id that shows play icon buildNotification(generateAction(R.drawable.uamp_ic_play_arrow_white_24dp, "Play", ACTION_PLAY));
}
#Override
public void onSkipToNext() {
super.onSkipToNext();
//add you code for next button click here
buildNotification(generateAction(R.drawable.uamp_ic_pause_white_24dp, "Pause", ACTION_PAUSE));
}
#Override
public void onSkipToPrevious() {
super.onSkipToPrevious();
//add you code for previous button click here
buildNotification(generateAction(R.drawable.uamp_ic_pause_white_24dp, "Pause", ACTION_PAUSE));
}
#Override
public void onStop() {
super.onStop();
Log.e("MediaPlayerService", "onStop");
//Stop media player and dismiss widget here
NotificationManager notificationManager = (NotificationManager) getApplicationContext().getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.cancel(1);
Intent intent = new Intent(getApplicationContext(), MediaPlayerService.class);
stopService(intent);
}
#Override
public void onSeekTo(long pos) {
super.onSeekTo(pos);
}
}
);
}
#Override
public boolean onUnbind(Intent intent) {
mSession.release();
return super.onUnbind(intent);
}
//method to create notification channel on android Oreo and above
#RequiresApi(Build.VERSION_CODES.O)
private void createNotificationChannel() {
int notifyID = 1;
CharSequence name = "Player Widget";// The user-visible name of the channel. This channel name will be shown in settings.
if (notificationManager.getNotificationChannel(CHANNEL_ID) == null) {
NotificationChannel notificationChannel =
new NotificationChannel(CHANNEL_ID, name, NotificationManager.IMPORTANCE_LOW);
notificationManager.createNotificationChannel(notificationChannel);
}
}
}
And fire these intents for actions to update widget when play status is changed from within the app:
Play-
//to change widgets current action button to play
Intent intent = new Intent(getApplicationContext(), MediaPlayerService.class);
intent.setAction(MediaPlayerService.ACTION_PAUSE);
startService(intent);
Pause-
//to change widgets current action button to pause
Intent intent = new Intent(getApplicationContext(), MediaPlayerService.class);
intent.setAction(MediaPlayerService.ACTION_PLAY);
startService(intent);
Excuse me if there are any unwanted import.All the best.

Android location api not working

I'm trying to acquire GPS coordinates on my android application.
Criteria criteria = new Criteria();
criteria.setAltitudeRequired(false);
criteria.setAccuracy(Criteria.ACCURACY_FINE);
criteria.setBearingRequired(false);
criteria.setCostAllowed(false);
criteria.setPowerRequirement(Criteria.POWER_HIGH);
LocationManager locationManager =
(LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
Intent i = new Intent(context, IntentListener.class);
i.setAction(Actions.ACTION_UPDATE_LOCATION);
PendingIntent pi = PendingIntent.getBroadcast(
context, 0, i, PendingIntent.FLAG_UPDATE_CURRENT);
String provider = locationManager.getBestProvider(criteria, true);
if (provider == null) return;
locationManager.requestLocationUpdates(provider, 90 * 1000, 30, pi);
and here's receiving code.
Intent service = new Intent(context, WorkerService.class);
service.setAction(Actions.ACTION_UPDATE_LOCATION);
Location location = (Location) intent.getExtras().get(
LocationManager.KEY_LOCATION_CHANGED);
if (location == null) { // <-- Always true
return;
}
service.putExtra("lat", location.getLatitude());
service.putExtra("lon", location.getLongitude());
context.startService(service);
As you can see, I'm unable to obtain Location instance by calling intent.getExtras()... etc. Returned value is always null. I'm testing on my emulator running android 4.1.2 and telnet client, using geo fix longitude latitude. Anyone knows what's wrong? Thanks.
P.S. Manifest contains all required permissions and GPS is enabled in the emulator.
P.P.S. This application is a corporate app, that runs as a service, without UI and should collect GPS coordinates.
You casually mentioned that you're testing on an emulator. The emulator doesn't receive mock locations by itself; you have to specifically send them through the DDMS interface.
Additionally, due to a bug in the emulator, the time offset in incoming locations is set to midnight, so your location criteria will likely not match it.
I strongly suggest you test with a physical device to confirm that the problem is still occurring.
Use the new Location API.
You'd have to include Google Play services into your project.
Add this in onCreate:
mIntentService = new Intent(this,LocationService.class);
mPendingIntent = PendingIntent.getService(this, 1, mIntentService, 0);
int resp =GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
if(resp == ConnectionResult.SUCCESS){
locationclient = new LocationClient(this,this,this);
locationclient.connect();
}
And you'd have to override these methods:
#Override
protected void onDestroy() {
super.onDestroy();
if(locationclient!=null)
locationclient.disconnect();
}
#Override
public void onConnected(Bundle connectionHint) {
Log.i(TAG, "onConnected");
//to get last location
Location loc =locationclient.getLastLocation();
//to get updates via service
locationrequest = LocationRequest.create();
locationrequest.setInterval(100);
locationclient.requestLocationUpdates(locationrequest, mPendingIntent);
}
#Override
public void onDisconnected() {
Log.i(TAG, "onDisconnected");
}
#Override
public void onConnectionFailed(ConnectionResult result) {
Log.i(TAG, "onConnectionFailed");
}
#Override
public void onLocationChanged(Location location) {
if(location!=null){
Log.i(TAG, "Location Request :" + location.getLatitude() + "," + location.getLongitude());
}
}
Here's the service where I'm creating a notification for every new location, you can remove that and update location there.
public class LocationService extends IntentService {
private String TAG = this.getClass().getSimpleName();
public LocationService() {
super("Fused Location");
}
public LocationService(String name) {
super("Fused Location");
}
#Override
protected void onHandleIntent(Intent intent) {
Location location = intent.getParcelableExtra(LocationClient.KEY_LOCATION_CHANGED);
if(location !=null){
Log.i(TAG, "onHandleIntent " + location.getLatitude() + "," + location.getLongitude());
NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
Builder noti = new NotificationCompat.Builder(this);
noti.setContentTitle("Fused Location");
noti.setContentText(location.getLatitude() + "," + location.getLongitude());
noti.setSmallIcon(R.drawable.ic_launcher);
notificationManager.notify(1234, noti.build());
}
}
}
Follow the tutorial to get the location in Android app
You should take your location by implementing LocationListener
#Override
public void onLocationChanged(Location loc) {
}
Take a look at this implementation, works really nice and i have tested it on several devices.
package ro.gebs.captoom.activities;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.location.Address;
import android.location.Geocoder;
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.Window;
import android.view.WindowManager;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.Toast;
import com.bugsense.trace.BugSenseHandler;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;
import java.io.IOException;
import java.util.List;
import java.util.Locale;
import ro.gebs.captoom.R;
import ro.gebs.captoom.database.ReceiptDataSource;
import ro.gebs.captoom.utils.Constants;
import ro.gebs.captoom.utils.Utils;
public class LocationActivity extends FragmentActivity {
private GoogleMap map;
private long rec_id;
private String address;
private Marker selectedLoc;
private boolean isSessionClosed;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
requestWindowFeature(Window.FEATURE_NO_TITLE);
BugSenseHandler.initAndStartSession(this, Constants.BugSenseKEY);
setContentView(R.layout.preview_location);
RelativeLayout cancel_btn = (RelativeLayout) findViewById(R.id.cancel_btn);
LinearLayout save_location_btn = (LinearLayout) findViewById(R.id.delete_btn);
save_location_btn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
if (address != null) {
ReceiptDataSource r = new ReceiptDataSource();
r.updateReceiptLocation(rec_id, address);
Intent returnIntent = new Intent(getBaseContext(), EditReceiptActivity.class);
returnIntent.putExtra("result", address);
setResult(RESULT_OK, returnIntent);
finish();
} else {
Utils.showToast(getApplicationContext(), getString(R.string.c_unknownLocation), Toast.LENGTH_SHORT);
}
}
});
cancel_btn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
onBackPressed();
}
});
if (map == null) {
map = ((SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map)).getMap();
if (isGoogleMapsInstalled()) {
if (map != null) {
retrieveLocation();
}
} else {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage("Install Google Maps");
builder.setCancelable(false);
builder.setPositiveButton("Install", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialogInterface, int i) {
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=com.google.android.apps.maps"));
startActivity(intent);
finish();
}
});
AlertDialog dialog = builder.create();
dialog.show();
}
}
}
#Override
protected void onResume() {
super.onResume();
if (isSessionClosed) {
BugSenseHandler.startSession(this);
isSessionClosed = false;
}
}
#Override
protected void onPause() {
super.onPause();
BugSenseHandler.closeSession(this);
isSessionClosed = true;
}
#Override
public void onBackPressed() {
map.clear();
super.onBackPressed();
}
private void retrieveLocation() {
Intent intent = getIntent();
address = intent.getStringExtra("location");
assert address != null;
if (address.equalsIgnoreCase("")) {
address = Utils.getCurrentLocation(LocationActivity.this);
}
rec_id = intent.getLongExtra("receipt_to_update_location", 0);
final Geocoder geocoder = new Geocoder(this, Locale.US);
double latitude = 0, longitude = 0;
try {
List<Address> loc = geocoder.getFromLocationName(address, 5);
if (loc.size() > 0) {
latitude = loc.get(0).getLatitude();
longitude = loc.get(0).getLongitude();
} else {
Utils.showToast(LocationActivity.this, getString(R.string.UnableToFindLocation), Toast.LENGTH_SHORT);
}
selectedLoc = map.addMarker(new MarkerOptions().position(new LatLng(latitude, longitude)).title(address).draggable(true));
map.setOnMarkerDragListener(new GoogleMap.OnMarkerDragListener() {
#Override
public void onMarkerDragStart(Marker marker) {
}
#Override
public void onMarkerDrag(Marker marker) {
}
#Override
public void onMarkerDragEnd(Marker marker) {
try {
List<Address> addresses = geocoder.getFromLocation(selectedLoc.getPosition().latitude, selectedLoc.getPosition().longitude, 1);
StringBuilder sb = new StringBuilder();
if (addresses.size() > 0) {
Address address = addresses.get(0);
if (address.getAddressLine(0) != null)
sb.append(address.getAddressLine(0)).append(", ");
if (address.getLocality() != null)
sb.append(address.getLocality()).append(", ");
if (address.getCountryName() != null)
sb.append(address.getCountryName());
}
address = sb.toString();
} catch (IOException e) {
}
}
});
map.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(latitude, longitude), 12));
// Zoom in, animating the camera.
map.animateCamera(CameraUpdateFactory.zoomTo(12), 2000, null);
} catch (IOException e) {
Log.e("IOException", e.getMessage());
Utils.showToast(LocationActivity.this, getString(R.string.c_unknownLocation), Toast.LENGTH_LONG);
}
}
public boolean isGoogleMapsInstalled() {
try {
getPackageManager().getApplicationInfo("com.google.android.apps.maps", 0);
return true;
} catch (PackageManager.NameNotFoundException e) {
return false;
}
}
}
I see you implement the intent.putExtra after you get the extra! You should do the put in the activity that receives the location data and when you want to receive the data from the intent.extra you should do this:
Bundle extras = getIntent().getExtras();
if (extras != null) {
latitude= (double)extras.getDouble("lat");
longitude=(double)extras.getDouble("lon");
}

Categories

Resources