From 23886053b0a7c4f241ce0b8c041d8d24331fc1b5 Mon Sep 17 00:00:00 2001 From: Sarah Lensing Date: Fri, 2 Dec 2016 10:20:27 -0700 Subject: [PATCH 1/6] Respect location request's fastest interval & smallest displacement when reporting location --- .../android/lost/internal/ClientManager.java | 7 +- .../FusedLocationProviderServiceImpl.java | 11 +- .../lost/internal/LostClientManager.java | 183 ++++++++--- .../lost/internal/ReportedChanges.java | 40 +++ .../FusedLocationProviderServiceImplTest.java | 303 ++++++++++++++++++ .../lost/internal/LostApiClientImplTest.java | 12 +- .../lost/internal/LostClientManagerTest.java | 2 +- .../lost/internal/TestClientManager.java | 110 ------- .../lost/internal/TestLocationCallback.java | 4 + 9 files changed, 503 insertions(+), 169 deletions(-) create mode 100644 lost/src/main/java/com/mapzen/android/lost/internal/ReportedChanges.java delete mode 100644 lost/src/test/java/com/mapzen/android/lost/internal/TestClientManager.java diff --git a/lost/src/main/java/com/mapzen/android/lost/internal/ClientManager.java b/lost/src/main/java/com/mapzen/android/lost/internal/ClientManager.java index 6d13648..0fac01d 100644 --- a/lost/src/main/java/com/mapzen/android/lost/internal/ClientManager.java +++ b/lost/src/main/java/com/mapzen/android/lost/internal/ClientManager.java @@ -34,10 +34,11 @@ void addLocationCallback(LostApiClient client, LocationRequest request, boolean removeListener(LostApiClient client, LocationListener listener); boolean removePendingIntent(LostApiClient client, PendingIntent callbackIntent); boolean removeLocationCallback(LostApiClient client, LocationCallback callback); - void reportLocationChanged(Location location); - void sendPendingIntent(Context context, Location location, LocationAvailability availability, + ReportedChanges reportLocationChanged(Location location); + ReportedChanges sendPendingIntent(Context context, Location location, LocationAvailability availability, LocationResult result); - void reportLocationResult(final LocationResult result); + ReportedChanges reportLocationResult(Location location, final LocationResult result); + void updateReportedValues(ReportedChanges changes); void reportProviderEnabled(String provider); void reportProviderDisabled(String provider); void notifyLocationAvailability(final LocationAvailability availability); diff --git a/lost/src/main/java/com/mapzen/android/lost/internal/FusedLocationProviderServiceImpl.java b/lost/src/main/java/com/mapzen/android/lost/internal/FusedLocationProviderServiceImpl.java index 45b3aec..2e11943 100644 --- a/lost/src/main/java/com/mapzen/android/lost/internal/FusedLocationProviderServiceImpl.java +++ b/lost/src/main/java/com/mapzen/android/lost/internal/FusedLocationProviderServiceImpl.java @@ -123,16 +123,21 @@ public boolean isProviderEnabled(LostApiClient client, String provider) { @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION}) public void reportLocation(Location location) { - clientManager.reportLocationChanged(location); + ReportedChanges changes = clientManager.reportLocationChanged(location); LocationAvailability availability = locationEngine.createLocationAvailability(); ArrayList locations = new ArrayList<>(); locations.add(location); final LocationResult result = LocationResult.create(locations); - clientManager.sendPendingIntent(context, location, availability, result); + ReportedChanges pendingIntentChanges = clientManager.sendPendingIntent( + context, location, availability, result); + ReportedChanges callbackChanges = clientManager.reportLocationResult( + location, result); - clientManager.reportLocationResult(result); + changes.putAll(pendingIntentChanges); + changes.putAll(callbackChanges); + clientManager.updateReportedValues(changes); } @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION}) diff --git a/lost/src/main/java/com/mapzen/android/lost/internal/LostClientManager.java b/lost/src/main/java/com/mapzen/android/lost/internal/LostClientManager.java index d394938..9f2d94b 100644 --- a/lost/src/main/java/com/mapzen/android/lost/internal/LostClientManager.java +++ b/lost/src/main/java/com/mapzen/android/lost/internal/LostClientManager.java @@ -38,14 +38,26 @@ public class LostClientManager implements ClientManager { private Map> clientToLocationCallbacks; private Map> clientCallbackToLoopers; + private Map listenerToLocationRequests; + private Map intentToLocationRequests; + private Map callbackToLocationRequests; + private Map requestToLastReportedTime; + private Map requestToLastReportedLocation; - private LostClientManager() { + public LostClientManager() { clients = new HashSet<>(); clientToListeners = new HashMap<>(); clientToPendingIntents = new HashMap<>(); clientToLocationCallbacks = new HashMap<>(); clientCallbackToLoopers = new HashMap<>(); + + listenerToLocationRequests = new HashMap<>(); + intentToLocationRequests = new HashMap<>(); + callbackToLocationRequests = new HashMap<>(); + requestToLastReportedTime = new HashMap<>(); + requestToLastReportedLocation = new HashMap<>(); + } public static LostClientManager shared() { @@ -83,6 +95,7 @@ public void addListener(LostApiClient client, LocationRequest request, } listeners.add(listener); clientToListeners.put(client, listeners); + listenerToLocationRequests.put(listener, request); } public void addPendingIntent(LostApiClient client, LocationRequest request, @@ -93,6 +106,7 @@ public void addPendingIntent(LostApiClient client, LocationRequest request, } intents.add(callbackIntent); clientToPendingIntents.put(client, intents); + intentToLocationRequests.put(callbackIntent, request); } public void addLocationCallback(LostApiClient client, LocationRequest request, @@ -110,6 +124,7 @@ public void addLocationCallback(LostApiClient client, LocationRequest request, } looperMap.put(callback, looper); clientCallbackToLoopers.put(client, looperMap); + callbackToLocationRequests.put(callback, request); } public boolean removeListener(LostApiClient client, LocationListener listener) { @@ -124,7 +139,7 @@ public boolean removeListener(LostApiClient client, LocationListener listener) { clientToListeners.remove(client); } } - + listenerToLocationRequests.remove(listener); return removedListener; } @@ -140,6 +155,7 @@ public boolean removePendingIntent(LostApiClient client, PendingIntent callbackI clientToPendingIntents.remove(client); } } + intentToLocationRequests.remove(callbackIntent); return removedPendingIntent; } @@ -163,51 +179,61 @@ public boolean removeLocationCallback(LostApiClient client, LocationCallback cal clientCallbackToLoopers.remove(client); } } + callbackToLocationRequests.remove(callback); return removedCallback; } - public void reportLocationChanged(Location location) { - for (LostApiClient client : clientToListeners.keySet()) { - if (clientToListeners.get(client) != null) { - for (LocationListener listener : clientToListeners.get(client)) { - listener.onLocationChanged(location); - } - } - } + /** + * Reports location changed for all listeners respecting their corresponding + * {@link LocationRequest#getFastestInterval()} and + * {@link LocationRequest#getSmallestDisplacement()} values. Returns a map of the updated + * last reported times so that {@code LostClientManager#requestToLastReportedTime} after + * all reporting (including pending intents and location callbacks) has been done. + * @param location + * @return + */ + public ReportedChanges reportLocationChanged(final Location location) { + return iterateAndNotify(location, + clientToListeners, listenerToLocationRequests, new Notifier() { + @Override void notify(LostApiClient client, LocationListener listener) { + listener.onLocationChanged(location); + } + }); } - public void sendPendingIntent(Context context, Location location, - LocationAvailability availability, LocationResult result) { - for (LostApiClient client : clientToPendingIntents.keySet()) { - if (clientToPendingIntents.get(client) != null) { - for (PendingIntent intent : clientToPendingIntents.get(client)) { - try { - Intent toSend = new Intent().putExtra(KEY_LOCATION_CHANGED, location); - toSend.putExtra(LocationAvailability.EXTRA_LOCATION_AVAILABILITY, availability); - toSend.putExtra(LocationResult.EXTRA_LOCATION_RESULT, result); - intent.send(context, 0, toSend); - } catch (PendingIntent.CanceledException e) { - Log.e(TAG, "Unable to send pending intent: " + intent); + /** + * Fires intent for all pending intents respecting their corresponding + * {@link LocationRequest#getFastestInterval()} and + * {@link LocationRequest#getSmallestDisplacement()} values. Returns a map of the updated + * last reported times so that {@code LostClientManager#requestToLastReportedTime} after + * all reporting (including pending intents and location callbacks) has been done. + * @param location + * @return + */ + public ReportedChanges sendPendingIntent(final Context context, + final Location location, final LocationAvailability availability, + final LocationResult result) { + return iterateAndNotify(location, + clientToPendingIntents, intentToLocationRequests, new Notifier() { + @Override void notify(LostApiClient client, PendingIntent pendingIntent) { + fireIntent(context, pendingIntent, location, availability, result); } - } - } - } + }); } - public void reportLocationResult(final LocationResult result) { - for (LostApiClient client : clientToLocationCallbacks.keySet()) { - if (clientToLocationCallbacks.get(client) != null) { - for (final LocationCallback callback : clientToLocationCallbacks.get(client)) { - Looper looper = clientCallbackToLoopers.get(client).get(callback); - Handler handler = new Handler(looper); - handler.post(new Runnable() { - @Override public void run() { - callback.onLocationResult(result); - } - }); - } - } - } + public ReportedChanges reportLocationResult(Location location, + final LocationResult result) { + return iterateAndNotify(location, + clientToLocationCallbacks, callbackToLocationRequests, new Notifier() { + @Override void notify(LostApiClient client, LocationCallback callback) { + notifyCallback(client, callback, result); + } + }); + } + + public void updateReportedValues(ReportedChanges changes) { + requestToLastReportedTime.putAll(changes.timeChanges()); + requestToLastReportedLocation.putAll(changes.locationChanges()); } public void reportProviderEnabled(String provider) { @@ -234,13 +260,7 @@ public void notifyLocationAvailability(final LocationAvailability availability) for (LostApiClient client : clientToLocationCallbacks.keySet()) { if (clientToLocationCallbacks.get(client) != null) { for (final LocationCallback callback : clientToLocationCallbacks.get(client)) { - Looper looper = clientCallbackToLoopers.get(client).get(callback); - Handler handler = new Handler(looper); - handler.post(new Runnable() { - @Override public void run() { - callback.onLocationAvailability(availability); - } - }); + notifyAvailability(client, callback, availability); } } } @@ -269,4 +289,75 @@ public Map> getPendingIntents() { public Map> getLocationCallbacks() { return clientToLocationCallbacks; } + + private void fireIntent(Context context, PendingIntent intent, Location location, + LocationAvailability availability, LocationResult result) { + try { + Intent toSend = new Intent().putExtra(KEY_LOCATION_CHANGED, location); + toSend.putExtra(LocationAvailability.EXTRA_LOCATION_AVAILABILITY, availability); + toSend.putExtra(LocationResult.EXTRA_LOCATION_RESULT, result); + intent.send(context, 0, toSend); + } catch (PendingIntent.CanceledException e) { + Log.e(TAG, "Unable to send pending intent: " + intent); + } + } + + private void notifyCallback(LostApiClient client, final LocationCallback callback, + final LocationResult result) { + Looper looper = clientCallbackToLoopers.get(client).get(callback); + Handler handler = new Handler(looper); + handler.post(new Runnable() { + @Override public void run() { + callback.onLocationResult(result); + } + }); + } + + private void notifyAvailability(LostApiClient client, final LocationCallback callback, + final LocationAvailability availability) { + Looper looper = clientCallbackToLoopers.get(client).get(callback); + Handler handler = new Handler(looper); + handler.post(new Runnable() { + @Override public void run() { + callback.onLocationAvailability(availability); + } + }); + } + + private ReportedChanges iterateAndNotify(Location location, + Map> clientToObj, Map objToLocationRequest, + Notifier notifier) { + Map updatedRequestToReportedTime = new HashMap<>(); + Map updatedRequestToReportedLocation = new HashMap<>(); + for (LostApiClient client : clientToObj.keySet()) { + if (clientToObj.get(client) != null) { + for (final T obj : clientToObj.get(client)) { + LocationRequest request = objToLocationRequest.get(obj); + Long lastReportedTime = requestToLastReportedTime.get(request); + Location lastReportedLocation = requestToLastReportedLocation.get(request); + if (lastReportedTime == null && lastReportedLocation == null) { + updatedRequestToReportedTime.put(request, System.currentTimeMillis()); + updatedRequestToReportedLocation.put(request, location); + notifier.notify(client, obj); + } else { + long intervalSinceLastReport = System.currentTimeMillis() - lastReportedTime; + long fastestInterval = request.getFastestInterval(); + float smallestDisplacement = request.getSmallestDisplacement(); + float displacementSinceLastReport = location.distanceTo(lastReportedLocation); + if (intervalSinceLastReport >= fastestInterval && + displacementSinceLastReport >= smallestDisplacement) { + updatedRequestToReportedTime.put(request, System.currentTimeMillis()); + updatedRequestToReportedLocation.put(request, location); + notifier.notify(client, obj); + } + } + } + } + } + return new ReportedChanges(updatedRequestToReportedTime, updatedRequestToReportedLocation); + } + + abstract class Notifier { + abstract void notify(LostApiClient client, T obj); + } } diff --git a/lost/src/main/java/com/mapzen/android/lost/internal/ReportedChanges.java b/lost/src/main/java/com/mapzen/android/lost/internal/ReportedChanges.java new file mode 100644 index 0000000..6bd49f5 --- /dev/null +++ b/lost/src/main/java/com/mapzen/android/lost/internal/ReportedChanges.java @@ -0,0 +1,40 @@ +package com.mapzen.android.lost.internal; + +import com.mapzen.android.lost.api.LocationRequest; + +import android.location.Location; + +import java.util.HashMap; +import java.util.Map; + +/** + * Represents changes to reported locations and times at which locations were reported for + * different modes of notification (listeners, pending intents, and callbacks). After all types of + * callbacks are invoked, these changes will be committed so that the next time a location is + * reported, the {@link FusedLocationProviderServiceImpl} can properly determine if it should be + * reported to listeners, pending intents, and callbacks. + */ +public class ReportedChanges { + + private Map updatedRequestToReportedTime; + private Map updatedRequestToReportedLocation; + + public ReportedChanges(Map timeChanges, + Map locationChanges) { + updatedRequestToReportedTime = timeChanges; + updatedRequestToReportedLocation = locationChanges; + } + + public Map timeChanges() { + return updatedRequestToReportedTime; + } + + public Map locationChanges() { + return updatedRequestToReportedLocation; + } + + public void putAll(ReportedChanges changes) { + updatedRequestToReportedTime.putAll(changes.timeChanges()); + updatedRequestToReportedLocation.putAll(changes.locationChanges()); + } +} diff --git a/lost/src/test/java/com/mapzen/android/lost/internal/FusedLocationProviderServiceImplTest.java b/lost/src/test/java/com/mapzen/android/lost/internal/FusedLocationProviderServiceImplTest.java index a312bcd..62f9bb5 100644 --- a/lost/src/test/java/com/mapzen/android/lost/internal/FusedLocationProviderServiceImplTest.java +++ b/lost/src/test/java/com/mapzen/android/lost/internal/FusedLocationProviderServiceImplTest.java @@ -810,6 +810,309 @@ private File getTestGpxTrace() throws IOException { assertThat(otherCallback.getAvailability()).isNull(); } + @Test public void reportLocation_shouldNotifyBothListeners() { + TestLocationListener listener = new TestLocationListener(); + client.connect(); + api.requestLocationUpdates(client, LocationRequest.create(), listener); + + TestLocationListener otherListener = new TestLocationListener(); + otherClient.connect(); + LocationRequest otherRequest = LocationRequest.create(); + api.requestLocationUpdates(otherClient, otherRequest, otherListener); + + Location location = new Location("test"); + api.reportLocation(location); + assertThat(listener.getAllLocations()).contains(location); + assertThat(otherListener.getAllLocations()).contains(location); + } + + @Test public void reportLocation_listener_shouldRespectFastestInterval() { + TestLocationListener listener = new TestLocationListener(); + client.connect(); + LocationRequest request = LocationRequest.create(); + request.setFastestInterval(1000); + api.requestLocationUpdates(client, request, listener); + + TestLocationListener otherListener = new TestLocationListener(); + otherClient.connect(); + LocationRequest otherRequest = LocationRequest.create(); + otherRequest.setFastestInterval(0); + api.requestLocationUpdates(otherClient, otherRequest, otherListener); + + api.reportLocation(new Location("test")); + listener.getAllLocations().clear(); + otherListener.getAllLocations().clear(); + + Location location = new Location("test"); + api.reportLocation(location); + assertThat(listener.getAllLocations()).isEmpty(); + assertThat(otherListener.getAllLocations().size()).isEqualTo(1); + } + + @Test public void reportLocation_listener_shouldRespectSmallestDisplacement() { + TestLocationListener listener = new TestLocationListener(); + client.connect(); + LocationRequest request = LocationRequest.create(); + request.setSmallestDisplacement(10); + api.requestLocationUpdates(client, request, listener); + + TestLocationListener otherListener = new TestLocationListener(); + otherClient.connect(); + LocationRequest otherRequest = LocationRequest.create(); + otherRequest.setFastestInterval(0); + api.requestLocationUpdates(otherClient, otherRequest, otherListener); + + api.reportLocation(new Location("test")); + listener.getAllLocations().clear(); + otherListener.getAllLocations().clear(); + + Location location = new Location("test"); + api.reportLocation(location); + assertThat(listener.getAllLocations()).isEmpty(); + assertThat(otherListener.getAllLocations().size()).isEqualTo(1); + } + + @Test public void reportLocation_listener_shouldRespectLargestIntervalAndSmallestDisplacement() + throws InterruptedException { + TestLocationListener listener = new TestLocationListener(); + client.connect(); + LocationRequest request = LocationRequest.create(); + request.setFastestInterval(1000); + request.setSmallestDisplacement(10); + api.requestLocationUpdates(client, request, listener); + + TestLocationListener otherListener = new TestLocationListener(); + otherClient.connect(); + LocationRequest otherRequest = LocationRequest.create(); + otherRequest.setFastestInterval(0); + api.requestLocationUpdates(otherClient, otherRequest, otherListener); + + api.reportLocation(new Location("test")); + listener.getAllLocations().clear(); + otherListener.getAllLocations().clear(); + + Location location = new Location("test"); + location.setLatitude(70.0); + location.setLongitude(40.0); + api.reportLocation(location); + assertThat(listener.getAllLocations()).isEmpty(); + assertThat(otherListener.getAllLocations().size()).isEqualTo(1); + + api.reportLocation(new Location("test")); + assertThat(listener.getAllLocations()).isEmpty(); + assertThat(otherListener.getAllLocations().size()).isEqualTo(2); + + Thread.sleep(1000); + api.reportLocation(location); + assertThat(listener.getAllLocations().size()).isEqualTo(1); + assertThat(otherListener.getAllLocations().size()).isEqualTo(3); + } + + @Test public void reportLocation_shouldNotifyBothPendingIntents() { + Intent intent = new Intent(application, TestService.class); + PendingIntent pendingIntent = PendingIntent.getService(application, 0, intent, 0); + client.connect(); + api.requestLocationUpdates(client, LocationRequest.create(), pendingIntent); + + Intent otherIntent = new Intent(application, TestService.class); + PendingIntent otherPendingIntent = PendingIntent.getService(application, 0, otherIntent, 0); + otherClient.connect(); + LocationRequest otherRequest = LocationRequest.create(); + api.requestLocationUpdates(otherClient, otherRequest, otherPendingIntent); + + Location location = new Location("test"); + api.reportLocation(location); + assertThat(ShadowApplication.getInstance().getNextStartedService()).isNotNull(); + assertThat(ShadowApplication.getInstance().getNextStartedService()).isNotNull(); + } + + @Test public void reportLocation_pendingIntent_shouldRespectFastestInterval() { + Intent intent = new Intent(application, TestService.class); + PendingIntent pendingIntent = PendingIntent.getService(application, 0, intent, 0); + client.connect(); + LocationRequest request = LocationRequest.create(); + request.setFastestInterval(1000); + api.requestLocationUpdates(client, request, pendingIntent); + + Intent otherIntent = new Intent(application, TestService.class); + PendingIntent otherPendingIntent = PendingIntent.getService(application, 0, otherIntent, 0); + otherClient.connect(); + LocationRequest otherRequest = LocationRequest.create(); + otherRequest.setFastestInterval(0); + api.requestLocationUpdates(otherClient, otherRequest, otherPendingIntent); + + api.reportLocation(new Location("test")); + assertThat(ShadowApplication.getInstance().getNextStartedService()).isNotNull(); + assertThat(ShadowApplication.getInstance().getNextStartedService()).isNotNull(); + + Location location = new Location("test"); + api.reportLocation(location); + assertThat(ShadowApplication.getInstance().getNextStartedService()).isNotNull(); + assertThat(ShadowApplication.getInstance().getNextStartedService()).isNull(); + } + + @Test public void reportLocation_pendingIntent_shouldRespectSmallestDisplacement() { + Intent intent = new Intent(application, TestService.class); + PendingIntent pendingIntent = PendingIntent.getService(application, 0, intent, 0); + client.connect(); + LocationRequest request = LocationRequest.create(); + request.setFastestInterval(1000); + api.requestLocationUpdates(client, request, pendingIntent); + + Intent otherIntent = new Intent(application, TestService.class); + PendingIntent otherPendingIntent = PendingIntent.getService(application, 0, otherIntent, 0); + otherClient.connect(); + LocationRequest otherRequest = LocationRequest.create(); + otherRequest.setFastestInterval(0); + api.requestLocationUpdates(otherClient, otherRequest, otherPendingIntent); + + api.reportLocation(new Location("test")); + assertThat(ShadowApplication.getInstance().getNextStartedService()).isNotNull(); + assertThat(ShadowApplication.getInstance().getNextStartedService()).isNotNull(); + + Location location = new Location("test"); + api.reportLocation(location); + assertThat(ShadowApplication.getInstance().getNextStartedService()).isNotNull(); + assertThat(ShadowApplication.getInstance().getNextStartedService()).isNull(); + } + + @Test public void reportLocation_pendingIntent_shouldRespectLargestIntervalAndSmallestDisplacement() + throws InterruptedException { + Intent intent = new Intent(application, TestService.class); + PendingIntent pendingIntent = PendingIntent.getService(application, 0, intent, 0); + client.connect(); + LocationRequest request = LocationRequest.create(); + request.setFastestInterval(1000); + request.setSmallestDisplacement(10); + api.requestLocationUpdates(client, request, pendingIntent); + + Intent otherIntent = new Intent(application, TestService.class); + PendingIntent otherPendingIntent = PendingIntent.getService(application, 0, otherIntent, 0); + otherClient.connect(); + LocationRequest otherRequest = LocationRequest.create(); + otherRequest.setFastestInterval(0); + api.requestLocationUpdates(otherClient, otherRequest, otherPendingIntent); + + + api.reportLocation(new Location("test")); + assertThat(ShadowApplication.getInstance().getNextStartedService()).isNotNull(); + assertThat(ShadowApplication.getInstance().getNextStartedService()).isNotNull(); + + Location location = new Location("test"); + location.setLatitude(70.0); + location.setLongitude(40.0); + api.reportLocation(location); + assertThat(ShadowApplication.getInstance().getNextStartedService()).isNotNull(); + assertThat(ShadowApplication.getInstance().getNextStartedService()).isNull(); + + api.reportLocation(new Location("test")); + assertThat(ShadowApplication.getInstance().getNextStartedService()).isNotNull(); + assertThat(ShadowApplication.getInstance().getNextStartedService()).isNull(); + + Thread.sleep(1000); + api.reportLocation(location); + assertThat(ShadowApplication.getInstance().getNextStartedService()).isNotNull(); + assertThat(ShadowApplication.getInstance().getNextStartedService()).isNotNull(); + } + + @Test public void reportLocation_shouldNotifyBothCallbacks() { + TestLocationCallback callback = new TestLocationCallback(); + client.connect(); + api.requestLocationUpdates(client, LocationRequest.create(), callback, Looper.myLooper()); + + TestLocationCallback otherCallback = new TestLocationCallback(); + otherClient.connect(); + LocationRequest otherRequest = LocationRequest.create(); + api.requestLocationUpdates(otherClient, otherRequest, otherCallback, Looper.myLooper()); + + Location location = new Location("test"); + api.reportLocation(location); + assertThat(callback.getResult()).isNotNull(); + assertThat(otherCallback.getResult()).isNotNull(); + } + + @Test public void reportLocation_callback_shouldRespectFastestInterval() { + TestLocationCallback callback = new TestLocationCallback(); + client.connect(); + LocationRequest request = LocationRequest.create(); + request.setFastestInterval(1000); + api.requestLocationUpdates(client, request, callback, Looper.myLooper()); + + TestLocationCallback otherCallback = new TestLocationCallback(); + otherClient.connect(); + LocationRequest otherRequest = LocationRequest.create(); + otherRequest.setFastestInterval(0); + api.requestLocationUpdates(otherClient, otherRequest, otherCallback, Looper.myLooper()); + + api.reportLocation(new Location("test")); + callback.setResult(null); + otherCallback.setResult(null); + + Location location = new Location("test"); + api.reportLocation(location); + assertThat(callback.getResult()).isNull(); + assertThat(otherCallback.getResult()).isNotNull(); + } + + @Test public void reportLocation_callback_shouldRespectSmallestDisplacement() { + TestLocationCallback callback = new TestLocationCallback(); + client.connect(); + LocationRequest request = LocationRequest.create(); + request.setSmallestDisplacement(10); + api.requestLocationUpdates(client, request, callback, Looper.myLooper()); + + TestLocationCallback otherCallback = new TestLocationCallback(); + otherClient.connect(); + LocationRequest otherRequest = LocationRequest.create(); + otherRequest.setFastestInterval(0); + api.requestLocationUpdates(otherClient, otherRequest, otherCallback, Looper.myLooper()); + + api.reportLocation(new Location("test")); + callback.setResult(null); + otherCallback.setResult(null); + + Location location = new Location("test"); + api.reportLocation(location); + assertThat(callback.getResult()).isNull(); + assertThat(otherCallback.getResult()).isNotNull(); + } + + @Test public void reportLocation_callback_shouldRespectLargestIntervalAndSmallestDisplacement() + throws InterruptedException { + TestLocationCallback callback = new TestLocationCallback(); + client.connect(); + LocationRequest request = LocationRequest.create(); + request.setFastestInterval(1000); + request.setSmallestDisplacement(10); + api.requestLocationUpdates(client, request, callback, Looper.myLooper()); + + TestLocationCallback otherCallback = new TestLocationCallback(); + otherClient.connect(); + LocationRequest otherRequest = LocationRequest.create(); + otherRequest.setFastestInterval(0); + api.requestLocationUpdates(otherClient, otherRequest, otherCallback, Looper.myLooper()); + + api.reportLocation(new Location("test")); + callback.setResult(null); + otherCallback.setResult(null); + + Location location = new Location("test"); + location.setLatitude(70.0); + location.setLongitude(40.0); + api.reportLocation(location); + assertThat(callback.getResult()).isNull(); + assertThat(otherCallback.getResult()).isNotNull(); + + api.reportLocation(new Location("test")); + assertThat(callback.getResult()).isNull(); + assertThat(otherCallback.getResult()).isNotNull(); + + Thread.sleep(1000); + api.reportLocation(location); + assertThat(callback.getResult()).isNotNull(); + assertThat(otherCallback.getResult()).isNotNull(); + } + @Test public void requestLocationUpdates_listener_shouldReturnFusedLocationPendingResult() { TestLocationListener listener = new TestLocationListener(); PendingResult result = api.requestLocationUpdates(client, LocationRequest.create(), diff --git a/lost/src/test/java/com/mapzen/android/lost/internal/LostApiClientImplTest.java b/lost/src/test/java/com/mapzen/android/lost/internal/LostApiClientImplTest.java index 8eb8d18..4d24556 100644 --- a/lost/src/test/java/com/mapzen/android/lost/internal/LostApiClientImplTest.java +++ b/lost/src/test/java/com/mapzen/android/lost/internal/LostApiClientImplTest.java @@ -32,7 +32,7 @@ public class LostApiClientImplTest { @Before public void setUp() throws Exception { callbacks = new TestConnectionCallbacks(); - client = new LostApiClientImpl(application, callbacks, new TestClientManager()); + client = new LostApiClientImpl(application, callbacks, new LostClientManager()); FusedLocationProviderService.FusedLocationProviderBinder stubBinder = mock(FusedLocationProviderService.FusedLocationProviderBinder.class); @@ -75,7 +75,7 @@ public class LostApiClientImplTest { client.connect(); TestConnectionCallbacks callbacks = new TestConnectionCallbacks(); LostApiClient anotherClient = - new LostApiClientImpl(application, callbacks, new TestClientManager()); + new LostApiClientImpl(application, callbacks, new LostClientManager()); callbacks.setLostClient(anotherClient); anotherClient.connect(); assertThat(callbacks.isClientConnectedOnConnect()).isTrue(); @@ -143,7 +143,7 @@ public class LostApiClientImplTest { @Test public void disconnect_multipleClients_shouldNotRemoveFusedLocationProviderApiImpl() throws Exception { LostApiClient anotherClient = - new LostApiClientImpl(application, callbacks, new TestClientManager()); + new LostApiClientImpl(application, callbacks, new LostClientManager()); anotherClient.connect(); client.connect(); client.disconnect(); @@ -152,7 +152,7 @@ public class LostApiClientImplTest { @Test public void disconnect_multipleClients_shouldNotRemoveGeofencingApiImpl() throws Exception { LostApiClient anotherClient = - new LostApiClientImpl(application, callbacks, new TestClientManager()); + new LostApiClientImpl(application, callbacks, new LostClientManager()); anotherClient.connect(); client.connect(); client.disconnect(); @@ -161,7 +161,7 @@ public class LostApiClientImplTest { @Test public void disconnect_multipleClients_shouldNotRemoveSettingsApiImpl() throws Exception { LostApiClient anotherClient = - new LostApiClientImpl(application, callbacks, new TestClientManager()); + new LostApiClientImpl(application, callbacks, new LostClientManager()); anotherClient.connect(); client.connect(); client.disconnect(); @@ -196,7 +196,7 @@ public class LostApiClientImplTest { @Test public void isConnected_multipleClients_shouldReturnFalseAfterDisconnected() throws Exception { LostApiClient anotherClient = - new LostApiClientImpl(application, callbacks, new TestClientManager()); + new LostApiClientImpl(application, callbacks, new LostClientManager()); anotherClient.connect(); client.connect(); client.disconnect(); diff --git a/lost/src/test/java/com/mapzen/android/lost/internal/LostClientManagerTest.java b/lost/src/test/java/com/mapzen/android/lost/internal/LostClientManagerTest.java index 1b1ccf2..0ae508a 100644 --- a/lost/src/test/java/com/mapzen/android/lost/internal/LostClientManagerTest.java +++ b/lost/src/test/java/com/mapzen/android/lost/internal/LostClientManagerTest.java @@ -142,7 +142,7 @@ public class LostClientManagerTest { ArrayList locations = new ArrayList<>(); locations.add(location); LocationResult result = LocationResult.create(locations); - manager.reportLocationResult(result); + manager.reportLocationResult(location, result); assertThat(callback.getResult()).isEqualTo(result); } diff --git a/lost/src/test/java/com/mapzen/android/lost/internal/TestClientManager.java b/lost/src/test/java/com/mapzen/android/lost/internal/TestClientManager.java deleted file mode 100644 index 2f3e4b4..0000000 --- a/lost/src/test/java/com/mapzen/android/lost/internal/TestClientManager.java +++ /dev/null @@ -1,110 +0,0 @@ -package com.mapzen.android.lost.internal; - -import com.mapzen.android.lost.api.LocationAvailability; -import com.mapzen.android.lost.api.LocationCallback; -import com.mapzen.android.lost.api.LocationListener; -import com.mapzen.android.lost.api.LocationRequest; -import com.mapzen.android.lost.api.LocationResult; -import com.mapzen.android.lost.api.LostApiClient; - -import android.app.PendingIntent; -import android.content.Context; -import android.location.Location; -import android.os.Looper; - -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - -public class TestClientManager implements ClientManager { - - private HashSet clients = new HashSet<>(); - - @Override public void addClient(LostApiClient client) { - clients.add(client); - } - - @Override public void removeClient(LostApiClient client) { - clients.remove(client); - } - - @Override public boolean containsClient(LostApiClient client) { - return clients.contains(client); - } - - @Override public int numberOfClients() { - return clients.size(); - } - - @Override public void addListener(LostApiClient client, LocationRequest request, - LocationListener listener) { - - } - - @Override public void addPendingIntent(LostApiClient client, LocationRequest request, - PendingIntent callbackIntent) { - - } - - @Override public void addLocationCallback(LostApiClient client, LocationRequest request, - LocationCallback callback, Looper looper) { - - } - - @Override public boolean removeListener(LostApiClient client, LocationListener listener) { - return false; - } - - @Override public boolean removePendingIntent(LostApiClient client, PendingIntent callbackIntent) { - return false; - } - - @Override public boolean removeLocationCallback(LostApiClient client, LocationCallback callback) { - return false; - } - - @Override public void reportLocationChanged(Location location) { - - } - - @Override public void sendPendingIntent(Context context, Location location, - LocationAvailability availability, LocationResult result) { - - } - - @Override public void reportLocationResult(LocationResult result) { - - } - - @Override public void reportProviderEnabled(String provider) { - - } - - @Override public void reportProviderDisabled(String provider) { - - } - - @Override public void notifyLocationAvailability(LocationAvailability availability) { - - } - - @Override public boolean hasNoListeners() { - return false; - } - - @Override public void shutdown() { - - } - - @Override public Map> getLocationListeners() { - return null; - } - - @Override public Map> getPendingIntents() { - return null; - } - - @Override public Map> getLocationCallbacks() { - return null; - } -} diff --git a/lost/src/test/java/com/mapzen/android/lost/internal/TestLocationCallback.java b/lost/src/test/java/com/mapzen/android/lost/internal/TestLocationCallback.java index 223b93e..307227b 100644 --- a/lost/src/test/java/com/mapzen/android/lost/internal/TestLocationCallback.java +++ b/lost/src/test/java/com/mapzen/android/lost/internal/TestLocationCallback.java @@ -24,4 +24,8 @@ public LocationAvailability getAvailability() { public LocationResult getResult() { return result; } + + public void setResult(LocationResult result) { + this.result = result; + } } From 50a95488d8708bad48e681451ce23cdaf4dafd2c Mon Sep 17 00:00:00 2001 From: Sarah Lensing Date: Fri, 2 Dec 2016 16:26:44 -0700 Subject: [PATCH 2/6] Checkstyle --- .../java/com/mapzen/android/lost/internal/ClientManager.java | 4 ++-- .../com/mapzen/android/lost/internal/ReportedChanges.java | 1 - .../lost/internal/FusedLocationProviderServiceImplTest.java | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/lost/src/main/java/com/mapzen/android/lost/internal/ClientManager.java b/lost/src/main/java/com/mapzen/android/lost/internal/ClientManager.java index 0fac01d..fc664b8 100644 --- a/lost/src/main/java/com/mapzen/android/lost/internal/ClientManager.java +++ b/lost/src/main/java/com/mapzen/android/lost/internal/ClientManager.java @@ -35,8 +35,8 @@ void addLocationCallback(LostApiClient client, LocationRequest request, boolean removePendingIntent(LostApiClient client, PendingIntent callbackIntent); boolean removeLocationCallback(LostApiClient client, LocationCallback callback); ReportedChanges reportLocationChanged(Location location); - ReportedChanges sendPendingIntent(Context context, Location location, LocationAvailability availability, - LocationResult result); + ReportedChanges sendPendingIntent(Context context, Location location, + LocationAvailability availability, LocationResult result); ReportedChanges reportLocationResult(Location location, final LocationResult result); void updateReportedValues(ReportedChanges changes); void reportProviderEnabled(String provider); diff --git a/lost/src/main/java/com/mapzen/android/lost/internal/ReportedChanges.java b/lost/src/main/java/com/mapzen/android/lost/internal/ReportedChanges.java index 6bd49f5..9ee592a 100644 --- a/lost/src/main/java/com/mapzen/android/lost/internal/ReportedChanges.java +++ b/lost/src/main/java/com/mapzen/android/lost/internal/ReportedChanges.java @@ -4,7 +4,6 @@ import android.location.Location; -import java.util.HashMap; import java.util.Map; /** diff --git a/lost/src/test/java/com/mapzen/android/lost/internal/FusedLocationProviderServiceImplTest.java b/lost/src/test/java/com/mapzen/android/lost/internal/FusedLocationProviderServiceImplTest.java index 62f9bb5..c4b8145 100644 --- a/lost/src/test/java/com/mapzen/android/lost/internal/FusedLocationProviderServiceImplTest.java +++ b/lost/src/test/java/com/mapzen/android/lost/internal/FusedLocationProviderServiceImplTest.java @@ -976,7 +976,7 @@ private File getTestGpxTrace() throws IOException { assertThat(ShadowApplication.getInstance().getNextStartedService()).isNull(); } - @Test public void reportLocation_pendingIntent_shouldRespectLargestIntervalAndSmallestDisplacement() + @Test public void reportLocation_pendingIntent_shouldRespectLargestIntervalSmallestDisplacement() throws InterruptedException { Intent intent = new Intent(application, TestService.class); PendingIntent pendingIntent = PendingIntent.getService(application, 0, intent, 0); From e9898570c6fd3cb12e9e7a3c154841bbf3bcd5a9 Mon Sep 17 00:00:00 2001 From: Sarah Lensing Date: Wed, 4 Jan 2017 13:46:01 -0700 Subject: [PATCH 3/6] Refactor to use ReportedChanges obj --- .../android/lost/internal/LostClientManager.java | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/lost/src/main/java/com/mapzen/android/lost/internal/LostClientManager.java b/lost/src/main/java/com/mapzen/android/lost/internal/LostClientManager.java index 9f2d94b..d08d8ed 100644 --- a/lost/src/main/java/com/mapzen/android/lost/internal/LostClientManager.java +++ b/lost/src/main/java/com/mapzen/android/lost/internal/LostClientManager.java @@ -41,8 +41,7 @@ public class LostClientManager implements ClientManager { private Map listenerToLocationRequests; private Map intentToLocationRequests; private Map callbackToLocationRequests; - private Map requestToLastReportedTime; - private Map requestToLastReportedLocation; + private ReportedChanges reportedChanges; public LostClientManager() { clients = new HashSet<>(); @@ -55,9 +54,9 @@ public LostClientManager() { listenerToLocationRequests = new HashMap<>(); intentToLocationRequests = new HashMap<>(); callbackToLocationRequests = new HashMap<>(); - requestToLastReportedTime = new HashMap<>(); - requestToLastReportedLocation = new HashMap<>(); + reportedChanges = new ReportedChanges(new HashMap(), + new HashMap()); } public static LostClientManager shared() { @@ -232,8 +231,7 @@ public ReportedChanges reportLocationResult(Location location, } public void updateReportedValues(ReportedChanges changes) { - requestToLastReportedTime.putAll(changes.timeChanges()); - requestToLastReportedLocation.putAll(changes.locationChanges()); + reportedChanges.putAll(changes); } public void reportProviderEnabled(String provider) { @@ -333,8 +331,8 @@ private ReportedChanges iterateAndNotify(Location location, if (clientToObj.get(client) != null) { for (final T obj : clientToObj.get(client)) { LocationRequest request = objToLocationRequest.get(obj); - Long lastReportedTime = requestToLastReportedTime.get(request); - Location lastReportedLocation = requestToLastReportedLocation.get(request); + Long lastReportedTime = reportedChanges.timeChanges().get(request); + Location lastReportedLocation = reportedChanges.locationChanges().get(request); if (lastReportedTime == null && lastReportedLocation == null) { updatedRequestToReportedTime.put(request, System.currentTimeMillis()); updatedRequestToReportedLocation.put(request, location); From f10b5c8eae5b92a062f595a29c3a02e6fd88768b Mon Sep 17 00:00:00 2001 From: Sarah Lensing Date: Wed, 4 Jan 2017 13:49:16 -0700 Subject: [PATCH 4/6] change Notifier to interface --- .../android/lost/internal/LostClientManager.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lost/src/main/java/com/mapzen/android/lost/internal/LostClientManager.java b/lost/src/main/java/com/mapzen/android/lost/internal/LostClientManager.java index d08d8ed..0664945 100644 --- a/lost/src/main/java/com/mapzen/android/lost/internal/LostClientManager.java +++ b/lost/src/main/java/com/mapzen/android/lost/internal/LostClientManager.java @@ -192,9 +192,9 @@ public boolean removeLocationCallback(LostApiClient client, LocationCallback cal * @return */ public ReportedChanges reportLocationChanged(final Location location) { - return iterateAndNotify(location, - clientToListeners, listenerToLocationRequests, new Notifier() { - @Override void notify(LostApiClient client, LocationListener listener) { + return iterateAndNotify(location, clientToListeners, listenerToLocationRequests, + new Notifier() { + @Override public void notify(LostApiClient client, LocationListener listener) { listener.onLocationChanged(location); } }); @@ -214,7 +214,7 @@ public ReportedChanges sendPendingIntent(final Context context, final LocationResult result) { return iterateAndNotify(location, clientToPendingIntents, intentToLocationRequests, new Notifier() { - @Override void notify(LostApiClient client, PendingIntent pendingIntent) { + @Override public void notify(LostApiClient client, PendingIntent pendingIntent) { fireIntent(context, pendingIntent, location, availability, result); } }); @@ -224,7 +224,7 @@ public ReportedChanges reportLocationResult(Location location, final LocationResult result) { return iterateAndNotify(location, clientToLocationCallbacks, callbackToLocationRequests, new Notifier() { - @Override void notify(LostApiClient client, LocationCallback callback) { + @Override public void notify(LostApiClient client, LocationCallback callback) { notifyCallback(client, callback, result); } }); @@ -355,7 +355,7 @@ private ReportedChanges iterateAndNotify(Location location, return new ReportedChanges(updatedRequestToReportedTime, updatedRequestToReportedLocation); } - abstract class Notifier { - abstract void notify(LostApiClient client, T obj); + interface Notifier { + void notify(LostApiClient client, T obj); } } From 5a2d08e98cb1e2dd9680f732d70ce0b2a191a244 Mon Sep 17 00:00:00 2001 From: Sarah Lensing Date: Wed, 4 Jan 2017 16:00:27 -0700 Subject: [PATCH 5/6] Add interval example activities --- lost-sample/src/main/AndroidManifest.xml | 2 + .../src/main/java/com/example/lost/Item.java | 20 ++ .../java/com/example/lost/ListActivity.java | 64 ++++++ ...cationListenerMultipleClientsActivity.java | 189 ++++++++++++++++++ ...eLocationListenerSingleClientActivity.java | 156 +++++++++++++++ .../java/com/example/lost/SamplesList.java | 6 + lost-sample/src/main/res/values/strings.xml | 4 + 7 files changed, 441 insertions(+) create mode 100644 lost-sample/src/main/java/com/example/lost/Item.java create mode 100644 lost-sample/src/main/java/com/example/lost/ListActivity.java create mode 100644 lost-sample/src/main/java/com/example/lost/MultipleLocationListenerMultipleClientsActivity.java create mode 100644 lost-sample/src/main/java/com/example/lost/MultipleLocationListenerSingleClientActivity.java diff --git a/lost-sample/src/main/AndroidManifest.xml b/lost-sample/src/main/AndroidManifest.xml index 9728581..ee4d945 100644 --- a/lost-sample/src/main/AndroidManifest.xml +++ b/lost-sample/src/main/AndroidManifest.xml @@ -35,6 +35,8 @@ + + getItems(); + + @Override protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_list_view); + setupListView(); + } + + private void setupListView() { + listView = (ListView) findViewById(R.id.list_view); + listView.setAdapter(new BaseAdapter() { + @Override public int getCount() { + return numOfItems(); + } + + @Override public Object getItem(int position) { + return null; + } + + @Override public long getItemId(int position) { + return 0; + } + + @Override public View getView(int position, View convertView, ViewGroup parent) { + View view; + ViewHolder holder; + if (convertView == null) { + view = LayoutInflater.from(ListActivity.this).inflate(R.layout.sample_item, parent, + false); + holder = new ViewHolder(view); + view.setTag(holder); + } else { + view = convertView; + holder = (ViewHolder) view.getTag(); + } + Item item = getItems().get(position); + holder.title.setText(item.getTitle()); + holder.description.setText(item.getDetail()); + return view; + } + }); + } +} diff --git a/lost-sample/src/main/java/com/example/lost/MultipleLocationListenerMultipleClientsActivity.java b/lost-sample/src/main/java/com/example/lost/MultipleLocationListenerMultipleClientsActivity.java new file mode 100644 index 0000000..795afaf --- /dev/null +++ b/lost-sample/src/main/java/com/example/lost/MultipleLocationListenerMultipleClientsActivity.java @@ -0,0 +1,189 @@ +package com.example.lost; + +import com.mapzen.android.lost.api.LocationListener; +import com.mapzen.android.lost.api.LocationRequest; +import com.mapzen.android.lost.api.LocationServices; +import com.mapzen.android.lost.api.LostApiClient; + +import android.Manifest; +import android.app.FragmentManager; +import android.content.pm.PackageManager; +import android.location.Location; +import android.os.Bundle; +import android.support.v4.app.ActivityCompat; +import android.widget.BaseAdapter; + +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +/** + * Demonstrates two {@link LostApiClient}s receiving location updates at difference intervals + */ +public class MultipleLocationListenerMultipleClientsActivity extends ListActivity + implements LocationListener { + + private static final int LOCATION_PERMISSION_REQUEST = 1; + + LostApiClient lostApiClient; + LostClientFragment fragment; + List items = new ArrayList<>(); + + @Override int numOfItems() { + return items.size(); + } + + @Override List getItems() { + return items; + } + + @Override protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + final FragmentManager fragmentManager = getFragmentManager(); + final String fragTag = "Frag"; + fragment = (LostClientFragment) fragmentManager.findFragmentByTag(fragTag); + if (fragment == null) { + fragment = new LostClientFragment(); + fragmentManager.beginTransaction() + .add(android.R.id.content, fragment, fragTag) + .commit(); + } + + lostApiClient = new LostApiClient.Builder(this).addConnectionCallbacks( + new LostApiClient.ConnectionCallbacks() { + @Override + public void onConnected() { + initLocationTracking(); + } + + @Override + public void onConnectionSuspended() { + + } + }).build(); + } + + @Override public void onStart() { + super.onStart(); + lostApiClient.connect(); + } + + @Override public void onStop() { + super.onStop(); + LocationServices.FusedLocationApi.removeLocationUpdates(lostApiClient, + MultipleLocationListenerMultipleClientsActivity.this); + fragment.removeLocationUpdates(); + lostApiClient.disconnect(); + } + + private void initLocationTracking() { + if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) + != PackageManager.PERMISSION_GRANTED) { + ActivityCompat.requestPermissions( + this, new String[]{ Manifest.permission.ACCESS_FINE_LOCATION }, + LOCATION_PERMISSION_REQUEST); + return; + } + + long interval = 3 * 60 * 1000; // 3 minutes + LocationRequest request = LocationRequest.create() + .setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY) + .setFastestInterval(interval) + .setInterval(interval); + + LocationServices.FusedLocationApi.requestLocationUpdates(lostApiClient, request, this); + } + + @Override public void onLocationChanged(Location location) { + addItem("Activity"); + } + + @Override public void onProviderDisabled(String provider) { + + } + + @Override public void onProviderEnabled(String provider) { + + } + + public void addItem(String title) { + Date date = new Date(System.currentTimeMillis()); + SimpleDateFormat dateformat = new SimpleDateFormat("HH:mm:ss"); + StringBuilder dateString = new StringBuilder(dateformat.format(date)); + String description = dateString.toString(); + Item item = new Item(title, description); + items.add(item); + BaseAdapter adapter = (BaseAdapter) listView.getAdapter(); + adapter.notifyDataSetChanged(); + } + + public static class LostClientFragment extends android.app.Fragment implements LocationListener { + + private static final int LOCATION_PERMISSION_REQUEST = 2; + + LostApiClient fragmentClient; + + @Override public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + fragmentClient = new LostApiClient.Builder(this.getActivity()).addConnectionCallbacks( + new LostApiClient.ConnectionCallbacks() { + @Override + public void onConnected() { + fragmentInitLocationTracking(); + } + + @Override + public void onConnectionSuspended() { + + } + }).build(); + } + + @Override public void onStart() { + super.onStart(); + fragmentClient.connect(); + } + + public void removeLocationUpdates() { + LocationServices.FusedLocationApi.removeLocationUpdates(fragmentClient, this); + } + + @Override public void onStop() { + super.onStop(); + fragmentClient.disconnect(); + } + + private void fragmentInitLocationTracking() { + if (ActivityCompat.checkSelfPermission(this.getActivity(), + Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) { + ActivityCompat.requestPermissions(this.getActivity(), new String[]{ + Manifest.permission.ACCESS_FINE_LOCATION }, LOCATION_PERMISSION_REQUEST); + return; + } + + long interval = 30 * 1000; // 30 sec + LocationRequest request = LocationRequest.create() + .setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY) + .setFastestInterval(interval) + .setInterval(interval); + + LocationServices.FusedLocationApi.requestLocationUpdates(fragmentClient, request, this); + } + + @Override public void onLocationChanged(Location location) { + MultipleLocationListenerMultipleClientsActivity a = + (MultipleLocationListenerMultipleClientsActivity) getActivity(); + a.addItem("Fragment"); + } + + @Override public void onProviderDisabled(String provider) { + + } + + @Override public void onProviderEnabled(String provider) { + + } + } + +} diff --git a/lost-sample/src/main/java/com/example/lost/MultipleLocationListenerSingleClientActivity.java b/lost-sample/src/main/java/com/example/lost/MultipleLocationListenerSingleClientActivity.java new file mode 100644 index 0000000..39cc87d --- /dev/null +++ b/lost-sample/src/main/java/com/example/lost/MultipleLocationListenerSingleClientActivity.java @@ -0,0 +1,156 @@ +package com.example.lost; + +import com.mapzen.android.lost.api.LocationListener; +import com.mapzen.android.lost.api.LocationRequest; +import com.mapzen.android.lost.api.LocationServices; +import com.mapzen.android.lost.api.LostApiClient; + +import android.Manifest; +import android.content.pm.PackageManager; +import android.location.Location; +import android.os.Bundle; +import android.support.v4.app.ActivityCompat; +import android.widget.BaseAdapter; + +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +/** + * Demonstrates one {@link LostApiClient}s receiving location updates at difference intervals + */ +public class MultipleLocationListenerSingleClientActivity extends ListActivity { + + private static final int LOCATION_PERMISSION_REQUEST = 1; + + LostApiClient lostApiClient; + LostApiClient otherLostApiClient; + List items = new ArrayList<>(); + + LocationListener listener = new LocationListener() { + @Override public void onLocationChanged(Location location) { + addItem("Client"); + } + + @Override public void onProviderDisabled(String provider) { + + } + + @Override public void onProviderEnabled(String provider) { + + } + }; + + LocationListener otherListener = new LocationListener() { + @Override public void onLocationChanged(Location location) { + addItem("Other Client"); + } + + @Override public void onProviderDisabled(String provider) { + + } + + @Override public void onProviderEnabled(String provider) { + + } + }; + + @Override int numOfItems() { + return items.size(); + } + + @Override List getItems() { + return items; + } + + @Override protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + lostApiClient = new LostApiClient.Builder(this).addConnectionCallbacks( + new LostApiClient.ConnectionCallbacks() { + @Override + public void onConnected() { + initLocationTracking(); + } + + @Override + public void onConnectionSuspended() { + + } + }).build(); + + otherLostApiClient = new LostApiClient.Builder(this).addConnectionCallbacks( + new LostApiClient.ConnectionCallbacks() { + @Override + public void onConnected() { + initOtherLocationTracking(); + } + + @Override + public void onConnectionSuspended() { } + }).build(); + } + + @Override public void onStart() { + super.onStart(); + lostApiClient.connect(); + otherLostApiClient.connect(); + } + + @Override public void onStop() { + super.onStop(); + LocationServices.FusedLocationApi.removeLocationUpdates(lostApiClient, listener); + lostApiClient.disconnect(); + LocationServices.FusedLocationApi.removeLocationUpdates(otherLostApiClient, otherListener); + otherLostApiClient.disconnect(); + } + + private void initLocationTracking() { + if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) + != PackageManager.PERMISSION_GRANTED) { + ActivityCompat.requestPermissions( + this, new String[]{ Manifest.permission.ACCESS_FINE_LOCATION }, + LOCATION_PERMISSION_REQUEST); + return; + } + + long interval = 3 * 60 * 1000; // 3 minutes + LocationRequest request = LocationRequest.create() + .setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY) + .setFastestInterval(interval) + .setInterval(interval); + + LocationServices.FusedLocationApi.requestLocationUpdates(lostApiClient, request, listener); + } + + private void initOtherLocationTracking() { + if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) + != PackageManager.PERMISSION_GRANTED) { + ActivityCompat.requestPermissions( + this, new String[]{ Manifest.permission.ACCESS_FINE_LOCATION }, + LOCATION_PERMISSION_REQUEST); + return; + } + + long interval = 30 * 1000; // 30 seconds + LocationRequest request = LocationRequest.create() + .setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY) + .setFastestInterval(interval) + .setInterval(interval); + + LocationServices.FusedLocationApi.requestLocationUpdates(otherLostApiClient, request, + otherListener); + } + + public void addItem(String title) { + Date date = new Date(System.currentTimeMillis()); + SimpleDateFormat dateformat = new SimpleDateFormat("HH:mm:ss"); + StringBuilder dateString = new StringBuilder(dateformat.format(date)); + String description = dateString.toString(); + Item item = new Item(title, description); + items.add(item); + BaseAdapter adapter = (BaseAdapter) listView.getAdapter(); + adapter.notifyDataSetChanged(); + } +} diff --git a/lost-sample/src/main/java/com/example/lost/SamplesList.java b/lost-sample/src/main/java/com/example/lost/SamplesList.java index 49a6030..9e0ae13 100644 --- a/lost-sample/src/main/java/com/example/lost/SamplesList.java +++ b/lost-sample/src/main/java/com/example/lost/SamplesList.java @@ -17,6 +17,12 @@ private SamplesList() { public static final Sample[] FUSED_API_SAMPLES = { new Sample(R.string.sample_location_listener_title, R.string.sample_location_listener_description, LocationListenerActivity.class), + new Sample(R.string.sample_multiple_clients_diff_intervals_title, + R.string.sample_multiple_clients_diff_intervals_description, + MultipleLocationListenerMultipleClientsActivity.class), + new Sample(R.string.sample_single_client_diff_intervals_title, + R.string.sample_single_client_diff_intervals_description, + MultipleLocationListenerSingleClientActivity.class), new Sample(R.string.sample_pending_intent_title, R.string.sample_pending_intent_description, PendingIntentActivity.class), new Sample(R.string.sample_location_availability_title, diff --git a/lost-sample/src/main/res/values/strings.xml b/lost-sample/src/main/res/values/strings.xml index 9991369..26c2ac8 100644 --- a/lost-sample/src/main/res/values/strings.xml +++ b/lost-sample/src/main/res/values/strings.xml @@ -76,5 +76,9 @@ Check Availability Location Available Location NOT Available + Multiple Clients w/different Intervals + Demonstrates how multiple clients can request location updates at different fastest intervals + Single Client w/different Intervals + Demonstrates how a single client can request location updates at different fastest intervals From b8c236f195eb6050a9ae29abb13cd955ca30b8ee Mon Sep 17 00:00:00 2001 From: Sarah Lensing Date: Thu, 5 Jan 2017 14:19:31 -0700 Subject: [PATCH 6/6] Actually make single client single client --- ...eLocationListenerSingleClientActivity.java | 37 +++---------------- 1 file changed, 6 insertions(+), 31 deletions(-) diff --git a/lost-sample/src/main/java/com/example/lost/MultipleLocationListenerSingleClientActivity.java b/lost-sample/src/main/java/com/example/lost/MultipleLocationListenerSingleClientActivity.java index 39cc87d..c668582 100644 --- a/lost-sample/src/main/java/com/example/lost/MultipleLocationListenerSingleClientActivity.java +++ b/lost-sample/src/main/java/com/example/lost/MultipleLocationListenerSingleClientActivity.java @@ -25,12 +25,11 @@ public class MultipleLocationListenerSingleClientActivity extends ListActivity { private static final int LOCATION_PERMISSION_REQUEST = 1; LostApiClient lostApiClient; - LostApiClient otherLostApiClient; List items = new ArrayList<>(); LocationListener listener = new LocationListener() { @Override public void onLocationChanged(Location location) { - addItem("Client"); + addItem("Listener"); } @Override public void onProviderDisabled(String provider) { @@ -44,7 +43,7 @@ public class MultipleLocationListenerSingleClientActivity extends ListActivity { LocationListener otherListener = new LocationListener() { @Override public void onLocationChanged(Location location) { - addItem("Other Client"); + addItem("Other Listener"); } @Override public void onProviderDisabled(String provider) { @@ -79,31 +78,18 @@ public void onConnectionSuspended() { } }).build(); - - otherLostApiClient = new LostApiClient.Builder(this).addConnectionCallbacks( - new LostApiClient.ConnectionCallbacks() { - @Override - public void onConnected() { - initOtherLocationTracking(); - } - - @Override - public void onConnectionSuspended() { } - }).build(); } @Override public void onStart() { super.onStart(); lostApiClient.connect(); - otherLostApiClient.connect(); } @Override public void onStop() { super.onStop(); LocationServices.FusedLocationApi.removeLocationUpdates(lostApiClient, listener); + LocationServices.FusedLocationApi.removeLocationUpdates(lostApiClient, otherListener); lostApiClient.disconnect(); - LocationServices.FusedLocationApi.removeLocationUpdates(otherLostApiClient, otherListener); - otherLostApiClient.disconnect(); } private void initLocationTracking() { @@ -122,25 +108,14 @@ private void initLocationTracking() { .setInterval(interval); LocationServices.FusedLocationApi.requestLocationUpdates(lostApiClient, request, listener); - } - private void initOtherLocationTracking() { - if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) - != PackageManager.PERMISSION_GRANTED) { - ActivityCompat.requestPermissions( - this, new String[]{ Manifest.permission.ACCESS_FINE_LOCATION }, - LOCATION_PERMISSION_REQUEST); - return; - } - - long interval = 30 * 1000; // 30 seconds - LocationRequest request = LocationRequest.create() + interval = 30 * 1000; // 30 seconds + request = LocationRequest.create() .setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY) .setFastestInterval(interval) .setInterval(interval); - LocationServices.FusedLocationApi.requestLocationUpdates(otherLostApiClient, request, - otherListener); + LocationServices.FusedLocationApi.requestLocationUpdates(lostApiClient, request, otherListener); } public void addItem(String title) {