summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorŁukasz Paczos <lukas.paczos@gmail.com>2019-09-03 15:40:09 +0200
committerŁukasz Paczos <lukas.paczos@gmail.com>2019-09-03 15:40:09 +0200
commit3c8120dca00e2ef61c98515467356cd07e505018 (patch)
tree53cca69e00f5790a2c656a70281e134ae7f9f8a3
parent4ba1270dcc0a51c7c68be2bfbac283ee76ea8680 (diff)
downloadqtlocation-mapboxgl-3c8120dca00e2ef61c98515467356cd07e505018.tar.gz
[android][wip] basic animation thread and target animation
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/CameraTransition.java98
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapCameraController.java227
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java9
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java9
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/TargetCameraTransition.java29
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Transform.java9
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapCameraControllerTest.java7
7 files changed, 386 insertions, 2 deletions
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/CameraTransition.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/CameraTransition.java
new file mode 100644
index 0000000000..7132effce1
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/CameraTransition.java
@@ -0,0 +1,98 @@
+package com.mapbox.mapboxsdk.maps;
+
+public abstract class CameraTransition<T> {
+
+ static final int PROPERTY_CENTER = 0;
+ static final int PROPERTY_ZOOM = 1;
+ static final int PROPERTY_PITCH = 2;
+ static final int PROPERTY_BEARING = 3;
+ static final int PROPERTY_ANCHOR = 4;
+ static final int PROPERTY_PADDING = 5;
+
+ public static final int TYPE_ANY = 0;
+ public static final int TYPE_GESTURE = 1;
+ public static final int TYPE_LOCATION = 2;
+
+ private final int type;
+ T startValue;
+ protected final T endValue;
+ double startTime;
+ protected final double duration;
+ private final double delay;
+ protected final double endTime;
+ protected boolean canceled;
+ private boolean isFinishing;
+
+ CameraTransition(int type, double duration, double delay, T endValue) {
+ this.type = type;
+ this.startTime = System.currentTimeMillis() + delay;
+ this.duration = duration;
+ this.delay = delay;
+ this.endTime = startTime + duration;
+ this.endValue = endValue;
+ }
+
+ public int getType() {
+ return type;
+ }
+
+ public void cancel() {
+ canceled = true;
+ }
+
+ public T getStartValue() {
+ return startValue;
+ }
+
+ void setStartValue(T startValue) {
+ this.startValue = startValue;
+ }
+
+ public T getEndValue() {
+ return endValue;
+ }
+
+ public boolean isCanceled() {
+ return canceled;
+ }
+
+ public double getStartTime() {
+ return startTime;
+ }
+
+ void setStartTime(double startTime) {
+ this.startTime = startTime;
+ }
+
+ public double getDuration() {
+ return duration;
+ }
+
+ public double getDelay() {
+ return delay;
+ }
+
+ public double getEndTime() {
+ return endTime;
+ }
+
+ abstract int getCameraProperty();
+
+ abstract T onFrame(double currentTime);
+
+ boolean isFinishing() {
+ return isFinishing;
+ }
+
+ void setFinishing() {
+ isFinishing = true;
+ }
+
+ void onCancel() {
+ // todo camera - notify listeners
+ }
+
+ void onFinish() {
+ // todo camera - notify listeners
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapCameraController.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapCameraController.java
new file mode 100644
index 0000000000..2156b5f744
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapCameraController.java
@@ -0,0 +1,227 @@
+package com.mapbox.mapboxsdk.maps;
+
+import android.os.Handler;
+import android.os.Looper;
+import android.support.annotation.NonNull;
+
+import com.mapbox.mapboxsdk.camera.CameraPosition;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+
+public class MapCameraController {
+
+ @NonNull
+ private final List<CameraTransition> queuedTransitions = new ArrayList<>();
+
+ @NonNull
+ private final HashMap<Integer, CameraTransition> runningTransitions = new HashMap<>(5);
+
+ @NonNull
+ private CameraBehavior behavior = new DefaultCameraBehavior();
+
+ @NonNull
+ private final Handler handler = new Handler(Looper.getMainLooper());
+
+ @NonNull
+ private final Transform transform;
+
+ private volatile boolean destroyed;
+
+ @NonNull
+ private final Thread thread = new Thread(new Runnable() {
+ @Override
+ public void run() {
+ CameraPosition cameraPosition = null;
+ while (true) {
+ if (destroyed) {
+ return;
+ }
+
+ final CameraPosition update = cameraPosition;
+ if (!runningTransitions.isEmpty()) {
+ handler.post(new Runnable() {
+ @Override
+ public void run() {
+ CameraPosition finalUpdate = update;
+
+ Iterator<CameraTransition> iterator = runningTransitions.values().iterator();
+ while (iterator.hasNext()) {
+ CameraTransition transition = iterator.next();
+ if (transition.isCanceled()) {
+ transition.onCancel();
+ iterator.remove();
+ CameraPosition.Builder builder = new CameraPosition.Builder(finalUpdate);
+ if (transition.getCameraProperty() == CameraTransition.PROPERTY_CENTER) {
+ builder.target(null);
+ }
+ finalUpdate = builder.build();
+ }
+ }
+
+ // todo camera - check if update is noop, abort then
+
+ if (finalUpdate != null && finalUpdate.target != null) {
+ // todo camera - remove if-check
+ transform.moveCamera(finalUpdate);
+ }
+
+ iterator = runningTransitions.values().iterator();
+ while (iterator.hasNext()) {
+ CameraTransition transition = iterator.next();
+ if (transition.isFinishing()) {
+ transition.onFinish();
+ iterator.remove();
+ }
+ }
+ }
+ });
+ }
+
+ // todo camera - what's the correct delay not to flood and block the main thread?
+ double nextFrameTime = System.currentTimeMillis() + 5;
+
+ if (!runningTransitions.isEmpty()) {
+ boolean willRun = false;
+ for (CameraTransition transition : runningTransitions.values()) {
+ if (transition.startTime <= nextFrameTime) {
+ willRun = true;
+ break;
+ }
+ }
+
+ if (willRun) {
+ CameraPosition.Builder builder = new CameraPosition.Builder();
+
+ TargetCameraTransition targetCameraTransition =
+ (TargetCameraTransition) runningTransitions.get(CameraTransition.PROPERTY_CENTER);
+ if (targetCameraTransition != null && targetCameraTransition.startTime <= nextFrameTime) {
+ if (nextFrameTime >= targetCameraTransition.endTime) {
+ builder.target(targetCameraTransition.endValue);
+ targetCameraTransition.setFinishing();
+ } else {
+ builder.target(targetCameraTransition.onFrame(nextFrameTime));
+ }
+
+ cameraPosition = builder.build();
+ }
+ } else {
+ cameraPosition = null;
+ }
+
+ } else {
+ cameraPosition = null;
+ }
+
+ double sleepTime = nextFrameTime - System.currentTimeMillis();
+ int nanos = (int) (sleepTime % 999_999);
+
+ try {
+ Thread.sleep((long) sleepTime, nanos);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ }, "MapCameraController");
+
+ MapCameraController(@NonNull final Transform transform) {
+ this.transform = transform;
+ thread.start();
+ }
+
+ public void startTransition(final CameraTransition transition) {
+ transition.setStartTime(System.currentTimeMillis() + transition.getDelay());
+ switch (transition.getCameraProperty()) {
+ case CameraTransition.PROPERTY_CENTER:
+ transition.setStartValue(transform.getCameraPosition().target);
+ break;
+ }
+
+ behavior.animationScheduled(this, transition);
+
+ final CameraTransition runningTransition = runningTransitions.get(transition.getCameraProperty());
+ if (runningTransition != null) {
+ CameraTransition resultingTransition = behavior.resolve(runningTransition, transition);
+ if (resultingTransition != transition && resultingTransition != runningTransition) {
+ throw new UnsupportedOperationException();
+ } else if (resultingTransition != transition) {
+ // todo camera - invoke cancel callback right away
+ transition.cancel();
+ } else {
+ runningTransition.cancel();
+ schedule(transition);
+ }
+ } else {
+ schedule(transition);
+ }
+ }
+
+ @NonNull
+ public List<CameraTransition> getQueuedTransitions() {
+ return queuedTransitions;
+ }
+
+ @NonNull
+ public HashMap<Integer, CameraTransition> getRunningTransitions() {
+ return runningTransitions;
+ }
+
+ @NonNull
+ public CameraBehavior getBehavior() {
+ return behavior;
+ }
+
+ public void setBehavior(@NonNull CameraBehavior behavior) {
+ this.behavior = behavior;
+ }
+
+ void onDestroy() {
+ try {
+ destroyed = true;
+ thread.join();
+ } catch (InterruptedException ex) {
+ ex.printStackTrace();
+ }
+ }
+
+ public interface CameraBehavior {
+
+ void animationScheduled(MapCameraController controller, CameraTransition transition);
+
+ @NonNull
+ CameraTransition resolve(CameraTransition currentTransition, CameraTransition interruptingTransition);
+ }
+
+ private void schedule(CameraTransition transition) {
+ runningTransitions.put(transition.getCameraProperty(), transition);
+ }
+
+ public static class DefaultCameraBehavior implements CameraBehavior {
+
+ @Override
+ public void animationScheduled(MapCameraController controller, CameraTransition transition) {
+ if (transition.getType() == CameraTransition.TYPE_GESTURE) {
+ for (CameraTransition currentTransition : controller.getRunningTransitions().values()) {
+ if (currentTransition.getType() != CameraTransition.TYPE_GESTURE) {
+ currentTransition.cancel();
+ }
+ }
+
+ for (CameraTransition currentTransition : controller.getQueuedTransitions()) {
+ if (currentTransition.getType() != CameraTransition.TYPE_GESTURE) {
+ currentTransition.cancel();
+ }
+ }
+ }
+ }
+
+ @NonNull
+ @Override
+ public CameraTransition resolve(CameraTransition currentTransition, CameraTransition interruptingTransition) {
+ return interruptingTransition;
+ }
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java
index 4521d2ae60..ac74bc8812 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java
@@ -80,6 +80,8 @@ public class MapView extends FrameLayout implements NativeMapView.ViewCallback {
private ImageView attrView;
private ImageView logoView;
+ private MapCameraController cameraController;
+
@Nullable
private MapGestureDetector mapGestureDetector;
@Nullable
@@ -169,11 +171,12 @@ public class MapView extends FrameLayout implements NativeMapView.ViewCallback {
AnnotationManager annotationManager = new AnnotationManager(this, annotationsArray, iconManager,
annotations, markers, polygons, polylines, shapeAnnotations);
Transform transform = new Transform(this, nativeMapView, cameraDispatcher);
+ cameraController = new MapCameraController(transform);
// MapboxMap
List<MapboxMap.OnDeveloperAnimationListener> developerAnimationListeners = new ArrayList<>();
mapboxMap = new MapboxMap(nativeMapView, transform, uiSettings, proj, registerTouchListener, cameraDispatcher,
- developerAnimationListeners);
+ developerAnimationListeners, cameraController);
mapboxMap.injectAnnotationManager(annotationManager);
// user input
@@ -418,6 +421,10 @@ public class MapView extends FrameLayout implements NativeMapView.ViewCallback {
mapCallback.onDestroy();
initialRenderCallback.onDestroy();
+ if (cameraController != null) {
+ cameraController.onDestroy();
+ }
+
if (compassView != null) {
// avoid leaking context through animator #13742
compassView.resetAnimation();
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java
index acd5093dad..1aec486fbc 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java
@@ -61,6 +61,7 @@ public final class MapboxMap {
private final UiSettings uiSettings;
private final Projection projection;
private final Transform transform;
+ private final MapCameraController cameraController;
private final CameraChangeDispatcher cameraChangeDispatcher;
private final OnGesturesManagerInteractionListener onGesturesManagerInteractionListener;
private final List<Style.OnStyleLoaded> awaitingStyleGetters = new ArrayList<>();
@@ -82,11 +83,13 @@ public final class MapboxMap {
MapboxMap(NativeMap map, Transform transform, UiSettings ui, Projection projection,
OnGesturesManagerInteractionListener listener, CameraChangeDispatcher cameraChangeDispatcher,
- List<OnDeveloperAnimationListener> developerAnimationStartedListeners) {
+ List<OnDeveloperAnimationListener> developerAnimationStartedListeners,
+ MapCameraController cameraController) {
this.nativeMapView = map;
this.uiSettings = ui;
this.projection = projection;
this.transform = transform;
+ this.cameraController = cameraController;
this.onGesturesManagerInteractionListener = listener;
this.cameraChangeDispatcher = cameraChangeDispatcher;
this.developerAnimationStartedListeners = developerAnimationStartedListeners;
@@ -2388,4 +2391,8 @@ public final class MapboxMap {
listener.onDeveloperAnimationStarted();
}
}
+
+ public MapCameraController getCameraController() {
+ return cameraController;
+ }
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/TargetCameraTransition.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/TargetCameraTransition.java
new file mode 100644
index 0000000000..ffc8ed32ad
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/TargetCameraTransition.java
@@ -0,0 +1,29 @@
+package com.mapbox.mapboxsdk.maps;
+
+import com.mapbox.mapboxsdk.geometry.LatLng;
+
+public class TargetCameraTransition extends CameraTransition<LatLng> {
+
+ private final LatLng latLng = new LatLng();
+
+ public TargetCameraTransition(int type, long delay, long duration, LatLng endValue) {
+ super(type, duration, delay, endValue);
+ }
+
+ @Override
+ int getCameraProperty() {
+ return PROPERTY_CENTER;
+ }
+
+ @Override
+ LatLng onFrame(double currentTime) {
+ double fraction = (currentTime - startTime) / duration;
+
+ latLng.setLatitude(startValue.getLatitude()
+ + ((endValue.getLatitude() - startValue.getLatitude()) * fraction));
+ latLng.setLongitude(startValue.getLongitude()
+ + ((endValue.getLongitude() - startValue.getLongitude()) * fraction));
+
+ return latLng;
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Transform.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Transform.java
index 02cd05545d..460e7a0dac 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Transform.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Transform.java
@@ -124,6 +124,15 @@ public final class Transform implements MapView.OnCameraDidChangeListener {
}
@UiThread
+ public final void moveCamera(@Nullable CameraPosition cameraPosition) {
+ if (isValidCameraPosition(cameraPosition)) {
+ nativeMap.jumpTo(cameraPosition.target, cameraPosition.zoom, cameraPosition.tilt, cameraPosition.bearing,
+ cameraPosition.padding);
+ invalidateCameraPosition();
+ }
+ }
+
+ @UiThread
final void easeCamera(@NonNull MapboxMap mapboxMap, CameraUpdate update, int durationMs, boolean easingInterpolator,
@Nullable final MapboxMap.CancelableCallback callback) {
CameraPosition cameraPosition = update.getCameraPosition(mapboxMap);
diff --git a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapCameraControllerTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapCameraControllerTest.java
new file mode 100644
index 0000000000..1d68c9323f
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapCameraControllerTest.java
@@ -0,0 +1,7 @@
+package com.mapbox.mapboxsdk.maps;
+
+import static org.junit.Assert.*;
+
+public class MapCameraControllerTest {
+
+} \ No newline at end of file