[android] Added geofences

This commit is contained in:
Dmitry Donskoy 2018-12-17 18:20:55 +03:00 committed by Aleksandr Zatsepin
parent 9aae789623
commit e2d1c4a5dc
11 changed files with 369 additions and 2 deletions

View file

@ -568,6 +568,20 @@
android:name="com.pushwoosh.location.GeoLocationService"/>
<service android:name="com.mapswithme.util.push.GcmInstanceIDListenerService"/>
<service android:name="com.mapswithme.util.push.GcmMessageHandlerService"/>
<receiver android:name="com.mapswithme.maps.GeofenceReceiver"
android:enabled="true"
android:exported="true">
<intent-filter >
<action android:name="com.aol.android.geofence.ACTION_RECEIVE_GEOFENCE"/>
</intent-filter>
</receiver>
<service
android:name="com.mapswithme.maps.scheduling.GeofenceTransitionsIntentService"
android:permission="android.permission.BIND_JOB_SERVICE"
android:exported="true"/>
<!-- Catches app upgraded intent -->
<receiver android:name=".background.UpgradeReceiver">
<intent-filter>

View file

@ -0,0 +1,162 @@
package com.mapswithme.maps;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.support.v4.app.NotificationCompat;
import android.support.v4.app.TaskStackBuilder;
import android.support.v4.content.LocalBroadcastManager;
import android.text.TextUtils;
import android.util.Log;
import com.google.android.gms.location.Geofence;
import com.mapswithme.maps.scheduling.GeofenceTransitionsIntentService;
import java.util.List;
public class GeofenceReceiver extends BroadcastReceiver
{
Context context;
Intent broadcastIntent = new Intent();
@Override
public void onReceive(Context context, Intent intent) {
GeofenceTransitionsIntentService.enqueueWork(context, intent);
this.context = context;
/* broadcastIntent.addCategory(GeofenceUtils.CATEGORY_LOCATION_SERVICES);
if (LocationClient.hasError(intent)) {
handleError(intent);
} else {
handleEnterExit(intent);
}*/
}
/*
private void handleError(Intent intent){
// Get the error code
int errorCode = LocationClient.getErrorCode(intent);
// Get the error message
String errorMessage = LocationServiceErrorMessages.getErrorString(
context, errorCode);
// Log the error
Log.e(GeofenceUtils.APPTAG,
context.getString(R.string.geofence_transition_error_detail,
errorMessage));
// Set the action and error message for the broadcast intent
broadcastIntent
.setAction(GeofenceUtils.ACTION_GEOFENCE_ERROR)
.putExtra(GeofenceUtils.EXTRA_GEOFENCE_STATUS, errorMessage);
// Broadcast the error *locally* to other components in this app
LocalBroadcastManager.getInstance(context).sendBroadcast(
broadcastIntent);
}
private void handleEnterExit(Intent intent) {
// Get the type of transition (entry or exit)
int transition = LocationClient.getGeofenceTransition(intent);
// Test that a valid transition was reported
if ((transition == Geofence.GEOFENCE_TRANSITION_ENTER)
|| (transition == Geofence.GEOFENCE_TRANSITION_EXIT)) {
// Post a notification
List<Geofence> geofences = LocationClient
.getTriggeringGeofences(intent);
String[] geofenceIds = new String[geofences.size()];
String ids = TextUtils.join(GeofenceUtils.GEOFENCE_ID_DELIMITER,
geofenceIds);
String transitionType = GeofenceUtils
.getTransitionString(transition);
for (int index = 0; index < geofences.size(); index++) {
Geofence geofence = geofences.get(index);
...do something with the geofence entry or exit. I'm saving them to a local sqlite db
}
// Create an Intent to broadcast to the app
broadcastIntent
.setAction(GeofenceUtils.ACTION_GEOFENCE_TRANSITION)
.addCategory(GeofenceUtils.CATEGORY_LOCATION_SERVICES)
.putExtra(GeofenceUtils.EXTRA_GEOFENCE_ID, geofenceIds)
.putExtra(GeofenceUtils.EXTRA_GEOFENCE_TRANSITION_TYPE,
transitionType);
LocalBroadcastManager.getInstance(MyApplication.getContext())
.sendBroadcast(broadcastIntent);
// Log the transition type and a message
Log.d(GeofenceUtils.APPTAG, transitionType + ": " + ids);
Log.d(GeofenceUtils.APPTAG,
context.getString(R.string.geofence_transition_notification_text));
// In debug mode, log the result
Log.d(GeofenceUtils.APPTAG, "transition");
// An invalid transition was reported
} else {
// Always log as an error
Log.e(GeofenceUtils.APPTAG,
context.getString(R.string.geofence_transition_invalid_type,
transition));
}
}
*/
/**
* Posts a notification in the notification bar when a transition is
* detected. If the user clicks the notification, control goes to the main
* Activity.
*
* @param transitionType
* The type of transition that occurred.
*
*//*
private void sendNotification(String transitionType, String locationName) {
// Create an explicit content Intent that starts the main Activity
Intent notificationIntent = new Intent(context, MainActivity.class);
// Construct a task stack
TaskStackBuilder stackBuilder = TaskStackBuilder.create(context);
// Adds 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(
context);
// Set the notification contents
builder.setSmallIcon(R.drawable.ic_notification)
.setContentTitle(transitionType + ": " + locationName)
.setContentText(
context.getString(R.string.geofence_transition_notification_text))
.setContentIntent(notificationPendingIntent);
// Get an instance of the Notification manager
NotificationManager mNotificationManager = (NotificationManager) context
.getSystemService(Context.NOTIFICATION_SERVICE);
// Issue the notification
mNotificationManager.notify(0, builder.build());
}*/
}

View file

@ -0,0 +1,7 @@
package com.mapswithme.maps;
public interface GeofenceService
{
void registryGeofences();
void invalidateGeofences();
}

View file

@ -0,0 +1,19 @@
package com.mapswithme.maps;
class GeofenceServiceImpl implements GeofenceService
{
@Override
public void registryGeofences()
{
}
@Override
public void invalidateGeofences()
{
}
}

View file

@ -0,0 +1,16 @@
package com.mapswithme.maps;
class GeofenceServiceStub implements GeofenceService
{
@Override
public void registryGeofences()
{
}
@Override
public void invalidateGeofences()
{
}
}

View file

@ -6,14 +6,29 @@ import android.support.annotation.Nullable;
import com.mapswithme.maps.background.NotificationCandidate;
import com.mapswithme.maps.geofence.GeoFenceFeature;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class LightFramework
{
public static native boolean nativeIsAuthenticated();
public static native int nativeGetNumberUnsentUGC();
@NonNull
public static native GeoFenceFeature[] nativeGetLocalAdsFeatures(double lat, double lon,
private static native GeoFenceFeature[] nativeGetLocalAdsFeatures(double lat, double lon,
double radiusInMeters,
int maxCount);
@NonNull
public static List<GeoFenceFeature> getLocalAdsFeatures(double lat, double lon,
double radiusInMeters,
int maxCount)
{
return Collections.unmodifiableList(Arrays.asList(nativeGetLocalAdsFeatures(lat,
lon,
radiusInMeters,
maxCount)));
}
public static native void nativeLogLocalAdsEvent(int type, double lat, double lon,
int accuracyInMeters, long mwmVersion,
@NonNull String countryId, int featureIndex);

View file

@ -3,12 +3,14 @@ package com.mapswithme.maps;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.Dialog;
import android.app.PendingIntent;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.location.Location;
import android.location.LocationManager;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.CallSuper;
@ -29,6 +31,12 @@ import android.view.WindowManager;
import android.widget.ImageButton;
import android.widget.Toast;
import com.google.android.gms.location.Geofence;
import com.google.android.gms.location.GeofencingClient;
import com.google.android.gms.location.GeofencingRequest;
import com.google.android.gms.location.LocationServices;
import com.google.android.gms.tasks.OnFailureListener;
import com.google.android.gms.tasks.OnSuccessListener;
import com.mapswithme.maps.Framework.MapObjectListener;
import com.mapswithme.maps.activity.CustomNavigateUpListener;
import com.mapswithme.maps.ads.LikesManager;
@ -66,6 +74,7 @@ import com.mapswithme.maps.editor.EditorHostFragment;
import com.mapswithme.maps.editor.FeatureCategoryActivity;
import com.mapswithme.maps.editor.ReportFragment;
import com.mapswithme.maps.gallery.Items;
import com.mapswithme.maps.geofence.GeoFenceFeature;
import com.mapswithme.maps.location.CompassData;
import com.mapswithme.maps.location.LocationHelper;
import com.mapswithme.maps.maplayer.MapLayerCompositeController;
@ -87,6 +96,7 @@ import com.mapswithme.maps.routing.RoutingBottomMenuListener;
import com.mapswithme.maps.routing.RoutingController;
import com.mapswithme.maps.routing.RoutingPlanFragment;
import com.mapswithme.maps.routing.RoutingPlanInplaceController;
import com.mapswithme.maps.scheduling.GeofenceTransitionsIntentService;
import com.mapswithme.maps.search.BookingFilterParams;
import com.mapswithme.maps.search.FilterActivity;
import com.mapswithme.maps.search.FloatingSearchToolbarController;
@ -134,9 +144,11 @@ import com.mapswithme.util.statistics.PlacePageTracker;
import com.mapswithme.util.statistics.Statistics;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Stack;
import java.util.concurrent.TimeUnit;
public class MwmActivity extends BaseMwmFragmentActivity
implements MapObjectListener,
@ -597,6 +609,65 @@ public class MwmActivity extends BaseMwmFragmentActivity
}
initTips();
GeofencingClient geofencingClient = LocationServices.getGeofencingClient(this);
Location lastKnownLocation = LocationHelper.INSTANCE.getLastKnownLocation();
if (lastKnownLocation == null)
return;
List<GeoFenceFeature> adsFeatures = LightFramework.getLocalAdsFeatures(lastKnownLocation.getLatitude(), lastKnownLocation.getLongitude(), 50 * 1000, 20);
List<Geofence> geofences = new ArrayList<>();
Geofence geofence = new Geofence.Builder()
// Set the request ID of the geofence. This is a string to identify this
// geofence.
.setRequestId(String.valueOf(System.currentTimeMillis()))
.setCircularRegion(lastKnownLocation.getLatitude(), lastKnownLocation.getLongitude(), 100)
.setExpirationDuration(Geofence.NEVER_EXPIRE)
.setLoiteringDelay(5000)
.setTransitionTypes(Geofence.GEOFENCE_TRANSITION_DWELL)
.build();
geofences.add(geofence);
for (GeoFenceFeature each : adsFeatures)
{
}
GeofencingRequest geofencingRequest = getGeofencingRequest(geofences);
geofencingClient.addGeofences(geofencingRequest, getGeofencePendingIntent()).addOnSuccessListener(new OnSuccessListener<Void>()
{
@Override
public void onSuccess(Void aVoid)
{
}
}).addOnFailureListener(new OnFailureListener()
{
@Override
public void onFailure(@NonNull Exception e)
{
}
});
}
private PendingIntent getGeofencePendingIntent() {
// Reuse the PendingIntent if we already have it.
PendingIntent mGeofencePendingIntent = null;
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().
mGeofencePendingIntent = PendingIntent.getService(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
return mGeofencePendingIntent;
}
private GeofencingRequest getGeofencingRequest(List<Geofence> mGeofenceList) {
GeofencingRequest.Builder builder = new GeofencingRequest.Builder();
builder.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_DWELL);
builder.addGeofences(mGeofenceList);
return builder.build();
}
private void initViews()

View file

@ -49,4 +49,26 @@ public class GeoFenceFeature
{
return longitude;
}
@Override
public boolean equals(Object o)
{
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
GeoFenceFeature that = (GeoFenceFeature) o;
if (mwmVersion != that.mwmVersion) return false;
if (featureIndex != that.featureIndex) return false;
return countryId.equals(that.countryId);
}
@Override
public int hashCode()
{
int result = (int) (mwmVersion ^ (mwmVersion >>> 32));
result = 31 * result + countryId.hashCode();
result = 31 * result + featureIndex;
return result;
}
}

View file

@ -89,7 +89,7 @@ public class ConnectivityJobScheduler implements ConnectivityListener
.Builder(jobId, component)
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
.setPersisted(true)
.setMinimumLatency(TimeUnit.HOURS.toMillis(SCHEDULE_PERIOD_IN_HOURS))
.setMinimumLatency(1000 * 60 * 60)
.build();
mJobScheduler.schedule(jobInfo);
}

View file

@ -0,0 +1,40 @@
package com.mapswithme.maps.scheduling;
import android.content.Context;
import android.content.Intent;
import android.support.annotation.NonNull;
import android.support.v4.app.JobIntentService;
import com.google.android.gms.location.Geofence;
import com.google.android.gms.location.GeofencingEvent;
import com.mapswithme.maps.LightFramework;
public class GeofenceTransitionsIntentService extends JobIntentService
{
@Override
protected void onHandleWork(@NonNull Intent intent)
{
GeofencingEvent geofencingEvent = GeofencingEvent.fromIntent(intent);
if (geofencingEvent.hasError())
return;
int transitionType = geofencingEvent.getGeofenceTransition();
if (transitionType == Geofence.GEOFENCE_TRANSITION_ENTER
|| transitionType == Geofence.GEOFENCE_TRANSITION_EXIT)
{
Geofence geofence = geofencingEvent.getTriggeringGeofences().get(0);
// LightFramework.nativeLogLocalAdsEvent(1, /* myPlaceLat */, /* myPlaceLon */, /* locationProviderAccuracy */, , , );
}
}
/**
* Convenience method for enqueuing work in to this service.
*/
public static void enqueueWork(Context context, Intent intent) {
int id = JobIdMap.getId(GeofenceTransitionsIntentService.class);
enqueueWork(context, GeofenceTransitionsIntentService.class, id, intent);
}
}

View file

@ -19,6 +19,7 @@ public class JobIdMap
MAP.put(TrackRecorderWakeService.class, calcIdentifier(MAP.size()));
MAP.put(SystemDownloadCompletedService.class, calcIdentifier(MAP.size()));
MAP.put(WorkerService.class, calcIdentifier(MAP.size()));
MAP.put(GeofenceTransitionsIntentService.class, calcIdentifier(MAP.size()));
}
private static final int ID_BASIC = 1070;