/************************************************************************* * Copyright (c) 2015 Lemberg Solutions * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. **************************************************************************/ package com.ls.widgets.map; import java.util.ArrayList; import android.content.Context; import android.graphics.BitmapFactory; import android.graphics.Point; import android.graphics.drawable.BitmapDrawable; import android.test.AndroidTestCase; import android.util.Log; import android.view.animation.Animation.AnimationListener; import com.ls.widgets.map.config.OfflineMapConfig; import com.ls.widgets.map.interfaces.Layer; import com.ls.widgets.map.interfaces.MapEventsListener; import com.ls.widgets.map.interfaces.TileManagerDelegate; import com.ls.widgets.map.model.MapObject; import com.ls.widgets.map.providers.AssetTileProvider; public class MapWidgetTest extends AndroidTestCase { private TestMapWidget map; private BitmapDrawable drawable; @Override protected void setUp() throws Exception { map = new TestMapWidget(getContext(), "map", 11); map.setScale(1.0f); drawable = new BitmapDrawable(getContext().getResources(), BitmapFactory.decodeResource(getContext().getResources(), com.ls.widgets.map.test.R.drawable.maps_blue_dot)); super.setUp(); } @Override protected void tearDown() throws Exception { map.removeAllLayers(); map.startProcessing(); super.tearDown(); } public void testCreateLayer() { int layerIds[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; Layer layers[] = new Layer[layerIds.length]; for (int i = 0; i < layerIds.length; ++i) { layers[i] = map.createLayer(layerIds[i]); } for (int i = 0; i < layerIds.length; ++i) { Layer layer = map.getLayerById(Integer.valueOf(i)); assertNotNull(layer); assertSame(layers[i], layer); } boolean ok = false; try { map.createLayer(0); } catch (IllegalArgumentException e) { ok = true; } assertTrue(ok); } public void testRemoveLayer() { for (int i = -100; i <= 100; ++i) { map.createLayer(i); } for (int i = -100; i <= 100; ++i) { Layer layer = map.getLayerById(i); assertNotNull(layer); map.removeLayer(i); layer = map.getLayerById(i); assertNull(layer); } try { map.removeLayer(0); } catch (Exception e) { fail(); } } public void testGetLayer() { int layerIds[] = {10, 11, 12, 13, 14, 15, 16, 17, 18, 19}; Layer layers[] = new Layer[layerIds.length]; for (int i = 0; i < layerIds.length; ++i) { layers[i] = map.createLayer(layerIds[i]); } for (int i = 0; i < layerIds.length; ++i) { Layer layer = map.getLayer(i); assertSame(layers[i], layer); } boolean ok = false; try { map.getLayer(layerIds.length); } catch (IndexOutOfBoundsException e) { ok = true; } assertTrue(ok); } public void testGetLayerById() { int layerIds[] = {10, 11, 12, 13, 14, 15, 16, 17, 18, 19}; Layer layers[] = new Layer[layerIds.length]; for (int i = 0; i < layerIds.length; ++i) { layers[i] = map.createLayer(layerIds[i]); } for (int i = 0; i < layerIds.length; ++i) { Layer layer = map.getLayerById(layerIds[i]); assertSame(layers[i], layer); } assertNull(map.getLayerById(0)); } public void testGetLayerCount() { for (int j = 0; j < 100; ++j) { for (int i = 0; i < j; ++i) { map.createLayer(i); } assertEquals(map.getLayerCount(), j); map.removeAllLayers(); } } public void testGetMapHeight() { int height = map.getConfig().getImageHeight(); for (int i = 1; i <= 11; ++i) { assertEquals("i:" + i, height, map.getMapHeight()); map.zoomOut(); height = (int) Math.ceil(height / 2.0f); } } public void testGetMapWidth() { int width = map.getConfig().getImageWidth(); for (int i = 1; i <= 11; ++i) { assertEquals("i:" + i, width, map.getMapWidth()); map.zoomOut(); width = (int) Math.ceil(width / 2.0f); } } public void testGetOriginalMapWidth() { int width = map.getConfig().getImageWidth(); for (int i = 1; i <= 11; ++i) { assertEquals(width, map.getOriginalMapWidth()); map.zoomOut(); } } public void testGetOriginalMapHeight() { int height = map.getConfig().getImageHeight(); for (int i = 1; i <= 11; ++i) { assertEquals(height, map.getOriginalMapHeight()); map.zoomOut(); } } public void testGetConfig() { OfflineMapConfig config = map.getConfig(); assertNotNull(config); config.setMaxZoomLevelLimit(1); config = map.getConfig(); assertTrue(config.getMaxZoomLevelLimit() == 1); } public void testGetScale() { float scalesUp[] = {1.0f, 2.0f, 4.0f, 8.0f, 16f, 32f}; float scalesDown[] = {1.0f, 0.5f, 0.25f, 0.125f}; map.setAnimationEnabled(false); for (int i = 0; i < scalesUp.length; ++i) { assertEquals("i=" + i, scalesUp[i], map.getScale()); map.zoomIn(); } for (int i = 0; i < scalesUp.length; ++i) { map.zoomOut(); } for (int i = 0; i < scalesDown.length; ++i) { assertEquals(scalesDown[i], map.getScale()); map.zoomOut(); } for (int i = 0; i < 20; i++) { double testScale = 0.1; final double step = 0.1; while (testScale < 3.0f) { float prevScale = map.getScale(); int prevWidth = map.getMapWidth(); Log.d("MapWidgetTest", "ZL: " + map.getZoomLevel() + ", scale: " + map.getScale() + ", width: " + map.getMapWidth() + ", testScale: " + testScale); map.setScale((float) testScale); assertEquals("ZL: " + map.getZoomLevel() + ", prevScale: " + prevScale + ", CurScale:" + (float) testScale + ", prevWidth: " + prevWidth, (float) (prevScale * testScale), map.getScale()); map.setScale(1.0f); testScale += step; } map.zoomIn(); } } public void testGetZoomLevel() { map.setAnimationEnabled(false); // Test lower bound for (int i = 11; i >= -11; --i) { int zl = map.getZoomLevel(); if (i >= 0) { assertEquals(i, zl); } map.zoomOut(); } assertEquals(0, map.getZoomLevel()); // Test regular zoom with software zoom is enabled for (int i = 0; i <= 22; ++i) { int zl = map.getZoomLevel(); assertEquals(i, zl); map.zoomIn(); } // Test upper bound when software zoom is disabled map = new TestMapWidget(getContext(), "map", 1); map.setScale(1.0f); map.setAnimationEnabled(false); OfflineMapConfig conf = map.getConfig(); conf.setSoftwareZoomEnabled(false); for (int i = 1; i <= 22; ++i) { int zl = map.getZoomLevel(); if (i <= 11) { assertEquals(i, zl); } else { assertEquals(11, zl); } map.zoomIn(); } } public void testRemoveAllLayers() { for (int i = -50; i < 50; ++i) { map.createLayer(i); } assertEquals(100, map.getLayerCount()); map.removeAllLayers(); for (int i = -50; i < 50; ++i) { assertNull("i:" + i, map.getLayerById(i)); } } public void testClearLayers() { int count = 50; MapObject[] objects = generateMapObjects(count); ArrayList<Layer> layers = new ArrayList<Layer>(10); for (int i = -5; i < 5; ++i) { Layer layer = map.createLayer(i); for (MapObject object : objects) { layer.addMapObject(object); } layers.add(layer); assertEquals(count, layer.getMapObjectCount()); } map.clearLayers(); for (Layer layer : layers) { assertEquals(0, layer.getMapObjectCount()); } } public void testSetMinZoomLevel() { for (int j = 10; j >= 0; --j) { map = new TestMapWidget(getContext(), "map", 11); map.setAnimationEnabled(false); map.setMinZoomLevel(j); for (int i = j; i >= 0; --i) { map.zoomOut(); int zl = map.getZoomLevel(); if (zl < j) { fail("ZL: " + zl + ", j: " + j); } } } } public void testSetMaxZoomLevel() { for (int j = 2; j <= 11; ++j) { map = new TestMapWidget(getContext(), "map", 1); map.setAnimationEnabled(false); map.setMaxZoomLevel(j); for (int i = 2; i <= 11; ++i) { map.zoomIn(); int zl = map.getZoomLevel(); if (zl > j) { fail("ZL: " + zl + ", j: " + j); } } } } public void testSetScale() { map = new TestMapWidget(getContext(), "map", 1); map.setAnimationEnabled(false); float scalesUp[] = {1.0f, 2.0f, 4.0f, 8.0f, 16f, 32f}; float scalesDown[] = {1.0f, 0.5f, 0.25f, 0.125f}; for (int j = 0; j < 15; ++j) { for (int i = 0; i < scalesDown.length; ++i) { float oldScale = map.getScale(); map.setScale(scalesDown[i]); float newScale = map.getScale(); assertEquals("zl:" + map.getZoomLevel() + ", i:" + i + ", os:" + oldScale + ", ns:" + newScale, scalesDown[i], newScale / oldScale); map.setScale(1.0f); } for (int i = 0; i < scalesUp.length; ++i) { float oldScale = map.getScale(); map.setScale(scalesUp[i]); float newScale = map.getScale(); assertEquals("zl:" + map.getZoomLevel(), scalesUp[i], newScale / oldScale); map.setScale(1.0f); } map.zoomIn(); } } public void testUseSoftwareZoom() { map.setAnimationEnabled(false); map.setUseSoftwareZoom(false); for (int i = 0; i < 10; ++i) { map.zoomIn(); } assertEquals(11, map.getZoomLevel()); map.setUseSoftwareZoom(true); for (int i = 0; i < 10; ++i) { map.zoomIn(); } assertEquals(11 + 10, map.getZoomLevel()); } public void testZoomIn() { map = new TestMapWidget(getContext(), "map", 1); map.setAnimationEnabled(false); TestMapEventsListener listener = new TestMapEventsListener(); for (int i = 2; i <= 13; ++i) { map.addMapEventsListener(listener); float oldScale = map.getScale(); map.zoomIn(); float newScale = map.getScale(); assertTrue("I:" + i + ", zoomIn: " + listener.counters[TestMapEventsListener.PRE_ZOOM_IN] + " " + listener.counters[TestMapEventsListener.POST_ZOOM_IN], listener.zoomInValid()); assertEquals("i:" + i, 2.0f, newScale / oldScale); map.removeMapEventsListener(listener); listener.clearCounters(); } } public void testZoomOut() { map.setAnimationEnabled(false); TestMapEventsListener listener = new TestMapEventsListener(); for (int i = 2; i <= 11; ++i) { map.addMapEventsListener(listener); float oldScale = map.getScale(); map.zoomOut(); float newScale = map.getScale(); assertTrue("I:" + i + ", zoomOut: " + listener.counters[TestMapEventsListener.PRE_ZOOM_OUT] + " " + listener.counters[TestMapEventsListener.POST_ZOOM_OUT], listener.zoomOutValid()); assertEquals(2.0f, oldScale / newScale); map.removeMapEventsListener(listener); listener.clearCounters(); } } // FIXME: Temporarily disabled // public void testAnimatedZoomIn() { // map = new TestMapWidget(getContext(), "map", 1); // map.setAnimationEnabled(true); // final Object event = new Object(); // // TestMapEventsListener listener = new TestMapEventsListener() { // @Override // public void onPostZoomIn() { // super.onPostZoomIn(); // // synchronized (event) { // event.notify(); // } // } // }; // // // for (int i = 2; i <= 11; ++i) { // map.addMapEventsListener(listener); // float oldScale = map.getScale(); // map.zoomIn(); // // synchronized (event) { // try { // event.wait(3000); // } catch (InterruptedException e) { // fail(e.toString()); // e.printStackTrace(); // } // } // // float newScale = map.getScale(); // map.removeMapEventsListener(listener); // assertTrue("I:" + i + ", zoomIn: " + listener.counters[TestMapEventsListener.PRE_ZOOM_IN] + // " " + listener.counters[TestMapEventsListener.POST_ZOOM_IN], // listener.zoomInValid()); // assertEquals(2.0f, newScale / oldScale); // listener.clearCounters(); // } // } public void testAnimatedZoomOut() { map.setAnimationEnabled(true); TestMapEventsListener listener = new TestMapEventsListener(); for (int i = 2; i <= 11; ++i) { map.addMapEventsListener(listener); float oldScale = map.getScale(); map.zoomOut(); float newScale = map.getScale(); map.removeMapEventsListener(listener); assertTrue("I:" + i + ", zoomOut: " + listener.counters[TestMapEventsListener.PRE_ZOOM_OUT] + " " + listener.counters[TestMapEventsListener.POST_ZOOM_OUT], listener.zoomOutValid()); assertEquals(2.0f, oldScale / newScale); listener.clearCounters(); } } private MapObject[] generateMapObjects(int count) { MapObject[] result = new MapObject[count]; for (int i = 0; i < count; ++i) { MapObject object = new MapObject(i, drawable, new Point(0, 0)); result[i] = object; } return result; } private class TestMapEventsListener implements MapEventsListener { public static final int PRE_ZOOM_IN = 0; public static final int PRE_ZOOM_OUT = 1; public static final int POST_ZOOM_IN = 2; public static final int POST_ZOOM_OUT = 3; private int counters[]; public TestMapEventsListener() { counters = new int[]{0, 0, 0, 0}; } @Override public void onPreZoomIn() { counters[PRE_ZOOM_IN] += 1; } @Override public void onPostZoomIn() { counters[POST_ZOOM_IN] += 1; } @Override public void onPreZoomOut() { counters[PRE_ZOOM_OUT] += 1; } @Override public void onPostZoomOut() { counters[POST_ZOOM_OUT] += 1; } public void clearCounters() { counters = new int[]{0, 0, 0, 0}; } public boolean zoomInValid() { return counters[PRE_ZOOM_IN] == 1 && counters[POST_ZOOM_IN] == 1; } public boolean zoomOutValid() { return counters[PRE_ZOOM_OUT] == 1 && counters[POST_ZOOM_OUT] == 1; } } private class TestMapWidget extends MapWidget { public TestMapWidget(Context context, String rootMapFolder) { super(context, rootMapFolder); this.tileProvider = new TestTileManager(context, this.getConfig()); this.setTileProvider(tileProvider); } public TestMapWidget(Context context, String rootMapFolder, int initialZl) { super(context, rootMapFolder, initialZl); this.tileProvider = new TestTileManager(context, this.getConfig()); this.setTileProvider(tileProvider); } @Override protected void animateZoomIn(final AnimationListener listener, float pivotX, float pivotY) { (new Thread(new Runnable() { @Override public void run() { try { Thread.sleep(300); } catch (InterruptedException e) { e.printStackTrace(); } post(new Runnable() { public void run() { onAnimationEnd(); } }); } })).start(); } @Override protected void animateZoomOut(final AnimationListener listener) { (new Thread(new Runnable() { @Override public void run() { try { Thread.sleep(300); } catch (InterruptedException e) { e.printStackTrace(); } post(new Runnable() { public void run() { onAnimationEnd(); } }); //onAnimationEnd(); //listener.onAnimationEnd(null); } })).start(); } public void startProcessing() { super.startProcessingRequests(); } } private class TestTileManager extends AssetTileProvider { public TestTileManager(Context context, OfflineMapConfig config) { super(context, config); } @Override public void requestTile(int zoomLevel, int col, int row, TileManagerDelegate delegate) { delegate.onTileReady(zoomLevel, col, row, drawable); } } }