summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorŁukasz Paczos <lukasz.paczos@mapbox.com>2019-09-06 14:22:30 +0200
committerŁukasz Paczos <lukasz.paczos@mapbox.com>2019-09-06 14:23:15 +0200
commit0dff7299e2546ec7828739dd6ee0a0b9f68fb0f6 (patch)
tree907fffbf869bbcad8cfe913e213f93e2b11b9df7
parent641a7c242d8119b05f93d53ead9991008a39b431 (diff)
downloadqtlocation-mapboxgl-0dff7299e2546ec7828739dd6ee0a0b9f68fb0f6.tar.gz
[android][wip] use framework choreographer to sync camera animations
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/CameraTransition.java76
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapCameraController.java211
2 files changed, 130 insertions, 157 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
index 4a1828f9a6..cf0a9b825f 100644
--- 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
@@ -15,11 +15,11 @@ public abstract class CameraTransition<T> {
public static final Interpolator INTERPOLATOR_EASING = PathInterpolatorCompat.create(0f, 0f, 0.25f, 1f);
public 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 PROPERTY_ZOOM = 1;
+ public static final int PROPERTY_PITCH = 2;
+ public static final int PROPERTY_BEARING = 3;
+ public static final int PROPERTY_ANCHOR = 4;
+ public static final int PROPERTY_PADDING = 5;
private final CopyOnWriteArrayList<Listener> listeners = new CopyOnWriteArrayList<>();
@@ -28,10 +28,14 @@ public abstract class CameraTransition<T> {
private T startValue;
private final T endValue;
- private double startTime;
- private double endTime;
- private final double duration;
- private final double delay;
+ private double startTimeMillis;
+ private double startTimeNanos;
+ private double endTimeMillis;
+ private double endTimeNanos;
+ private final double durationMillis;
+ private final double durationNanos;
+ private final double delayMillis;
+ private final double delayNanos;
private boolean isCanceled;
private boolean isStarted;
@@ -39,17 +43,21 @@ public abstract class CameraTransition<T> {
private final Interpolator interpolator;
- CameraTransition(int type, double duration, double delay, T endValue, Interpolator interpolator) {
+ CameraTransition(int type, double durationMillis, double delayMillis, T endValue, Interpolator interpolator) {
this.type = type;
- this.duration = duration;
- this.delay = delay;
+ this.durationMillis = durationMillis;
+ this.durationNanos = durationMillis * 1E6;
+ this.delayMillis = delayMillis;
+ this.delayNanos = this.delayMillis * 1E6;
this.endValue = endValue;
this.interpolator = interpolator;
}
- void initTime(T startValue, double currentTime) {
- this.startTime = currentTime + delay;
- this.endTime = this.startTime + duration;
+ void initTime(T startValue, double currentTimeNanos) {
+ this.startTimeMillis = currentTimeNanos / 1E6 + delayMillis;
+ this.startTimeNanos = currentTimeNanos + delayNanos;
+ this.endTimeMillis = startTimeMillis + durationMillis;
+ this.endTimeNanos = startTimeNanos + durationNanos;
this.startValue = startValue;
this.isStarted = true;
}
@@ -82,25 +90,47 @@ public abstract class CameraTransition<T> {
}
public double getStartTime() {
- if (startTime <= 0) {
+ if (startTimeMillis <= 0) {
throw new RuntimeException("start or queue the transition first");
}
- return startTime;
+ return startTimeMillis;
+ }
+
+ double getStartTimeNanos() {
+ if (startTimeNanos <= 0) {
+ throw new RuntimeException("start or queue the transition first");
+ }
+ return startTimeNanos;
}
public double getEndTime() {
- if (endTime <= 0) {
+ if (endTimeMillis <= 0) {
+ throw new RuntimeException("start or queue the transition first");
+ }
+ return endTimeMillis;
+ }
+
+ double getEndTimeNanos() {
+ if (endTimeNanos <= 0) {
throw new RuntimeException("start or queue the transition first");
}
- return endTime;
+ return endTimeNanos;
}
public double getDuration() {
- return duration;
+ return durationMillis;
+ }
+
+ double getDurationNanos() {
+ return durationNanos;
}
public double getDelay() {
- return delay;
+ return delayMillis;
+ }
+
+ double getDelayNanos() {
+ return delayNanos;
}
public Interpolator getInterpolator() {
@@ -115,8 +145,8 @@ public abstract class CameraTransition<T> {
listeners.remove(listener);
}
- T onFrame(double currentTime) {
- double animationPosition = (currentTime - startTime) / duration;
+ T onFrame(double currentTimeNanos) {
+ double animationPosition = (currentTimeNanos - startTimeNanos) / durationNanos;
double fraction = interpolator.getInterpolation((float) animationPosition);
return getAnimatedValue(fraction);
}
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
index ffbb19d23a..952cb4f20a 100644
--- 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
@@ -1,17 +1,16 @@
package com.mapbox.mapboxsdk.maps;
-import android.os.Handler;
-import android.os.Looper;
import android.support.annotation.NonNull;
+import android.view.Choreographer;
import com.mapbox.mapboxsdk.camera.CameraPosition;
import com.mapbox.mapboxsdk.geometry.LatLng;
+import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
-import java.util.concurrent.locks.ReentrantLock;
public class MapCameraController {
@@ -19,159 +18,109 @@ public class MapCameraController {
private final HashMap<Integer, LinkedList<CameraTransition>> queuedTransitions = new HashMap<>(5);
@NonNull
- private final ReentrantLock runningTransitionsLock = new ReentrantLock();
-
- @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() {
+ private final Choreographer choreographer = Choreographer.getInstance();
- private static final short MIN_FRAME_INTERVAL = 10;
+ MapCameraController(@NonNull final Transform transform) {
+ this.transform = transform;
+ queuedTransitions.put(CameraTransition.PROPERTY_CENTER, new LinkedList<CameraTransition>());
+ queuedTransitions.put(CameraTransition.PROPERTY_ZOOM, new LinkedList<CameraTransition>());
+ queuedTransitions.put(CameraTransition.PROPERTY_PITCH, new LinkedList<CameraTransition>());
+ queuedTransitions.put(CameraTransition.PROPERTY_BEARING, new LinkedList<CameraTransition>());
+ queuedTransitions.put(CameraTransition.PROPERTY_ANCHOR, new LinkedList<CameraTransition>());
+ queuedTransitions.put(CameraTransition.PROPERTY_PADDING, new LinkedList<CameraTransition>());
+ choreographer.postFrameCallback(frameCallback);
+ }
+ private final Choreographer.FrameCallback frameCallback = new Choreographer.FrameCallback() {
@Override
- public void run() {
- CameraPosition cameraPosition = null;
- while (true) {
- if (destroyed) {
- return;
+ public void doFrame(long frameTimeNanos) {
+ if (destroyed) {
+ return;
+ }
+ List<CameraTransition> canceled = new ArrayList<>();
+ Iterator<CameraTransition> iterator = runningTransitions.values().iterator();
+ while (iterator.hasNext()) {
+ CameraTransition transition = iterator.next();
+ if (transition.isCanceled()) {
+ transition.onCancel();
+ iterator.remove();
+ canceled.add(transition);
}
+ }
- final CameraPosition update = cameraPosition;
- if (update != null) {
- handler.post(new Runnable() {
- @Override
- public void run() {
- if (destroyed) {
- return;
- }
-
- CameraPosition finalUpdate = update;
-
- synchronized (runningTransitionsLock) {
- 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);
- setCameraProperty(builder, transition.getCameraProperty(), null);
- finalUpdate = builder.build();
-
- startNextTransition(transition.getCameraProperty());
- }
- }
- }
-
- // todo camera - check if update is noop, abort then
-
- transform.moveCamera(finalUpdate);
-
- synchronized (runningTransitionsLock) {
- Iterator<CameraTransition> iterator = runningTransitions.values().iterator();
- while (iterator.hasNext()) {
- CameraTransition transition = iterator.next();
- transition.onProgress();
-
- if (transition.isFinishing()) {
- transition.onFinish();
- iterator.remove();
-
- startNextTransition(transition.getCameraProperty());
- }
- }
- }
- }
- });
- }
+ for (CameraTransition transition : canceled) {
+ startNextTransition(transition.getCameraProperty());
+ }
- // todo camera - what's the correct delay not to flood and block the main thread?
- long nextFrameTime = System.currentTimeMillis() + MIN_FRAME_INTERVAL;
-
- synchronized (runningTransitionsLock) {
- boolean willRun = false;
- CameraPosition.Builder builder = new CameraPosition.Builder();
- for (final CameraTransition transition : runningTransitions.values()) {
- if (transition.getStartTime() <= nextFrameTime) {
- willRun = true;
- if (nextFrameTime >= transition.getEndTime()) {
- handler.post(new Runnable() {
- @Override
- public void run() {
- transition.setFinishing();
- }
- });
- }
-
- Object value = transition.isFinishing() ? transition.getEndValue() : transition.onFrame(nextFrameTime);
- setCameraProperty(builder, transition.getCameraProperty(), value);
- }
+ boolean shouldRun = false;
+ CameraPosition.Builder builder = new CameraPosition.Builder();
+ for (final CameraTransition transition : runningTransitions.values()) {
+ if (transition.getStartTimeNanos() <= frameTimeNanos) {
+ shouldRun = true;
+ if (frameTimeNanos >= transition.getEndTimeNanos()) {
+ transition.setFinishing();
}
- if (willRun) {
- cameraPosition = builder.build();
- } else {
- cameraPosition = null;
- }
+ Object value = transition.isFinishing() ? transition.getEndValue() : transition.onFrame(frameTimeNanos);
+ setCameraProperty(builder, transition.getCameraProperty(), value);
}
+ }
- long sleepTime = nextFrameTime - System.currentTimeMillis();
+ if (shouldRun) {
+ transform.moveCamera(builder.build());
+ }
- if (sleepTime >= 0) {
- try {
- Thread.sleep(sleepTime);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
+
+ List<CameraTransition> finished = new ArrayList<>();
+ iterator = runningTransitions.values().iterator();
+ while (iterator.hasNext()) {
+ CameraTransition transition = iterator.next();
+ transition.onProgress();
+
+ if (transition.isFinishing()) {
+ transition.onFinish();
+ iterator.remove();
+ finished.add(transition);
}
}
- }
- }, "MapCameraController");
- MapCameraController(@NonNull final Transform transform) {
- this.transform = transform;
- queuedTransitions.put(CameraTransition.PROPERTY_CENTER, new LinkedList<CameraTransition>());
- queuedTransitions.put(CameraTransition.PROPERTY_ZOOM, new LinkedList<CameraTransition>());
- queuedTransitions.put(CameraTransition.PROPERTY_PITCH, new LinkedList<CameraTransition>());
- queuedTransitions.put(CameraTransition.PROPERTY_BEARING, new LinkedList<CameraTransition>());
- queuedTransitions.put(CameraTransition.PROPERTY_ANCHOR, new LinkedList<CameraTransition>());
- queuedTransitions.put(CameraTransition.PROPERTY_PADDING, new LinkedList<CameraTransition>());
- thread.start();
- }
+ for (CameraTransition transition : finished) {
+ startNextTransition(transition.getCameraProperty());
+ }
+
+ choreographer.postFrameCallback(this);
+ }
+ };
public void startTransition(CameraTransition transition) {
- synchronized (runningTransitionsLock) {
- 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) {
- transition.cancel();
- transition.onCancel();
- } else {
- runningTransition.cancel();
- queuedTransitions.get(transition.getCameraProperty()).push(transition);
- }
+ 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) {
+ transition.cancel();
+ transition.onCancel();
} else {
- long time = System.currentTimeMillis();
- transition.initTime(getCameraPropertyValue(transition.getCameraProperty()), time);
- runningTransitions.put(transition.getCameraProperty(), transition);
+ runningTransition.cancel();
+ queuedTransitions.get(transition.getCameraProperty()).push(transition);
}
+ } else {
+ long time = System.nanoTime();
+ transition.initTime(getCameraPropertyValue(transition.getCameraProperty()), time);
+ runningTransitions.put(transition.getCameraProperty(), transition);
}
}
@@ -219,12 +168,6 @@ public class MapCameraController {
transition.onCancel();
}
runningTransitions.clear();
-
- try {
- thread.join();
- } catch (InterruptedException ex) {
- ex.printStackTrace();
- }
}
private static void setCameraProperty(CameraPosition.Builder builder, int property, Object value) {