First stage animation refactoring

This commit is contained in:
Alexey Kulish 2018-05-29 12:35:42 +03:00
parent c94c8f21ad
commit a95f39a9cd
2 changed files with 151 additions and 136 deletions

View file

@ -99,11 +99,13 @@ public class MapViewTrackingUtilities implements OsmAndLocationListener, IMapLoc
public void setMapView(OsmandMapTileView mapView) {
this.mapView = mapView;
if(mapView != null) {
if (mapView != null) {
WindowManager wm = (WindowManager) app.getSystemService(Context.WINDOW_SERVICE);
int orientation = wm.getDefaultDisplay().getOrientation();
app.getLocationProvider().updateScreenOrientation(orientation);
mapView.setMapLocationListener(this);
if (wm != null) {
int orientation = wm.getDefaultDisplay().getOrientation();
app.getLocationProvider().updateScreenOrientation(orientation);
mapView.setMapLocationListener(this);
}
}
}
@ -152,33 +154,7 @@ public class MapViewTrackingUtilities implements OsmAndLocationListener, IMapLoc
}
private void detectDrivingRegion(final LatLon latLon) {
new AsyncTask<LatLon, Void, BinaryMapDataObject>() {
@Override
protected BinaryMapDataObject doInBackground(LatLon... latLons) {
try {
if (latLons != null && latLons.length > 0) {
return app.getRegions().getSmallestBinaryMapDataObjectAt(latLons[0]);
}
} catch (IOException e) {
// ignore
}
return null;
}
@Override
protected void onPostExecute(BinaryMapDataObject o) {
if (o != null) {
String fullName = app.getRegions().getFullName(o);
WorldRegion worldRegion = app.getRegions().getRegionData(fullName);
if (worldRegion != null) {
app.setupDrivingRegion(worldRegion);
}
}
}
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, latLon);
new DetectDrivingRegionTask(app).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, latLon);
}
@Override
@ -193,16 +169,17 @@ public class MapViewTrackingUtilities implements OsmAndLocationListener, IMapLoc
}
}
if (mapView != null) {
RotatedTileBox tb = mapView.getCurrentRotatedTileBox();
RotatedTileBox tb = mapView.getCurrentRotatedTileBox().copy();
if (isMapLinkedToLocation() && location != null) {
Pair<Integer, Double> zoom = null;
Float rotation = null;
if (settings.AUTO_ZOOM_MAP.get()) {
zoom = autozoom(location);
zoom = autozoom(tb, location);
}
int currentMapRotation = settings.ROTATE_MAP.get();
float speedForDirectionOfMovement = settings.SWITCH_MAP_DIRECTION_TO_COMPASS.get();
boolean smallSpeedForDirectionOfMovement = speedForDirectionOfMovement != 0 && isSmallSpeedForDirectionOfMovement(location, speedForDirectionOfMovement);
boolean smallSpeedForDirectionOfMovement = speedForDirectionOfMovement != 0
&& isSmallSpeedForDirectionOfMovement(location, speedForDirectionOfMovement);
boolean smallSpeedForCompass = isSmallSpeedForCompass(location);
boolean smallSpeedForAnimation = isSmallSpeedForAnimation(location);
// boolean virtualBearing = fMode && settings.SNAP_TO_ROAD.get();
@ -226,7 +203,7 @@ public class MapViewTrackingUtilities implements OsmAndLocationListener, IMapLoc
mapView.getAnimatedDraggingThread().startMoving(
location.getLatitude(), location.getLongitude(), zoom, rotation, false);
} else {
if (zoom != null) {
if (zoom != null && zoom.first != null && zoom.second != null) {
mapView.getAnimatedDraggingThread().startZooming(zoom.first, zoom.second, false);
}
if (rotation != null) {
@ -234,24 +211,24 @@ public class MapViewTrackingUtilities implements OsmAndLocationListener, IMapLoc
}
mapView.setLatLon(location.getLatitude(), location.getLongitude());
}
} else if(location != null) {
} else if (location != null) {
showViewAngle = (!location.hasBearing() || isSmallSpeedForCompass(location)) && (tb != null &&
tb.containsLatLon(location.getLatitude(), location.getLongitude()));
registerUnregisterSensor(location, false);
}
RoutingHelper routingHelper = app.getRoutingHelper();
followingMode = routingHelper.isFollowingMode();
if(routePlanningMode != routingHelper.isRoutePlanningMode()) {
if (routePlanningMode != routingHelper.isRoutePlanningMode()) {
switchToRoutePlanningMode();
}
// When location is changed we need to refresh map in order to show movement!
mapView.refreshMap();
}
if(dashboard != null) {
if (dashboard != null) {
dashboard.updateMyLocation(location);
}
if(contextMenu != null) {
if (contextMenu != null) {
contextMenu.updateMyLocation(location);
}
}
@ -319,15 +296,13 @@ public class MapViewTrackingUtilities implements OsmAndLocationListener, IMapLoc
}
time /= settings.AUTO_ZOOM_MAP_SCALE.get().coefficient;
double distToSee = speed * time;
float zoomDelta = (float) (Math.log(visibleDist / distToSee) / Math.log(2.0f));
// check if 17, 18 is correct?
return zoomDelta;
return (float) (Math.log(visibleDist / distToSee) / Math.log(2.0f));
}
public Pair<Integer, Double> autozoom(Location location) {
public Pair<Integer, Double> autozoom(RotatedTileBox tb, Location location) {
if (location.hasSpeed()) {
long now = System.currentTimeMillis();
final RotatedTileBox tb = mapView.getCurrentRotatedTileBox();
float zdelta = defineZoomFromSpeed(tb, location.getSpeed());
if (Math.abs(zdelta) >= 0.5/*?Math.sqrt(0.5)*/) {
// prevent ui hysteresis (check time interval for autozoom)
@ -481,4 +456,35 @@ public class MapViewTrackingUtilities implements OsmAndLocationListener, IMapLoc
isUserZoomed = true;
}
private static class DetectDrivingRegionTask extends AsyncTask<LatLon, Void, BinaryMapDataObject> {
private OsmandApplication app;
DetectDrivingRegionTask(OsmandApplication app) {
this.app = app;
}
@Override
protected BinaryMapDataObject doInBackground(LatLon... latLons) {
try {
if (latLons != null && latLons.length > 0) {
return app.getRegions().getSmallestBinaryMapDataObjectAt(latLons[0]);
}
} catch (IOException e) {
// ignore
}
return null;
}
@Override
protected void onPostExecute(BinaryMapDataObject o) {
if (o != null) {
String fullName = app.getRegions().getFullName(o);
WorldRegion worldRegion = app.getRegions().getRegionData(fullName);
if (worldRegion != null) {
app.setupDrivingRegion(worldRegion);
}
}
}
}
}

View file

@ -15,40 +15,37 @@ import org.apache.commons.logging.Log;
/**
* Thread for animated dragging.
* Defines accelerator to stop dragging screen.
* Defines accelerator to stop dragging screen.
*/
public class AnimateDraggingMapThread {
protected static final Log log = PlatformUtil.getLog(AnimateDraggingMapThread.class);
private final static float DRAGGING_ANIMATION_TIME = 1200f;
private final static float ZOOM_ANIMATION_TIME = 250f;
private final static float ZOOM_MOVE_ANIMATION_TIME = 350f;
private final static float MOVE_MOVE_ANIMATION_TIME = 900f;
private final static float NAV_ANIMATION_TIME = 1000f;
private final static int DEFAULT_SLEEP_TO_REDRAW = 15;
private volatile boolean stopped;
private volatile Thread currentThread = null;
private final OsmandMapTileView tileView;
private float targetRotate = -720;
private double targetLatitude = 0;
private double targetLongitude = 0;
private int targetIntZoom = 0;
private int targetFloatZoom = 0;
private double targetFloatZoom = 0;
private boolean isAnimatingZoom;
public AnimateDraggingMapThread(OsmandMapTileView tileView){
public AnimateDraggingMapThread(OsmandMapTileView tileView) {
this.tileView = tileView;
}
private void pendingRotateAnimation() {
boolean conditionToCountinue = false;
boolean conditionToCountinue;
if (targetRotate != -720) {
do {
conditionToCountinue = false;
@ -71,42 +68,42 @@ public class AnimateDraggingMapThread {
targetRotate = -720;
}
}
/**
* Stop dragging async
*/
public void stopAnimating(){
public void stopAnimating() {
stopped = true;
}
public boolean isAnimating(){
public boolean isAnimating() {
return currentThread != null && !stopped;
}
/**
* Stop dragging sync
*/
public void stopAnimatingSync(){
public void stopAnimatingSync() {
// wait until current thread != null
stopped = true;
Thread tt = null;
while((tt = currentThread) != null){
Thread tt;
while ((tt = currentThread) != null) {
try {
tt.join();
} catch (Exception e) {
}
}
}
public synchronized void startThreadAnimating(final Runnable runnable){
public synchronized void startThreadAnimating(final Runnable runnable) {
stopAnimatingSync();
stopped = false;
final Thread t = new Thread(new Runnable() {
@Override
public void run() {
try {
try {
suspendUpdate();
runnable.run();
} finally {
@ -115,13 +112,14 @@ public class AnimateDraggingMapThread {
}
}
}, "Animating Thread");
currentThread = t;
currentThread = t;
t.start();
}
public void startMoving(final double finalLat, final double finalLon, final Pair<Integer, Double> finalZoom,
final Float finalRotation, final boolean notifyListener) {
stopAnimatingSync();
final RotatedTileBox rb = tileView.getCurrentRotatedTileBox().copy();
double startLat = rb.getLatitude();
double startLon = rb.getLongitude();
@ -132,7 +130,7 @@ public class AnimateDraggingMapThread {
final int zoom;
final double zoomFP;
final float rotation;
if (finalZoom != null) {
if (finalZoom != null && finalZoom.first != null && finalZoom.second != null) {
zoom = finalZoom.first;
zoomFP = finalZoom.second;
} else {
@ -150,7 +148,7 @@ public class AnimateDraggingMapThread {
boolean skipAnimation = !rb.containsLatLon(finalLat, finalLon);
if (skipAnimation) {
tileView.setLatLonAnimate(finalLat, finalLon, notifyListener);
tileView.setFractionalZoom(zoom, 0, notifyListener);
tileView.setFractionalZoom(zoom, zoomFP, notifyListener);
tileView.rotateToAnimate(rotation);
return;
}
@ -159,19 +157,19 @@ public class AnimateDraggingMapThread {
@Override
public void run() {
setTargetValues(zoom, finalLat, finalLon);
setTargetValues(zoom, zoomFP, finalLat, finalLon);
boolean animateZoom = finalZoom != null && (zoom != startZoom || startZoomFP != 0);
if (animateZoom) {
animatingZoomInThread(startZoom, startZoomFP, zoom, zoomFP, NAV_ANIMATION_TIME, notifyListener);
}
boolean animateRotation = rotation != startRotaton;
if (animateRotation) {
animatingRotateInThread(rotation, 500f, notifyListener);
}
if (!stopped) {
animatingMoveInThread(mMoveX, mMoveY, NAV_ANIMATION_TIME, notifyListener, null);
}
if (!stopped && animateZoom) {
animatingZoomInThread(startZoom, startZoomFP, zoom, 0, NAV_ANIMATION_TIME, notifyListener);
}
pendingRotateAnimation();
animatingMoveInThread(mMoveX, mMoveY, NAV_ANIMATION_TIME, notifyListener, null);
}
});
}
@ -181,21 +179,21 @@ public class AnimateDraggingMapThread {
}
public void startMoving(final double finalLat, final double finalLon, final int endZoom,
final boolean notifyListener, final Runnable finishAminationCallback) {
final boolean notifyListener, final Runnable finishAnimationCallback) {
stopAnimatingSync();
final RotatedTileBox rb = tileView.getCurrentRotatedTileBox().copy();
double startLat = rb.getLatitude();
double startLon = rb.getLongitude();
float rotate = rb.getRotate();
final int startZoom = rb.getZoom();
final double startZoomFP = rb.getZoomFloatPart();
boolean skipAnimation = false;
float mStX = rb.getPixXFromLatLon(startLat, startLon) - rb.getPixXFromLatLon(finalLat, finalLon);
float mStY = rb.getPixYFromLatLon(startLat, startLon) - rb.getPixYFromLatLon(finalLat, finalLon);
while (Math.abs(mStX) + Math.abs(mStY) > 1200) {
rb.setZoom(rb.getZoom() - 1);
if(rb.getZoom() <= 4){
if (rb.getZoom() <= 4) {
skipAnimation = true;
}
mStX = rb.getPixXFromLatLon(startLat, startLon) - rb.getPixXFromLatLon(finalLat, finalLon);
@ -207,6 +205,14 @@ public class AnimateDraggingMapThread {
if (skipAnimation) {
tileView.setLatLonAnimate(finalLat, finalLon, notifyListener);
tileView.setFractionalZoom(endZoom, 0, notifyListener);
if (finishAnimationCallback != null) {
tileView.getApplication().runInUIThread(new Runnable() {
@Override
public void run() {
finishAnimationCallback.run();
}
});
}
return;
}
final float mMoveX = rb.getPixXFromLatLon(startLat, startLon) - rb.getPixXFromLatLon(finalLat, finalLon);
@ -214,20 +220,21 @@ public class AnimateDraggingMapThread {
final boolean doNotUseAnimations = tileView.getSettings().DO_NOT_USE_ANIMATIONS.get();
final float animationTime = doNotUseAnimations ? 0 : Math.max(450, (Math.abs(mStX) + Math.abs(mStY)) / 1200f * MOVE_MOVE_ANIMATION_TIME);
startThreadAnimating(new Runnable() {
@Override
public void run() {
setTargetValues(endZoom, finalLat, finalLon);
if(moveZoom != startZoom){
setTargetValues(endZoom, 0, finalLat, finalLon);
if (moveZoom != startZoom) {
animatingZoomInThread(startZoom, startZoomFP, moveZoom, startZoomFP, doNotUseAnimations ? 0 : ZOOM_MOVE_ANIMATION_TIME, notifyListener);
}
if(!stopped){
animatingMoveInThread(mMoveX, mMoveY, animationTime, notifyListener, finishAminationCallback);
if (!stopped) {
animatingMoveInThread(mMoveX, mMoveY, animationTime, notifyListener, finishAnimationCallback);
}
if(!stopped){
if (!stopped) {
tileView.setLatLonAnimate(finalLat, finalLon, notifyListener);
}
@ -235,13 +242,13 @@ public class AnimateDraggingMapThread {
animatingZoomInThread(moveZoom, startZoomFP, endZoom, 0, doNotUseAnimations ? 0 : ZOOM_MOVE_ANIMATION_TIME, notifyListener);
}
tileView.setFractionalZoom(endZoom, 0, notifyListener);
pendingRotateAnimation();
}
});
}
private void animatingRotateInThread(float rotate, float animationTime, boolean notify){
private void animatingRotateInThread(float rotate, float animationTime, boolean notify) {
AccelerateDecelerateInterpolator interpolator = new AccelerateDecelerateInterpolator();
float startRotate = tileView.getRotate();
float rotationDiff = MapUtils.unifyRotationDiff(startRotate, rotate);
@ -268,15 +275,15 @@ public class AnimateDraggingMapThread {
}
private void animatingMoveInThread(float moveX, float moveY, float animationTime,
boolean notify, final Runnable finishAnimationCallback){
boolean notify, final Runnable finishAnimationCallback) {
AccelerateDecelerateInterpolator interpolator = new AccelerateDecelerateInterpolator();
float cX = 0;
float cY = 0;
long timeMillis = SystemClock.uptimeMillis();
float normalizedTime = 0f;
while (!stopped){
normalizedTime = (SystemClock.uptimeMillis() - timeMillis) / animationTime;
float normalizedTime;
while (!stopped) {
normalizedTime = (SystemClock.uptimeMillis() - timeMillis) / animationTime;
if (normalizedTime > 1f) {
break;
}
@ -301,32 +308,31 @@ public class AnimateDraggingMapThread {
});
}
}
private void animatingZoomInThread(int zoomStart, double zoomFloatStart,
int zoomEnd, double zoomFloatEnd, float animationTime, boolean notifyListener){
private void animatingZoomInThread(int zoomStart, double zoomFloatStart,
int zoomEnd, double zoomFloatEnd, float animationTime, boolean notifyListener) {
try {
isAnimatingZoom = true;
// could be 0 ]-0.5,0.5], -1 ]-1,0], 1 ]0, 1]
int threshold = ((int)(zoomFloatEnd * 2));
int threshold = ((int) (zoomFloatEnd * 2));
double beginZoom = zoomStart + zoomFloatStart;
double endZoom = zoomEnd + zoomFloatEnd;
double curZoom = beginZoom;
double endZoom = zoomEnd + zoomFloatEnd;
animationTime *= Math.abs(endZoom - beginZoom);
// AccelerateInterpolator interpolator = new AccelerateInterpolator(1);
LinearInterpolator interpolator = new LinearInterpolator();
long timeMillis = SystemClock.uptimeMillis();
float normalizedTime = 0f;
float normalizedTime;
while (!stopped) {
normalizedTime = (SystemClock.uptimeMillis() - timeMillis) / animationTime;
if (normalizedTime > 1f) {
break;
}
float interpolation = interpolator.getInterpolation(normalizedTime);
curZoom = interpolation * (endZoom - beginZoom) + beginZoom;
double curZoom = interpolation * (endZoom - beginZoom) + beginZoom;
int baseZoom = (int) Math.round(curZoom - 0.5 * threshold);
double zaAnimate = curZoom - baseZoom;
double zaAnimate = curZoom - baseZoom;
tileView.zoomToAnimate(baseZoom, zaAnimate, notifyListener);
try {
Thread.sleep(DEFAULT_SLEEP_TO_REDRAW);
@ -334,55 +340,57 @@ public class AnimateDraggingMapThread {
stopped = true;
}
}
tileView.setFractionalZoom(zoomEnd, zoomFloatEnd, notifyListener);
tileView.setFractionalZoom(zoomEnd, zoomFloatEnd, notifyListener);
} finally {
isAnimatingZoom = false;
}
}
public boolean isAnimatingZoom() {
return isAnimatingZoom;
}
public void startZooming(final int zoomEnd, final double zoomPart, final boolean notifyListener){
public void startZooming(final int zoomEnd, final double zoomPart, final boolean notifyListener) {
boolean doNotUseAnimations = tileView.getSettings().DO_NOT_USE_ANIMATIONS.get();
final float animationTime = doNotUseAnimations ? 0 : ZOOM_ANIMATION_TIME;
startThreadAnimating(new Runnable(){
startThreadAnimating(new Runnable() {
@Override
public void run() {
RotatedTileBox tb = tileView.getCurrentRotatedTileBox();
setTargetValues(zoomEnd, tileView.getLatitude(), tileView.getLongitude());
setTargetValues(zoomEnd, zoomPart, tileView.getLatitude(), tileView.getLongitude());
RotatedTileBox tb = tileView.getCurrentRotatedTileBox().copy();
animatingZoomInThread(tb.getZoom(), tb.getZoomFloatPart(), zoomEnd, zoomPart, animationTime, notifyListener);
pendingRotateAnimation();
}
}); //$NON-NLS-1$
}
public void startDragging(final float velocityX, final float velocityY, float startX, float startY,
final float endX, final float endY, final boolean notifyListener){
public void startDragging(final float velocityX, final float velocityY,
float startX, float startY, final float endX, final float endY,
final boolean notifyListener) {
final float animationTime = DRAGGING_ANIMATION_TIME;
clearTargetValues();
startThreadAnimating(new Runnable(){
startThreadAnimating(new Runnable() {
@Override
public void run() {
float curX = endX;
float curY = endY;
DecelerateInterpolator interpolator = new DecelerateInterpolator(1);
long timeMillis = SystemClock.uptimeMillis();
float normalizedTime = 0f;
float normalizedTime;
float prevNormalizedTime = 0f;
while(!stopped){
normalizedTime = (SystemClock.uptimeMillis() - timeMillis) / animationTime;
if(normalizedTime >= 1f){
while (!stopped) {
normalizedTime = (SystemClock.uptimeMillis() - timeMillis) / animationTime;
if (normalizedTime >= 1f) {
break;
}
float interpolation = interpolator.getInterpolation(normalizedTime);
float newX = velocityX * (1 - interpolation) * (normalizedTime - prevNormalizedTime) + curX;
float newY = velocityY * (1 - interpolation) * (normalizedTime - prevNormalizedTime) + curY;
tileView.dragToAnimate(curX, curY, newX, newY, notifyListener);
curX = newX;
curY = newY;
@ -397,31 +405,32 @@ public class AnimateDraggingMapThread {
}
}); //$NON-NLS-1$
}
private void clearTargetValues(){
private void clearTargetValues() {
targetIntZoom = 0;
}
private void suspendUpdate() {
final MapRendererView mapRenderer = tileView.getMapRenderer();
if (mapRenderer != null) {
mapRenderer.suspendSymbolsUpdate();
}
}
private void resumeUpdate() {
final MapRendererView mapRenderer = tileView.getMapRenderer();
if (mapRenderer != null) {
mapRenderer.resumeSymbolsUpdate();
}
}
private void setTargetValues(int zoom, double lat, double lon){
private void setTargetValues(int zoom, double zoomPart, double lat, double lon) {
targetIntZoom = zoom;
targetFloatZoom = zoomPart;
targetLatitude = lat;
targetLongitude = lon;
}
public void startRotate(final float rotate) {
if (!isAnimating()) {
clearTargetValues();
@ -439,7 +448,7 @@ public class AnimateDraggingMapThread {
this.targetRotate = rotate;
}
}
public int getTargetIntZoom() {
return targetIntZoom;
@ -448,11 +457,11 @@ public class AnimateDraggingMapThread {
public double getTargetLatitude() {
return targetLatitude;
}
public double getTargetLongitude() {
return targetLongitude;
}
}