/* * Copyright 2010, 2011, 2012 mapsforge.org * * This program is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free Software * Foundation, either version 3 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with * this program. If not, see <http://www.gnu.org/licenses/>. */ package org.mapsforge.android.maps.inputhandling; import org.mapsforge.android.maps.MapView; import org.mapsforge.android.maps.PausableThread; import android.os.SystemClock; /** * A ZoomAnimator handles the zoom-in and zoom-out animations of the corresponding MapView. It runs in a separate thread * to avoid blocking the UI thread. */ public class ZoomAnimator extends PausableThread { private static final int DEFAULT_DURATION = 250; private static final int FRAME_LENGTH_IN_MS = 15; private static final String THREAD_NAME = "ZoomAnimator"; private boolean executeAnimation; private final MapView mapView; private float pivotX; private float pivotY; private float scaleFactorApplied; private long timeStart; private float zoomDifference; private float zoomStart; /** * @param mapView * the MapView whose zoom level changes should be animated. */ public ZoomAnimator(MapView mapView) { super(); this.mapView = mapView; } /** * @return true if the ZoomAnimator is working, false otherwise. */ public boolean isExecuting() { return this.executeAnimation; } /** * Starts a zoom animation with the current parameters. * * @param scaleFactorStart * the scale factor at the begin of the animation. * @param scaleFactorEnd * the scale factor at the end of the animation. * @param focusX * the x coordinate of the animation center. * @param focusY * the y coordinate of the animation center. */ public void startAnimation(float scaleFactorStart, float scaleFactorEnd, float focusX, float focusY) { this.zoomStart = scaleFactorStart; this.pivotX = focusX; this.pivotY = focusY; this.zoomDifference = scaleFactorEnd - scaleFactorStart; this.scaleFactorApplied = this.zoomStart; this.executeAnimation = true; this.timeStart = SystemClock.uptimeMillis(); synchronized (this) { notify(); } } @Override protected void doWork() throws InterruptedException { long timeElapsed = SystemClock.uptimeMillis() - this.timeStart; float timeElapsedPercent = Math.min(1, timeElapsed / (float) DEFAULT_DURATION); float currentZoom = this.zoomStart + timeElapsedPercent * this.zoomDifference; float scaleFactor = currentZoom / this.scaleFactorApplied; this.scaleFactorApplied *= scaleFactor; this.mapView.getFrameBuffer().matrixPostScale(scaleFactor, scaleFactor, this.pivotX, this.pivotY); if (timeElapsed >= DEFAULT_DURATION) { this.executeAnimation = false; this.mapView.redraw(); } else { this.mapView.postInvalidate(); sleep(FRAME_LENGTH_IN_MS); } } @Override protected String getThreadName() { return THREAD_NAME; } @Override protected ThreadPriority getThreadPriority() { return ThreadPriority.ABOVE_NORMAL; } @Override protected boolean hasWork() { return this.executeAnimation; } }