forked from organicmaps/organicmaps
[android] Added geofences
This commit is contained in:
parent
9aae789623
commit
e2d1c4a5dc
11 changed files with 369 additions and 2 deletions
|
@ -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>
|
||||
|
|
162
android/src/com/mapswithme/maps/GeofenceReceiver.java
Normal file
162
android/src/com/mapswithme/maps/GeofenceReceiver.java
Normal 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());
|
||||
}*/
|
||||
}
|
7
android/src/com/mapswithme/maps/GeofenceService.java
Normal file
7
android/src/com/mapswithme/maps/GeofenceService.java
Normal file
|
@ -0,0 +1,7 @@
|
|||
package com.mapswithme.maps;
|
||||
|
||||
public interface GeofenceService
|
||||
{
|
||||
void registryGeofences();
|
||||
void invalidateGeofences();
|
||||
}
|
19
android/src/com/mapswithme/maps/GeofenceServiceImpl.java
Normal file
19
android/src/com/mapswithme/maps/GeofenceServiceImpl.java
Normal file
|
@ -0,0 +1,19 @@
|
|||
package com.mapswithme.maps;
|
||||
|
||||
class GeofenceServiceImpl implements GeofenceService
|
||||
{
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public void registryGeofences()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invalidateGeofences()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
16
android/src/com/mapswithme/maps/GeofenceServiceStub.java
Normal file
16
android/src/com/mapswithme/maps/GeofenceServiceStub.java
Normal file
|
@ -0,0 +1,16 @@
|
|||
package com.mapswithme.maps;
|
||||
|
||||
class GeofenceServiceStub implements GeofenceService
|
||||
{
|
||||
@Override
|
||||
public void registryGeofences()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invalidateGeofences()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
|
|
Loading…
Add table
Reference in a new issue