1 package com.xtremelabs.robolectric.shadows; 2 3 import android.app.Activity; 4 import android.graphics.Point; 5 import android.view.MotionEvent; 6 import android.view.View; 7 import com.google.android.maps.GeoPoint; 8 import com.google.android.maps.MapView; 9 import com.xtremelabs.robolectric.WithTestDefaultsRunner; 10 import com.xtremelabs.robolectric.bytecode.AndroidTranslatorTest; 11 import org.junit.Before; 12 import org.junit.Test; 13 import org.junit.runner.RunWith; 14 15 import static com.xtremelabs.robolectric.shadows.ShadowMapView.toE6; 16 import static org.hamcrest.CoreMatchers.equalTo; 17 import static org.hamcrest.CoreMatchers.nullValue; 18 import static org.hamcrest.CoreMatchers.sameInstance; 19 import static org.junit.Assert.assertThat; 20 21 @RunWith(WithTestDefaultsRunner.class) 22 public class MapViewTest { 23 private MapView mapView; 24 private MyOverlay overlay1; 25 private MyOverlay overlay2; 26 private MotionEvent sourceEvent; 27 private MyOnTouchListener mapTouchListener; 28 29 30 @Before public void setUp() throws Exception { 31 mapView = new MapView(new Activity(), "foo"); 32 33 overlay1 = new MyOverlay(); 34 overlay2 = new MyOverlay(); 35 mapTouchListener = new MyOnTouchListener(); 36 37 mapView.getOverlays().add(overlay1); 38 mapView.getOverlays().add(overlay2); 39 mapView.setOnTouchListener(mapTouchListener); 40 41 sourceEvent = MotionEvent.obtain(0, 0, 0, 0, 0, 0); 42 } 43 44 @Test 45 public void shouldDispatchTouchEventsToOverlays() throws Exception { 46 mapView.dispatchTouchEvent(sourceEvent); 47 48 assertThat(overlay1.lastMotionEvent, sameInstance(sourceEvent)); 49 assertThat(overlay2.lastMotionEvent, nullValue()); 50 assertThat(mapTouchListener.lastMotionEvent, nullValue()); 51 } 52 53 @Test 54 public void shouldDispatchTouchEventsToOverlaysUntilEventIsConsumed() throws Exception { 55 overlay1.shouldConsumeEvent = false; 56 overlay2.shouldConsumeEvent = true; 57 58 mapView.dispatchTouchEvent(sourceEvent); 59 60 assertThat(overlay1.lastMotionEvent, sameInstance(sourceEvent)); 61 assertThat(overlay2.lastMotionEvent, sameInstance(sourceEvent)); 62 assertThat(mapTouchListener.lastMotionEvent, nullValue()); 63 } 64 65 @Test 66 public void shouldDispatchTouchEventsToMapViewIfNoOverlayConsumesEvent() throws Exception { 67 overlay1.shouldConsumeEvent = false; 68 overlay2.shouldConsumeEvent = false; 69 70 mapView.dispatchTouchEvent(sourceEvent); 71 72 assertThat(overlay1.lastMotionEvent, sameInstance(sourceEvent)); 73 assertThat(overlay2.lastMotionEvent, sameInstance(sourceEvent)); 74 assertThat(mapTouchListener.lastMotionEvent, sameInstance(sourceEvent)); 75 } 76 77 @Test 78 public void dispatchTouchEvents_shouldDragMapByCorrectAmount() throws Exception { 79 initMapForDrag(); 80 81 dispatchTouchEvent(MotionEvent.ACTION_DOWN, 10, 10); 82 dispatchTouchEvent(MotionEvent.ACTION_UP, 11, 11); 83 assertThat(mapView.getMapCenter(), equalTo(new GeoPoint(toE6(26), toE6(24)))); 84 } 85 86 @Test 87 public void dispatchTouchEvents_shouldDragMapByCorrectAmountInMultipleSteps() throws Exception { 88 initMapForDrag(); 89 90 dispatchTouchEvent(MotionEvent.ACTION_DOWN, 10, 10); 91 dispatchTouchEvent(MotionEvent.ACTION_MOVE, 11, 11); 92 dispatchTouchEvent(MotionEvent.ACTION_MOVE, 12, 12); 93 dispatchTouchEvent(MotionEvent.ACTION_UP, 11, 11); 94 assertThat(mapView.getMapCenter(), equalTo(new GeoPoint(toE6(26), toE6(24)))); 95 } 96 97 @Test 98 public void dispatchTouchEvents_shouldMoveBackToCenterOnCancel() throws Exception { 99 initMapForDrag(); 100 101 dispatchTouchEvent(MotionEvent.ACTION_DOWN, 10, 10); 102 dispatchTouchEvent(MotionEvent.ACTION_MOVE, 11, 11); 103 dispatchTouchEvent(MotionEvent.ACTION_MOVE, 12, 12); 104 dispatchTouchEvent(MotionEvent.ACTION_CANCEL, 11, 11); 105 assertThat(mapView.getMapCenter(), equalTo(new GeoPoint(toE6(25), toE6(25)))); 106 } 107 108 private void initMapForDrag() { 109 mapView = new MapView(null, ""); 110 mapView.layout(0, 0, 50, 50); 111 mapView.getController().setCenter(new GeoPoint(toE6(25), toE6(25))); 112 mapView.getController().zoomToSpan(toE6(50), toE6(50)); 113 } 114 115 @Test 116 public void getProjection_fromPixels_shouldPerformCorrectTranslations() throws Exception { 117 int centerLat = 11; 118 int centerLng = 16; 119 int spanLat = 20; 120 int spanLng = 30; 121 122 mapView.getController().setCenter(new GeoPoint(toE6(centerLat), toE6(centerLng))); 123 mapView.getController().zoomToSpan(toE6(spanLat), toE6(spanLng)); 124 mapView.layout(50, 60, 650, 460); 125 126 assertThat(mapView.getProjection().fromPixels(50, 60), 127 equalTo(new GeoPoint(toE6(21), toE6(1)))); 128 assertThat(mapView.getProjection().fromPixels(350, 260), 129 equalTo(new GeoPoint(toE6(11), toE6(16)))); 130 assertThat(mapView.getProjection().fromPixels(650, 460), 131 equalTo(new GeoPoint(toE6(1), toE6(31)))); 132 } 133 134 @Test 135 public void getProjection_toPixels_shouldPerformCorrectTranslations() throws Exception { 136 int centerLat = 11; 137 int centerLng = 16; 138 int spanLat = 20; 139 int spanLng = 30; 140 141 mapView.getController().setCenter(new GeoPoint(toE6(centerLat), toE6(centerLng))); 142 mapView.getController().zoomToSpan(toE6(spanLat), toE6(spanLng)); 143 mapView.layout(50, 60, 650, 460); 144 145 assertThat(mapView.getProjection().toPixels(new GeoPoint(toE6(21), toE6(1)), null), 146 equalTo(new Point(50, 60))); 147 assertThat(mapView.getProjection().toPixels(new GeoPoint(toE6(11), toE6(16)), null), 148 equalTo(new Point(350, 260))); 149 assertThat(mapView.getProjection().toPixels(new GeoPoint(toE6(1), toE6(31)), null), 150 equalTo(new Point(650, 460))); 151 } 152 153 private void dispatchTouchEvent(int action, int x, int y) { 154 mapView.dispatchTouchEvent(MotionEvent.obtain(0, 0, action, x, y, 0)); 155 } 156 157 private static class MyOnTouchListener implements View.OnTouchListener { 158 private MotionEvent lastMotionEvent; 159 160 @Override public boolean onTouch(View v, MotionEvent event) { 161 lastMotionEvent = event; 162 return false; 163 } 164 } 165 166 private class MyOverlay extends AndroidTranslatorTest.ItemizedOverlayForTests { 167 private MotionEvent lastMotionEvent; 168 private boolean shouldConsumeEvent = true; 169 170 public MyOverlay() { 171 super(null); 172 } 173 174 @Override public boolean onTouchEvent(MotionEvent motionEvent, MapView mapView) { 175 lastMotionEvent = motionEvent; 176 return shouldConsumeEvent; 177 } 178 } 179 } 180