Я очень плохо знаком с разработкой для Android и пытаюсь создать базовое приложение, которое отображает GoogleMap (с отображением некоторых слоев GeoJSON) и предупреждает пользователя при входе в геозону. Я настроил отправку уведомлений при входе / выходе, но, к сожалению, устройства, которые будут работать, работают на Android 4.4.2 и поэтому не могут отображать какие-либо хедз-ап уведомления. Мне удалось в основном реплицировать оповещение в виде головы, создав в объекте MainActivity мигающий объект TextView, но я бы хотел, чтобы оно стало видимым при входе в геозону и исчезало при выходе.
В настоящее время я добавляю ResultReceiver в качестве дополнительного при отправке намерения в IntentService, а затем отправляю код обратно в MainActivity на основе типа перехода. К сожалению, добавление ResultReceiver в качестве дополнительного заставляет GeofencingEvent возвращать все типы переходов как -1. Документ для объектов GeofencingEvent говорит, что это происходит, когда событие не генерируется для предупреждения о переходе. Если я удаляю ResultReceiver и просто отправляю уведомление, он корректно возвращает значение 1/2 при входе / выходе из геозоны.
Я надеялся, что у кого-то есть обходной путь для передачи ResultReceiver или какого-либо направления к другому способу изменения пользовательского интерфейса на основе значения в IntentService.
Вот соответствующие части в основной деятельности:
public class MapsActivity extends AppCompatActivity implements OnMapReadyCallback,
AdapterView.OnItemSelectedListener,
GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener,
ResultCallback<Status> {
...
private GeofencingClient mGeofencingClient;
private GoogleApiClient mGoogleApiClient;
private ArrayList<Geofence> mGeofenceList;
private ResultReceiver resultReceiver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_maps);
// Creates map fragment and sets to GoogleMap default
SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
.findFragmentById(R.id.map);
mapFragment.getMapAsync(this);
// Enables location services
mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
mGeofencingClient = LocationServices.getGeofencingClient(this);
// Populates a list of geofences and connects to the Google Maps API Client
mGeofenceList = new ArrayList<>();
populateGeofenceList();
buildGoogleApiClient();
createNotificationChannel();
resultReceiver = new GeofenceTransitionResultReceiver(new Handler());
...
}
// Connects to the Google Maps API Client
protected synchronized void buildGoogleApiClient() {
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
}
...
// Creates a list object containing geofenced points
public void populateGeofenceList() {
for (Map.Entry<String, LatLng> entry : LANDMARKS.entrySet()) {
mGeofenceList.add(new Geofence.Builder()
.setRequestId(entry.getKey())
.setCircularRegion(
entry.getValue().latitude,
entry.getValue().longitude,
Constants.GEOFENCE_RADIUS_IN_METERS
)
.setExpirationDuration(Constants.GEOFENCE_EXPIRATION_IN_MILLISECONDS)
.setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER |
Geofence.GEOFENCE_TRANSITION_EXIT)
.build());
}
}
// When the "Add Geofences" button is clicked, will activate geofences, Toast whether or not
// the geofences were successfully added, and if they were successfully added
// will create the (hidden) flashing TextView object
public void addGeofencesButtonHandler(View view) {
if (!mGoogleApiClient.isConnected()) {
Toast.makeText(this, "Google API Client not connected!", Toast.LENGTH_SHORT).show();
return;
}
try {
mGeofencingClient.addGeofences(getGeofencingRequest(), getGeofencePendingIntent())
.addOnSuccessListener(this, new OnSuccessListener<Void>() {
@Override
public void onSuccess(Void aVoid) {
// Geofences added
Toast.makeText(getApplicationContext(), "Geofence Connected", Toast.LENGTH_SHORT).show();
manageBlinkEffect();
}
})
.addOnFailureListener(this, new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
// Failed to add geofences
Toast.makeText(getApplicationContext(), "Geofence Not Connected", Toast.LENGTH_SHORT).show();
}
});
} catch (SecurityException securityException) {
// Catch exception generated if the app does not use ACCESS_FINE_LOCATION permission.
}
}
// Builds the geofences
private GeofencingRequest getGeofencingRequest() {
GeofencingRequest.Builder builder = new GeofencingRequest.Builder();
builder.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER);
builder.addGeofences(mGeofenceList);
return builder.build();
}
// Retrieves the intent from GeofenceTransitionsIntentService and creates a PendingIntent
private PendingIntent getGeofencePendingIntent() {
Intent intent = new Intent(this, GeofenceTransitionsIntentService.class);
intent.putExtra("receiver", resultReceiver);
// We use FLAG_UPDATE_CURRENT so that we get the same pending intent back when calling addgeoFences()
return PendingIntent.getService(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
}
private class GeofenceTransitionResultReceiver extends ResultReceiver {
public GeofenceTransitionResultReceiver(Handler handler) {
super(handler);
}
protected void onReceiveResult(int resultCode, Bundle resultData) {
String transition = "Test String";
switch (resultCode) {
case GeofenceTransitionsIntentService.GEOFENCE_ERROR:
transition = "Error in Geofence";
break;
case GeofenceTransitionsIntentService.GEOFENCE_ENTER:
transition = resultData.getString("enter");
txt.setVisibility(View.VISIBLE);
break;
case GeofenceTransitionsIntentService.GEOFENCE_EXIT:
transition = resultData.getString("exit");
txt.setVisibility(View.GONE);
break;
}
txt.setVisibility(View.VISIBLE);
Toast.makeText(getApplicationContext(), transition, Toast.LENGTH_SHORT).show();
super.onReceiveResult(resultCode, resultData);
}
}
}
А вот код для IntentService:
public class GeofenceTransitionsIntentService extends IntentService {
protected static final String TAG = "GeofenceTransitionsIS";
public static final int GEOFENCE_ENTER = 2;
public static final int GEOFENCE_EXIT = 3;
public static final int GEOFENCE_ERROR = 4;
public GeofenceTransitionsIntentService() {
super(TAG); // use TAG to name the IntentService worker thread
}
@Override
protected void onHandleIntent(Intent intent) {
GeofencingEvent event = GeofencingEvent.fromIntent(intent);
if (event.hasError()) {
Log.e(TAG, "GeofencingEvent Error: " + event.getErrorCode());
return;
}
// tests the geofence transition value
String description = String.valueOf(event.getGeofenceTransition());
sendNotification(description);
final ResultReceiver receiver = intent.getParcelableExtra("receiver");
Bundle bundle = new Bundle();
try {
switch (event.getGeofenceTransition()) {
case Geofence.GEOFENCE_TRANSITION_ENTER:
bundle.putString("enter", "Entering");
receiver.send(GEOFENCE_ENTER, bundle);
break;
case Geofence.GEOFENCE_TRANSITION_EXIT:
bundle.putString("exit", "Exiting");
receiver.send(GEOFENCE_EXIT, bundle);
break;
}
}
catch (Exception e) {
receiver.send(GEOFENCE_ERROR, Bundle.EMPTY);
e.printStackTrace();
}
}
private void sendNotification(String notificationDetails) {
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(getApplicationContext(), "test")
.setSmallIcon(R.drawable.ic_launcher_background)
.setContentTitle("Test Notification")
.setContentText(notificationDetails)
.setPriority(NotificationCompat.PRIORITY_HIGH);
mBuilder.setLights(Color.BLUE, 500, 500);
mBuilder.setVibrate(new long[] { 0,500 });
Uri alarmSound = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
mBuilder.setSound(alarmSound);
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(0, mBuilder.build());
}
}
Спасибо!