diff --git a/extern/GmsApi b/extern/GmsApi index c61a147d..3f1fa813 160000 --- a/extern/GmsApi +++ b/extern/GmsApi @@ -1 +1 @@ -Subproject commit c61a147de29456270bce1203c9f6700268b068c5 +Subproject commit 3f1fa81390d67053d3aa50b0bc3537953396bcf6 diff --git a/play-services-location/src/main/java/com/google/android/gms/location/GeofencingApi.java b/play-services-location/src/main/java/com/google/android/gms/location/GeofencingApi.java index b2b581bf..0268aeb2 100644 --- a/play-services-location/src/main/java/com/google/android/gms/location/GeofencingApi.java +++ b/play-services-location/src/main/java/com/google/android/gms/location/GeofencingApi.java @@ -16,5 +16,33 @@ package com.google.android.gms.location; +import android.app.PendingIntent; + +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 java.util.List; + +/** + * The main entry point for interacting with the geofencing APIs. + *

+ * The methods must be used in conjunction with a GoogleApiClient. E.g. + *

+ *  new GoogleApiClient.Builder(context)
+ *          .addApi(LocationServices.API)
+ *          .addConnectionCallbacks(this)
+ *          .addOnConnectionFailedListener(this)
+ *          .build()
+ * 
+ */ public interface GeofencingApi { + PendingResult addGeofences(GoogleApiClient client, GeofencingRequest geofencingRequest, PendingIntent pendingIntent); + + @Deprecated + PendingResult addGeofences(GoogleApiClient client, List geofences, PendingIntent pendingIntent); + + PendingResult removeGeofences(GoogleApiClient client, List geofenceRequestIds); + + PendingResult removeGeofences(GoogleApiClient client, PendingIntent pendingIntent); } diff --git a/play-services-location/src/main/java/org/microg/gms/location/FusedLocationProviderApiImpl.java b/play-services-location/src/main/java/org/microg/gms/location/FusedLocationProviderApiImpl.java index 4da06a0a..84584ac0 100644 --- a/play-services-location/src/main/java/org/microg/gms/location/FusedLocationProviderApiImpl.java +++ b/play-services-location/src/main/java/org/microg/gms/location/FusedLocationProviderApiImpl.java @@ -137,5 +137,4 @@ public class FusedLocationProviderApiImpl implements FusedLocationProviderApi { private interface Runnable { void run(LocationClientImpl client) throws RemoteException; } - } diff --git a/play-services-location/src/main/java/org/microg/gms/location/GeofencingApiImpl.java b/play-services-location/src/main/java/org/microg/gms/location/GeofencingApiImpl.java index 7b6512b0..e0b09c98 100644 --- a/play-services-location/src/main/java/org/microg/gms/location/GeofencingApiImpl.java +++ b/play-services-location/src/main/java/org/microg/gms/location/GeofencingApiImpl.java @@ -16,7 +16,101 @@ package org.microg.gms.location; +import android.app.PendingIntent; +import android.os.RemoteException; +import android.support.annotation.NonNull; +import android.util.Log; + +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.Geofence; import com.google.android.gms.location.GeofencingApi; +import com.google.android.gms.location.GeofencingRequest; +import com.google.android.gms.location.LocationServices; +import com.google.android.gms.location.internal.IGeofencerCallbacks; +import com.google.android.gms.location.internal.ParcelableGeofence; + +import org.microg.gms.common.GmsConnector; + +import java.util.ArrayList; +import java.util.List; public class GeofencingApiImpl implements GeofencingApi { + @Override + public PendingResult addGeofences(GoogleApiClient client, final GeofencingRequest geofencingRequest, final PendingIntent pendingIntent) { + return callGeofencer(client, new Runnable() { + @Override + public void run(LocationClientImpl client, IGeofencerCallbacks callbacks) throws RemoteException { + client.addGeofences(geofencingRequest, pendingIntent, callbacks); + } + }); + } + + @Override + public PendingResult addGeofences(GoogleApiClient client, final List geofences, final PendingIntent pendingIntent) { + final List geofenceList = new ArrayList(); + for (Geofence geofence : geofences) { + if (geofence instanceof ParcelableGeofence) geofenceList.add((ParcelableGeofence) geofence); + } + return callGeofencer(client, new Runnable() { + @Override + public void run(LocationClientImpl client, IGeofencerCallbacks callbacks) throws RemoteException { + client.addGeofences(geofenceList, pendingIntent, callbacks); + } + }); + } + + @Override + public PendingResult removeGeofences(GoogleApiClient client, final List geofenceRequestIds) { + return callGeofencer(client, new Runnable() { + @Override + public void run(LocationClientImpl client, IGeofencerCallbacks callbacks) throws RemoteException { + client.removeGeofences(geofenceRequestIds, callbacks); + } + }); + } + + @Override + public PendingResult removeGeofences(GoogleApiClient client, final PendingIntent pendingIntent) { + return callGeofencer(client, new Runnable() { + @Override + public void run(LocationClientImpl client, IGeofencerCallbacks callbacks) throws RemoteException { + client.removeGeofences(pendingIntent, callbacks); + } + }); + } + + @NonNull + private IGeofencerCallbacks.Stub createGeofencerCallbacks(final GmsConnector.Callback.ResultProvider resultProvider) { + return new IGeofencerCallbacks.Stub(){ + @Override + public void onAddGeofenceResult(int statusCode, String[] requestIds) throws RemoteException { + resultProvider.onResultAvailable(new Status(statusCode)); + } + + @Override + public void onRemoveGeofencesByRequestIdsResult(int statusCode, String[] requestIds) throws RemoteException { + resultProvider.onResultAvailable(new Status(statusCode)); + } + + @Override + public void onRemoveGeofencesByPendingIntentResult(int statusCode, PendingIntent pendingIntent) throws RemoteException { + resultProvider.onResultAvailable(new Status(statusCode)); + } + }; + } + + private PendingResult callGeofencer(GoogleApiClient client, final Runnable runnable) { + return GmsConnector.call(client, LocationServices.API, new GmsConnector.Callback() { + @Override + public void onClientAvailable(LocationClientImpl client, ResultProvider resultProvider) throws RemoteException { + runnable.run(client, createGeofencerCallbacks(resultProvider)); + } + }); + } + + private interface Runnable { + void run(LocationClientImpl client, IGeofencerCallbacks callbacks) throws RemoteException; + } } diff --git a/play-services-location/src/main/java/org/microg/gms/location/LocationClientImpl.java b/play-services-location/src/main/java/org/microg/gms/location/LocationClientImpl.java index e3593198..1d5f5b6c 100644 --- a/play-services-location/src/main/java/org/microg/gms/location/LocationClientImpl.java +++ b/play-services-location/src/main/java/org/microg/gms/location/LocationClientImpl.java @@ -25,14 +25,18 @@ import android.os.RemoteException; import android.util.Log; import com.google.android.gms.common.api.GoogleApiClient; +import com.google.android.gms.location.GeofencingRequest; import com.google.android.gms.location.ILocationListener; import com.google.android.gms.location.LocationListener; import com.google.android.gms.location.LocationRequest; import com.google.android.gms.location.LocationServices; +import com.google.android.gms.location.internal.IGeofencerCallbacks; +import com.google.android.gms.location.internal.ParcelableGeofence; import org.microg.gms.common.api.GoogleApiClientImpl; import java.util.HashMap; +import java.util.List; import java.util.Map; public class LocationClientImpl extends GoogleLocationManagerClient { @@ -42,7 +46,7 @@ public class LocationClientImpl extends GoogleLocationManagerClient { public LocationClientImpl(Context context, GoogleApiClient.ConnectionCallbacks callbacks, - GoogleApiClient.OnConnectionFailedListener connectionFailedListener) { + GoogleApiClient.OnConnectionFailedListener connectionFailedListener) { super(context, callbacks, connectionFailedListener); Log.d(TAG, ""); } @@ -55,6 +59,38 @@ public class LocationClientImpl extends GoogleLocationManagerClient { return null; } + public void addGeofences(GeofencingRequest request, PendingIntent pendingIntent, IGeofencerCallbacks callbacks) throws RemoteException { + if (nativeLocation != null) { + nativeLocation.addGeofences(request, pendingIntent, callbacks); + } else { + getServiceInterface().addGeofences(request, pendingIntent, callbacks); + } + } + + public void addGeofences(List request, PendingIntent pendingIntent, IGeofencerCallbacks callbacks) throws RemoteException { + if (nativeLocation != null) { + nativeLocation.addGeofences(request, pendingIntent, callbacks); + } else { + getServiceInterface().addGeofencesList(request, pendingIntent, callbacks, getContext().getPackageName()); + } + } + + public void removeGeofences(List geofenceRequestIds, IGeofencerCallbacks callbacks) throws RemoteException { + if (nativeLocation != null) { + nativeLocation.removeGeofences(geofenceRequestIds, callbacks); + } else { + getServiceInterface().removeGeofencesById(geofenceRequestIds.toArray(new String[geofenceRequestIds.size()]), callbacks, getContext().getPackageName()); + } + } + + public void removeGeofences(PendingIntent pendingIntent, IGeofencerCallbacks callbacks) throws RemoteException { + if (nativeLocation != null) { + nativeLocation.removeGeofences(pendingIntent, callbacks); + } else { + getServiceInterface().removeGeofencesByIntent(pendingIntent, callbacks, getContext().getPackageName()); + } + } + public Location getLastLocation() throws RemoteException { Log.d(TAG, "getLastLocation()"); if (nativeLocation != null) { @@ -92,7 +128,7 @@ public class LocationClientImpl extends GoogleLocationManagerClient { } public void requestLocationUpdates(LocationRequest request, LocationListener listener, - Looper looper) throws RemoteException { + Looper looper) throws RemoteException { if (nativeLocation != null) { nativeLocation.requestLocationUpdates(request, listener, looper); } diff --git a/play-services-location/src/main/java/org/microg/gms/location/NativeLocationClientImpl.java b/play-services-location/src/main/java/org/microg/gms/location/NativeLocationClientImpl.java index 7555b806..158c8cc2 100644 --- a/play-services-location/src/main/java/org/microg/gms/location/NativeLocationClientImpl.java +++ b/play-services-location/src/main/java/org/microg/gms/location/NativeLocationClientImpl.java @@ -25,15 +25,29 @@ import android.location.Location; import android.location.LocationManager; import android.os.Bundle; import android.os.Looper; +import android.os.RemoteException; +import android.os.SystemClock; import android.util.Log; +import com.google.android.gms.common.api.CommonStatusCodes; import com.google.android.gms.location.FusedLocationProviderApi; +import com.google.android.gms.location.Geofence; +import com.google.android.gms.location.GeofenceStatusCodes; +import com.google.android.gms.location.GeofencingEvent; +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.internal.IGeofencerCallbacks; +import com.google.android.gms.location.internal.ParcelableGeofence; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; +import static android.location.LocationManager.KEY_LOCATION_CHANGED; +import static android.location.LocationManager.KEY_PROXIMITY_ENTERING; + @SuppressWarnings("MissingPermission") public class NativeLocationClientImpl { private final static String TAG = "GmsToNativeLocClient"; @@ -71,6 +85,39 @@ public class NativeLocationClientImpl { return criteria; } + public void addGeofences(GeofencingRequest geofencingRequest, PendingIntent pendingIntent, IGeofencerCallbacks callbacks) throws RemoteException { + Log.d(TAG, "addGeofences(GeofencingRequest)"); + callbacks.onAddGeofenceResult(GeofenceStatusCodes.GEOFENCE_NOT_AVAILABLE, new String[0]); + } + + public void addGeofences(List geofences, PendingIntent pendingIntent, IGeofencerCallbacks callbacks) throws RemoteException { + Log.d(TAG, "addGeofences(List)"); + Intent i = new Intent(context, NativePendingIntentForwarder.class); + Bundle bundle = new Bundle(); + bundle.putParcelable(EXTRA_PENDING_INTENT, pendingIntent); + i.putExtras(bundle); + nativePendingMap.put(pendingIntent, PendingIntent.getActivity(context, 0, i, 0)); + List requestIds = new ArrayList(); + for (ParcelableGeofence geofence : geofences) { + locationManager.addProximityAlert(geofence.latitude, geofence.longitude, geofence.radius, + geofence.expirationTime - SystemClock.elapsedRealtime(), nativePendingMap.get(pendingIntent)); + requestIds.add(geofence.getRequestId()); + } + callbacks.onAddGeofenceResult(CommonStatusCodes.SUCCESS, requestIds.toArray(new String[requestIds.size()])); + } + + public void removeGeofences(List requestIds, IGeofencerCallbacks callbacks) throws RemoteException { + Log.d(TAG, "removeGeofences(List)"); + callbacks.onRemoveGeofencesByRequestIdsResult(GeofenceStatusCodes.ERROR, requestIds.toArray(new String[requestIds.size()])); + } + + public void removeGeofences(PendingIntent pendingIntent, IGeofencerCallbacks callbacks) throws RemoteException { + Log.d(TAG, "removeGeofences(PendingIntent)"); + locationManager.removeProximityAlert(nativePendingMap.get(pendingIntent)); + nativePendingMap.remove(pendingIntent); + callbacks.onRemoveGeofencesByPendingIntentResult(CommonStatusCodes.SUCCESS, pendingIntent); + } + public Location getLastLocation() { Log.d(TAG, "getLastLocation()"); return locationManager.getLastKnownLocation(locationManager.getBestProvider(DEFAULT_CRITERIA, true)); @@ -131,11 +178,19 @@ public class NativeLocationClientImpl { @Override public void onReceive(Context context, Intent intent) { - if (intent.hasExtra(LocationManager.KEY_LOCATION_CHANGED)) { + if (intent.hasExtra(KEY_PROXIMITY_ENTERING)) { + PendingIntent pendingIntent = intent.getExtras().getParcelable(EXTRA_PENDING_INTENT); + try { + intent.putExtra(GeofencingEvent.EXTRA_TRANSITION, intent.getBooleanExtra(KEY_PROXIMITY_ENTERING, false) ? Geofence.GEOFENCE_TRANSITION_ENTER : Geofence.GEOFENCE_TRANSITION_EXIT); + pendingIntent.send(context, 0, intent); + } catch (PendingIntent.CanceledException e) { + nativePendingMap.remove(pendingIntent); + } + } else if (intent.hasExtra(KEY_LOCATION_CHANGED)) { PendingIntent pendingIntent = intent.getExtras().getParcelable(EXTRA_PENDING_INTENT); try { intent.putExtra(FusedLocationProviderApi.KEY_LOCATION_CHANGED, - intent.getParcelableExtra(LocationManager.KEY_LOCATION_CHANGED)); + intent.getParcelableExtra(KEY_LOCATION_CHANGED)); pendingIntent.send(context, 0, intent); pendingCount.put(pendingIntent, pendingCount.get(pendingIntent) - 1); if (pendingCount.get(pendingIntent) == 0) {