问题
I am not able to add geofence from service class. Below is my code:
GeoFenceService:
package com.example.admin.reminderapp.services;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
import android.support.annotation.NonNull;
import android.util.Log;
import android.widget.Toast;
import com.example.admin.reminderapp.R;
import com.example.admin.reminderapp.database.model.Reminder;
import com.example.admin.reminderapp.geofencing.Constants;
import com.example.admin.reminderapp.geofencing.GeofenceErrorMessages;
import com.example.admin.reminderapp.geofencing.GeofenceTransitionsIntentService;
import com.google.android.gms.common.ConnectionResult;
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.LocationServices;
import java.util.ArrayList;
import java.util.List;
public class GeoFenceService extends Service implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener {
private Context mContext = this;
private IBinder mIBinder = new LocalBinder();
private GoogleApiClient mGoogleApiClient;
public GeoFenceService() {
Log.i(getClass().getName(), "GeoFenceService()");
}
@Override
public IBinder onBind(Intent intent) {
return mIBinder;
}
protected synchronized void buildGoogleApiClient() {
Log.i("GeoFenceService", "buildGoogleApiClient");
mGoogleApiClient = new GoogleApiClient.Builder(mContext)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
mGoogleApiClient.connect();
}
@Override
public void onCreate() {
super.onCreate();
Log.i("GeoFenceService", "onCreate");
buildGoogleApiClient();
}
@Override
public void onConnected(Bundle connectionHint) {
Log.i("GeoFenceService", "Connected to GoogleApiClient");
}
@Override
public void onConnectionFailed(ConnectionResult result) {
Log.e("GeoFenceService", "Connection failed: ConnectionResult.getErrorCode() = " + result.getErrorCode());
}
@Override
public void onConnectionSuspended(int cause) {
Log.i("GeoFenceService", "Connection suspended");
}
private GeofencingRequest getGeofencingRequest(long reminderId) {
GeofencingRequest.Builder builder = new GeofencingRequest.Builder();
builder.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER);
builder.addGeofences(populateGeofenceList(reminderId));
return builder.build();
}
public List<Geofence> populateGeofenceList(long reminderId) {
List<Geofence> geofenceList = new ArrayList<>();
Reminder reminder = Reminder.load(Reminder.class, reminderId);
Log.i("ReminderService", reminder.getId()+" - "+reminder.toString());
Geofence geofence = new Geofence.Builder()
.setRequestId(String.valueOf(reminderId))
.setCircularRegion(
reminder.getLat(),
reminder.getLat(),
(float) reminder.getKm() * 1000
)
.setExpirationDuration(Geofence.NEVER_EXPIRE)
.setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER |
Geofence.GEOFENCE_TRANSITION_EXIT)
.build();
geofenceList.add(geofence);
return geofenceList;
}
private PendingIntent getGeofencePendingIntent(long reminderId) {
Intent intent = new Intent(this, GeofenceTransitionsIntentService.class);
Log.i("ReminderService", intent +"");
// intent.putExtra("ReminderId", reminderId);
return PendingIntent.getService(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
}
public void addGeofence(long reminderId) {
if (!mGoogleApiClient.isConnected()) {
Toast.makeText(this, getString(R.string.not_connected), Toast.LENGTH_SHORT).show();
return;
}
try {
LocationServices.GeofencingApi.addGeofences(
mGoogleApiClient,
getGeofencingRequest(reminderId),
getGeofencePendingIntent(reminderId)
).setResultCallback(new ResultCallback<Status>() {
@Override
public void onResult(@NonNull Status status) {
if (status.isSuccess()) {
Toast.makeText(
mContext,
"Reminder Added.",
Toast.LENGTH_SHORT
).show();
} else {
String errorMessage = GeofenceErrorMessages.getErrorString(GeoFenceService.this, status.getStatusCode());
Log.e(GeoFenceService.this.getClass().getName(), errorMessage);
}
}
});
} catch (SecurityException securityException) {
Log.e(getClass().getName(), "Invalid location permission. You need to use ACCESS_FINE_LOCATION with geofences");
securityException.printStackTrace();
}
}
public void removeGeofence(long reminderId) {
if (!mGoogleApiClient.isConnected()) {
Toast.makeText(this, getString(R.string.not_connected), Toast.LENGTH_SHORT).show();
return;
}
try {
LocationServices.GeofencingApi.removeGeofences(
mGoogleApiClient,
getGeofencePendingIntent(reminderId)
).setResultCallback(new ResultCallback<Status>() {
@Override
public void onResult(@NonNull Status status) {
if (status.isSuccess()) {
Toast.makeText(
mContext,
"Reminder Removed.",
Toast.LENGTH_SHORT
).show();
} else {
String errorMessage = GeofenceErrorMessages.getErrorString(GeoFenceService.this,
status.getStatusCode());
Log.e(GeoFenceService.this.getClass().getName(), errorMessage);
}
}
});
} catch (SecurityException securityException) {
Log.e(getClass().getName(), "Invalid location permission. You need to use ACCESS_FINE_LOCATION with geofences");
securityException.printStackTrace();
}
}
@Override
public void onDestroy() {
super.onDestroy();
mGoogleApiClient.disconnect();
}
public class LocalBinder extends Binder {
public GeoFenceService getService() {
return GeoFenceService.this;
}
}
}
GeoFenceTransitionIntentService:
package com.example.admin.reminderapp.geofencing;
import android.app.IntentService;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.BitmapFactory;
import android.media.RingtoneManager;
import android.net.Uri;
import android.support.v4.app.NotificationCompat;
import android.support.v4.app.TaskStackBuilder;
import android.text.TextUtils;
import android.util.Log;
import com.example.admin.reminderapp.R;
import com.example.admin.reminderapp.activity.HomeActivity;
import com.google.android.gms.location.Geofence;
import com.google.android.gms.location.GeofencingEvent;
import java.util.ArrayList;
import java.util.List;
/**
* An {@link IntentService} subclass for handling asynchronous task requests in
* a service on a separate handler thread.
* <p/>
* TODO: Customize class - update intent actions, extra parameters and static
* helper methods.
*/
public class GeofenceTransitionsIntentService extends IntentService {
protected static final String TAG = "GeofenceTransitionsIS";
Boolean isMessageTone, isMessageVibrate;
String messageTone;
public GeofenceTransitionsIntentService() {
super(TAG);
Log.i(TAG, "GeofenceTransitionsIntentService");
}
@Override
public void onCreate() {
super.onCreate();
Log.i(TAG, "onCreate");
}
// @Override
// protected void onHandleIntent(Intent intent) {
// GeofencingEvent geofencingEvent = GeofencingEvent.fromIntent(intent);
// if (geofencingEvent.hasError()) {
// String errorMessage = GeofenceErrorMessages.getErrorString(this,
// geofencingEvent.getErrorCode());
// Log.e(TAG, errorMessage);
// return;
// }
//
// // Get the transition type.
// int geofenceTransition = geofencingEvent.getGeofenceTransition();
//
// // Test that the reported transition was of interest.
// if (geofenceTransition == Geofence.GEOFENCE_TRANSITION_ENTER ||
// geofenceTransition == Geofence.GEOFENCE_TRANSITION_EXIT) {
//
// // Get the geofences that were triggered. A single event can trigger
// // multiple geofences.
// List triggeringGeofences = geofencingEvent.getTriggeringGeofences();
//
// // Get the transition details as a String.
// String geofenceTransitionDetails = getGeofenceTransitionDetails(
// this,
// geofenceTransition,
// triggeringGeofences
// );
//
// // Send notification and log the transition details.
// sendNotification(geofenceTransitionDetails);
// Log.i(TAG, geofenceTransitionDetails);
// } else {
// // Log the error.
// Log.e(TAG, getString(R.string.geofence_transition_invalid_type,
// geofenceTransition));
// }
// }
@Override
protected void onHandleIntent(Intent intent) {
Log.i(TAG, "Intent");
GeofencingEvent geofencingEvent = GeofencingEvent.fromIntent(intent);
if (geofencingEvent.hasError()) {
String errorMessage = GeofenceErrorMessages.getErrorString(this,
geofencingEvent.getErrorCode());
Log.e(TAG, errorMessage);
return;
}
int geofenceTransition = geofencingEvent.getGeofenceTransition();
if (geofenceTransition == Geofence.GEOFENCE_TRANSITION_ENTER ||
geofenceTransition == Geofence.GEOFENCE_TRANSITION_EXIT) {
List<Geofence> triggeringGeofences = geofencingEvent.getTriggeringGeofences();
String geofenceTransitionDetails = getGeofenceTransitionDetails(
this,
geofenceTransition,
triggeringGeofences
);
sendNotification(geofenceTransitionDetails);
Log.i(TAG, geofenceTransitionDetails);
} else {
// Log the error.
Log.e(TAG, getString(R.string.geofence_transition_invalid_type, geofenceTransition));
}
}
private String getGeofenceTransitionDetails(
Context context,
int geofenceTransition,
List<Geofence> triggeringGeofences) {
String geofenceTransitionString = getTransitionString(geofenceTransition);
ArrayList triggeringGeofencesIdsList = new ArrayList();
for (Geofence geofence : triggeringGeofences) {
triggeringGeofencesIdsList.add(geofence.getRequestId());
}
String triggeringGeofencesIdsString = TextUtils.join(", ", triggeringGeofencesIdsList);
return geofenceTransitionString + ": " + triggeringGeofencesIdsString;
}
private void sendNotification(String notificationDetails) {
int notifyColor = getResources().getColor(R.color.primary);
SharedPreferences prefs = getSharedPreferences("NotificationPrefs", MODE_PRIVATE);
isMessageTone = prefs.getBoolean("is_message_notification", false);
isMessageVibrate = prefs.getBoolean("is_message_vibrate", false);
messageTone = prefs.getString("message_notificationTone", "");
SharedPreferences preferences = getSharedPreferences("Theme", MODE_PRIVATE);
int storedPreference = preferences.getInt("storedInt", 0);
if (storedPreference == 0 || storedPreference == 1) {
notifyColor = getResources().getColor(R.color.primary);
} else if (storedPreference == 2) {
notifyColor = getResources().getColor(R.color.primary_theme2);
} else if (storedPreference == 3) {
notifyColor = getResources().getColor(R.color.primary_theme3);
} else if (storedPreference == 4) {
notifyColor = getResources().getColor(R.color.primary_theme4);
} else if (storedPreference == 5) {
notifyColor = getResources().getColor(R.color.primary_theme5);
}
Intent notificationIntent = new Intent(getApplicationContext(), HomeActivity.class);
TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
stackBuilder.addParentStack(HomeActivity.class);
stackBuilder.addNextIntent(notificationIntent);
PendingIntent notificationPendingIntent =
stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
// Define the notification settings.
builder.setSmallIcon(R.drawable.ic_directions_black)
.setLargeIcon(BitmapFactory.decodeResource(getResources(),
R.drawable.ic_directions_black))
.setColor(notifyColor)
.setContentTitle(notificationDetails)
.setContentText(getString(R.string.geofence_transition_notification_text))
.setContentIntent(notificationPendingIntent);
if (isMessageTone) {
if (messageTone.equals("")) {
Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
builder.setSound(defaultSoundUri);
} else {
builder.setSound(Uri.parse(messageTone));
}
if (isMessageVibrate) {
builder.setVibrate(new long[]{0, 1000});
}
}
builder.setAutoCancel(true);
NotificationManager mNotificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.notify(0, builder.build());
}
private String getTransitionString(int transitionType) {
switch (transitionType) {
case Geofence.GEOFENCE_TRANSITION_ENTER:
return getString(R.string.geofence_transition_entered);
case Geofence.GEOFENCE_TRANSITION_EXIT:
return getString(R.string.geofence_transition_exited);
default:
return getString(R.string.unknown_geofence_transition);
}
}
}
Problem:
I am able to get the toast "Geofence added". But when I am selecting my current location for fencing, its not triggering any notification. Before when I used to do this from activity, it use to trigger the notification if my device location is in fencing which I have added.
Please help me to find the issue.
Thanks.
回答1:
I have done this way:
I have created GeoFenceObserversationService
singleton class.
GeoFenceObserversationService.java:
public class GeoFenceObserversationService extends Service implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, ResultCallback<Status> {
protected static final String TAG = "GeoFenceObserversationService";
protected GoogleApiClient mGoogleApiClient;
protected ArrayList<Geofence> mGeofenceList;
private boolean mGeofencesAdded;
private SharedPreferences mSharedPreferences;
private static GeoFenceObserversationService mInstant;
public static GeoFenceObserversationService getInstant(){
return mInstant;
}
@Override
public void onCreate() {
super.onCreate();
mInstant = this;
mGeofenceList = new ArrayList<Geofence>();
mSharedPreferences = getSharedPreferences(AppConstants.SHARED_PREFERENCES_NAME, MODE_PRIVATE);
mGeofencesAdded = mSharedPreferences.getBoolean(AppConstants.GEOFENCES_ADDED_KEY, false);
buildGoogleApiClient();
}
@Override
public void onDestroy() {
mGoogleApiClient.disconnect();
super.onDestroy();
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
}
protected void buildGoogleApiClient() {
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
mGoogleApiClient.connect();
}
@Override
public void onConnected(Bundle connectionHint) {
}
@Override
public void onConnectionFailed(ConnectionResult result) {
}
@Override
public void onConnectionSuspended(int cause) {
}
private GeofencingRequest getGeofencingRequest() {
GeofencingRequest.Builder builder = new GeofencingRequest.Builder();
builder.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER);
builder.addGeofences(mGeofenceList);
return builder.build();
}
public void addGeofences() {
if (!mGoogleApiClient.isConnected()) {
Toast.makeText(this, getString(R.string.not_connected), Toast.LENGTH_SHORT).show();
return;
}
populateGeofenceList();
if(!mGeofenceList.isEmpty()){
try {
LocationServices.GeofencingApi.addGeofences(mGoogleApiClient, getGeofencingRequest(), getGeofencePendingIntent()).setResultCallback(this);
} catch (SecurityException securityException) {
securityException.printStackTrace();
}
}
}
public void removeGeofences() {
if (!mGoogleApiClient.isConnected()) {
Toast.makeText(this, getString(R.string.not_connected), Toast.LENGTH_SHORT).show();
return;
}
try {
LocationServices.GeofencingApi.removeGeofences(mGoogleApiClient,getGeofencePendingIntent()).setResultCallback(this);
} catch (SecurityException securityException) {
securityException.printStackTrace();
}
}
public void onResult(Status status) {
if (status.isSuccess()) {
mGeofencesAdded = !mGeofencesAdded;
SharedPreferences.Editor editor = mSharedPreferences.edit();
editor.putBoolean(AppConstants.GEOFENCES_ADDED_KEY, mGeofencesAdded);
editor.apply();
} else {
String errorMessage = AppConstants.getErrorString(this,status.getStatusCode());
Log.i("Geofence", errorMessage);
}
}
private PendingIntent getGeofencePendingIntent() {
Intent intent = new Intent(this, GeofenceTransitionsIntentService.class);
return PendingIntent.getService(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
}
private void populateGeofenceList() {
mGeofenceList.clear();
List<GeoFencingResponce> geoFenceList = getGeofencesList;
if(geoFenceList!=null&&!geoFenceList.isEmpty()){
for (GeoFencingResponce obj : geoFenceList){
mGeofenceList.add(obj.getGeofence());
Log.i(TAG,"Registered Geofences : " + obj.Id+"-"+obj.Name+"-"+obj.Lattitude+"-"+obj.Longitude);
}
}
}
}
AppConstant:
public static final String SHARED_PREFERENCES_NAME = PACKAGE_NAME + ".SHARED_PREFERENCES_NAME";
public static final String GEOFENCES_ADDED_KEY = PACKAGE_NAME + ".GEOFENCES_ADDED_KEY";
public static final String DETECTED_GEOFENCES = "detected_geofences";
public static final String DETECTED_BEACONS = "detected_beacons";
public static String getErrorString(Context context, int errorCode) {
Resources mResources = context.getResources();
switch (errorCode) {
case GeofenceStatusCodes.GEOFENCE_NOT_AVAILABLE:
return mResources.getString(R.string.geofence_not_available);
case GeofenceStatusCodes.GEOFENCE_TOO_MANY_GEOFENCES:
return mResources.getString(R.string.geofence_too_many_geofences);
case GeofenceStatusCodes.GEOFENCE_TOO_MANY_PENDING_INTENTS:
return mResources.getString(R.string.geofence_too_many_pending_intents);
default:
return mResources.getString(R.string.unknown_geofence_error);
}
}
Where I started Service ? From Application class
startService(new Intent(getApplicationContext(),GeoFenceObserversationService.class));
How I registered Geofences ?
GeoFenceObserversationService.getInstant().addGeofences();
Hope this will help you.
来源:https://stackoverflow.com/questions/35973536/android-not-able-to-add-geofence-from-service