/** AirCasting - Share your Air! Copyright (C) 2011-2012 HabitatMap, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. You can contact the authors by email at <info@habitatmap.org> */ package pl.llp.aircasting.view.overlay; import pl.llp.aircasting.R; import pl.llp.aircasting.android.Logger; import pl.llp.aircasting.model.SessionManager; import pl.llp.aircasting.util.bitmap.BitmapHolder; import pl.llp.aircasting.util.map.ProjectionClone; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Point; import com.google.android.maps.GeoPoint; import com.google.android.maps.MapView; import com.google.android.maps.Overlay; import com.google.android.maps.Projection; import com.google.inject.Inject; import roboguice.inject.InjectResource; public abstract class BufferingOverlay<UpdateData> extends Overlay { @Inject BitmapHolder bitmapHolder; @InjectResource(R.color.transparent) int transparent; @Inject SessionManager sessionManager; private Bitmap bitmap; private int bitmapIndex = 0; private GeoPoint mapCenter; private int zoomLevel; private Projection projection; private volatile boolean paused; @Override public synchronized void draw(Canvas canvas, MapView mapView, boolean shadow) { if (shadow || bitmap == null || mapView.getZoomLevel() != zoomLevel) return; if(bitmap.isRecycled()) { String msg = "Trying to draw [" + mapView.getWidth() + ", " + mapView.getHeight() + "] with a recycled bitmap "; Logger.e(msg); return; } Projection projection = mapView.getProjection(); Point oldCenter = projection.toPixels(mapCenter, null); Point newCenter = projection.toPixels(mapView.getMapCenter(), null); int x = oldCenter.x - newCenter.x; int y = oldCenter.y - newCenter.y; canvas.drawBitmap(bitmap, x, y, null); } public void refresh(MapView mapView) { if (drawingIsPaused()) { return; } bitmapIndex = 1 - bitmapIndex; Canvas canvas = new Canvas(); int width = mapView.getWidth(); int height = mapView.getHeight(); Bitmap newBitmap = bitmapHolder.getBitmap(width, height, bitmapIndex); if(newBitmap == null || newBitmap.isRecycled()) { newBitmap = bitmapHolder.getBitmap(width, height, 2); } if (newBitmap != null && !newBitmap.isRecycled()) { newBitmap.eraseColor(transparent); canvas.setBitmap(newBitmap); int newZoomLevel = mapView.getZoomLevel(); GeoPoint newMapCenter = mapView.getMapCenter(); Projection newProjection = mapView.getProjection(); ProjectionClone projectionClone = new ProjectionClone(newProjection, width, height); performDraw(canvas, projectionClone); synchronized (this) { this.projection = projectionClone; zoomLevel = newZoomLevel; mapCenter = newMapCenter; bitmap = newBitmap; } } } private boolean drawingIsPaused() { return paused; } public void update(UpdateData updateData) { Canvas canvas = null; Projection projectionToUse = null; synchronized (this) { if (bitmap != null) { canvas = new Canvas(bitmap); projectionToUse = this.projection; } } if (canvas != null) { performUpdate(canvas, projectionToUse, updateData); } } protected abstract void performDraw(Canvas canvas, Projection projection); protected abstract void performUpdate(Canvas canvas, Projection projection, UpdateData updateData); protected void stopDrawing(MapView view) { paused = true; bitmap = null; bitmapHolder.release(view.getWidth(), view.getHeight()); } public void startDrawing() { paused = false; } }