├── .DS_Store ├── src ├── .DS_Store ├── map │ └── CameraUpdateAnimator.java └── tiles │ └── ExpandedMBTilesTileProvider.java └── README.md /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antoniocarlon/MapUtils/HEAD/.DS_Store -------------------------------------------------------------------------------- /src/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antoniocarlon/MapUtils/HEAD/src/.DS_Store -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Map Utils 2 | 3 | Utilities for Google Maps Android API v2 4 | 5 | ### Current version 6 | 7 | v0.2.0 8 | 9 | ## ExpandedMBTilesTileProvider 10 | 11 | Tile provider to read MBTiles format into Google Maps API Android v2 expanding the available zoom levels to the lowest one (lower zoom levels will be interpolated from higher levels). 12 | 13 | ### Usage: 14 | 15 | ``` 16 | TileProvider tileProvider = new ExpandedMBTilesTileProvider(new File("/sdcard/mydatabase.mbtiles"), 256, 256); 17 | TileOverlay tileOverlay = mMap.addTileOverlay( 18 | new TileOverlayOptions() 19 | .tileProvider(tileProvider)); 20 | ``` 21 | 22 | ## CameraUpdateAnimator 23 | 24 | Animaes the camera position chaining a series of CameraUpdates with a given delay between them and allowing camera to move or animate. 25 | 26 | ### Usage: 27 | 28 | ``` 29 | // Create a new CameraUpdateAnimator for a given mMap 30 | // with an OnCameraIdleListener to set when the animation ends 31 | CameraUpdateAnimator animator = new CameraUpdateAnimator(mMap, mOnCameraIdleListener); 32 | 33 | // Add animations 34 | animator.add(CameraUpdateFactory.newLatLngZoom(new LatLng(40.421, -3.71), 17), true, 1000); // Animate the camera with a 1000 milliseconds delay 35 | animator.add(CameraUpdateFactory.newLatLngZoom(new LatLng(40.421, -3.71), 18), false, 500); // Move the camera (no animation) with a 500 milliseconds delay 36 | animator.add(CameraUpdateFactory.newLatLngZoom(new LatLng(40.422, -3.72), 18), true, 500); 37 | animator.add(CameraUpdateFactory.newLatLngZoom(new LatLng(40.422, -3.72), 19), false, 1000); 38 | animator.add(CameraUpdateFactory.newLatLngZoom(new LatLng(40.423, -3.73), 19), true, 500); 39 | animator.add(CameraUpdateFactory.newLatLngZoom(new LatLng(40.421, -3.71), 17), true, 1000); 40 | 41 | // Execute the animation and set the final OnCameraIdleListener 42 | animator.execute(); 43 | ``` 44 | 45 | ## License 46 | Copyright 2016 ANTONIO CARLON 47 | 48 | Licensed under the Apache License, Version 2.0 (the "License"); 49 | you may not use this file except in compliance with the License. 50 | You may obtain a copy of the License at 51 | 52 | http://www.apache.org/licenses/LICENSE-2.0 53 | 54 | Unless required by applicable law or agreed to in writing, software 55 | distributed under the License is distributed on an "AS IS" BASIS, 56 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 57 | See the License for the specific language governing permissions and 58 | limitations under the License. -------------------------------------------------------------------------------- /src/map/CameraUpdateAnimator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 ANTONIO CARLON 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package map; 18 | 19 | import android.os.Handler; 20 | import android.util.Log; 21 | 22 | import com.google.android.gms.maps.CameraUpdate; 23 | import com.google.android.gms.maps.GoogleMap; 24 | 25 | import java.util.ArrayList; 26 | import java.util.List; 27 | 28 | public class CameraUpdateAnimator implements GoogleMap.OnCameraIdleListener { 29 | private final GoogleMap mMap; 30 | private final GoogleMap.OnCameraIdleListener mOnCameraIdleListener; 31 | private List cameraUpdates = new ArrayList<>(); 32 | private boolean mIsRotateGestureEnabled; 33 | private boolean mIsScrollGestureEnabled; 34 | private boolean mIsTiltGestureEnabled; 35 | private boolean mIsZoomGestureEnabled; 36 | 37 | public CameraUpdateAnimator(GoogleMap map, 38 | GoogleMap.OnCameraIdleListener onCameraIdleListener) { 39 | mMap = map; 40 | mIsRotateGestureEnabled = mMap.getUiSettings().isRotateGesturesEnabled(); 41 | mIsScrollGestureEnabled = mMap.getUiSettings().isScrollGesturesEnabled(); 42 | mIsTiltGestureEnabled = mMap.getUiSettings().isTiltGesturesEnabled(); 43 | mIsZoomGestureEnabled = mMap.getUiSettings().isZoomGesturesEnabled(); 44 | 45 | mOnCameraIdleListener = onCameraIdleListener; 46 | } 47 | 48 | public void add(CameraUpdate cameraUpdate, boolean animate, long delay) { 49 | if (cameraUpdate != null) { 50 | cameraUpdates.add(new Animation(cameraUpdate, animate, delay)); 51 | } 52 | } 53 | 54 | public void clear() { 55 | cameraUpdates.clear(); 56 | } 57 | 58 | public void execute() { 59 | mMap.getUiSettings().setRotateGesturesEnabled(false); 60 | mMap.getUiSettings().setScrollGesturesEnabled(false); 61 | mMap.getUiSettings().setTiltGesturesEnabled(false); 62 | mMap.getUiSettings().setZoomGesturesEnabled(false); 63 | 64 | mMap.setOnCameraIdleListener(this); 65 | executeNext(); 66 | } 67 | 68 | private void executeNext() { 69 | if (!cameraUpdates.isEmpty()) { 70 | final Animation animation = cameraUpdates.remove(0); 71 | 72 | Handler handler = new android.os.Handler(); 73 | handler.postDelayed(new Runnable() { 74 | public void run() { 75 | if (animation.mAnimate) { 76 | mMap.animateCamera(animation.mCameraUpdate); 77 | } else { 78 | mMap.moveCamera(animation.mCameraUpdate); 79 | } 80 | } 81 | }, animation.mDelay); 82 | } else { 83 | mMap.setOnCameraIdleListener(mOnCameraIdleListener); 84 | mMap.getUiSettings().setRotateGesturesEnabled(mIsRotateGestureEnabled); 85 | mMap.getUiSettings().setScrollGesturesEnabled(mIsScrollGestureEnabled); 86 | mMap.getUiSettings().setTiltGesturesEnabled(mIsTiltGestureEnabled); 87 | mMap.getUiSettings().setZoomGesturesEnabled(mIsZoomGestureEnabled); 88 | } 89 | } 90 | 91 | @Override 92 | public void onCameraIdle() { 93 | executeNext(); 94 | } 95 | 96 | private class Animation { 97 | private final CameraUpdate mCameraUpdate; 98 | private final boolean mAnimate; 99 | private final long mDelay; 100 | 101 | public Animation(CameraUpdate cameraUpdate, boolean animate, long delay) { 102 | mCameraUpdate = cameraUpdate; 103 | mAnimate = animate; 104 | mDelay = delay; 105 | } 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /src/tiles/ExpandedMBTilesTileProvider.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 ANTONIO CARLON 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package tiles; 18 | 19 | import android.database.Cursor; 20 | import android.database.sqlite.SQLiteDatabase; 21 | import android.graphics.Bitmap; 22 | import android.graphics.BitmapFactory; 23 | import android.util.Log; 24 | 25 | import com.google.android.gms.maps.model.Tile; 26 | import com.google.android.gms.maps.model.TileProvider; 27 | 28 | import java.io.ByteArrayOutputStream; 29 | import java.io.File; 30 | 31 | /** 32 | * Tile provider that reads MBTiles format into Google Maps API Android v2 expanding 33 | * the available zoom levels to the lowest one 34 | * (lower zoom levels will be interpolated from higher levels). 35 | */ 36 | public class ExpandedMBTilesTileProvider implements TileProvider { 37 | private final File source; 38 | private final int width; 39 | private final int height; 40 | 41 | public ExpandedMBTilesTileProvider(final File source, final int width, final int height) { 42 | if (source == null) { 43 | throw new IllegalArgumentException("source cannot be null"); 44 | } 45 | this.source = source; 46 | this.width = width; 47 | this.height = height; 48 | } 49 | 50 | @Override 51 | public Tile getTile(final int x, int y, final int zoom) { 52 | Tile tile = NO_TILE; 53 | 54 | y = tms2gmaps(y, zoom); 55 | byte[] bitmap = retrieveBitmap(x, y, zoom); 56 | if (bitmap != null) { 57 | tile = new Tile(width, height, bitmap); 58 | } 59 | 60 | return tile; 61 | } 62 | 63 | private byte[] retrieveBitmap(final int x, final int y, final int zoom) { 64 | byte[] bitmap = null; 65 | 66 | if (zoom > 0) { 67 | bitmap = readBitmapFromDB(x, y, zoom); 68 | if (bitmap == null) { 69 | bitmap = crop(retrieveBitmap(x / 2, y / 2, zoom - 1), x, y); 70 | } 71 | } 72 | 73 | return bitmap; 74 | } 75 | 76 | private byte[] readBitmapFromDB(final int x, final int y, final int zoom) { 77 | byte[] bitmap = null; 78 | 79 | SQLiteDatabase db = null; 80 | Cursor cursor = null; 81 | 82 | try { 83 | db = SQLiteDatabase.openDatabase(source.getPath(), null, SQLiteDatabase.OPEN_READONLY); 84 | 85 | cursor = db.query("tiles", 86 | new String[]{"tile_data"}, 87 | "tile_column=? and tile_row=? and zoom_level=?", 88 | new String[]{"" + x, "" + y, "" + zoom}, 89 | null, 90 | null, 91 | null); 92 | 93 | if (cursor != null && cursor.moveToFirst()) { 94 | bitmap = cursor.getBlob(0); 95 | } 96 | } catch (final Exception e) { 97 | Log.e("Error reading database", e.getMessage()); 98 | } finally { 99 | try { 100 | if (cursor != null) { 101 | cursor.close(); 102 | } 103 | } catch (Exception e) { 104 | } 105 | 106 | try { 107 | if (db != null) { 108 | db.close(); 109 | } 110 | } catch (Exception e) { 111 | } 112 | } 113 | 114 | return bitmap; 115 | } 116 | 117 | private byte[] crop(final byte[] bmp, final int x, final int y) { 118 | byte[] output = bmp; 119 | if (bmp == null) { 120 | return output; 121 | } 122 | 123 | Bitmap bitmap = BitmapFactory.decodeByteArray(bmp, 0, bmp.length); 124 | bitmap = Bitmap.createBitmap( 125 | bitmap, 126 | x % 2 == 0 ? 0 : bitmap.getWidth() / 2, 127 | y % 2 == 0 ? bitmap.getHeight() / 2 : 0, 128 | bitmap.getWidth() / 2, 129 | bitmap.getHeight() / 2 130 | ); 131 | 132 | final ByteArrayOutputStream stream = new ByteArrayOutputStream(); 133 | bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream); 134 | bitmap.recycle(); 135 | output = stream.toByteArray(); 136 | 137 | return output; 138 | } 139 | 140 | private int tms2gmaps(final int y, final int zoom) { 141 | final int ymax = 1 << zoom; 142 | return ymax - y - 1; 143 | } 144 | } --------------------------------------------------------------------------------