diff options
author | Tobrun <tobrun.van.nuland@gmail.com> | 2017-11-10 06:16:35 +0100 |
---|---|---|
committer | Tobrun <tobrun.van.nuland@gmail.com> | 2017-11-10 06:16:35 +0100 |
commit | 225fba8a0aad5ea52ff878443f58d65bb2221d74 (patch) | |
tree | 8fef9e5353ec33f2fc0cec378a77d7146f9c67d0 /platform/android/MapboxGLAndroidSDKTestApp | |
parent | 6b5afaab7611cc59c86f749fd9130edb512b4945 (diff) | |
parent | 91dabd01dfcd52dc40aa1c1d1db9d3f48f7abc97 (diff) | |
download | qtlocation-mapboxgl-225fba8a0aad5ea52ff878443f58d65bb2221d74.tar.gz |
Merge branch 'release-agua' into tvn-merge-release
Diffstat (limited to 'platform/android/MapboxGLAndroidSDKTestApp')
16 files changed, 469 insertions, 228 deletions
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/build.gradle b/platform/android/MapboxGLAndroidSDKTestApp/build.gradle index 81ee635cf1..f45ad3dc3a 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/build.gradle +++ b/platform/android/MapboxGLAndroidSDKTestApp/build.gradle @@ -59,6 +59,7 @@ dependencies { // Support libraries compile rootProject.ext.dep.supportAppcompatV7 compile rootProject.ext.dep.supportRecyclerView + compile rootProject.ext.dep.supportDesign // Leak Canary debugCompile rootProject.ext.dep.leakCanaryDebug @@ -71,7 +72,6 @@ dependencies { compile rootProject.ext.dep.lost // Testing dependencies - androidTestCompile rootProject.ext.dep.testSpoonRunner androidTestCompile rootProject.ext.dep.supportAnnotations androidTestCompile rootProject.ext.dep.testRunner androidTestCompile rootProject.ext.dep.testRules @@ -81,8 +81,6 @@ dependencies { apply from: 'gradle-make.gradle' apply from: 'gradle-config.gradle' -apply from: 'gradle-device-farm.gradle' -apply from: 'gradle-spoon.gradle' apply from: 'gradle-checkstyle.gradle' apply from: '../gradle-lint.gradle' diff --git a/platform/android/MapboxGLAndroidSDKTestApp/gradle-device-farm.gradle b/platform/android/MapboxGLAndroidSDKTestApp/gradle-device-farm.gradle deleted file mode 100644 index 5cb5d75bbb..0000000000 --- a/platform/android/MapboxGLAndroidSDKTestApp/gradle-device-farm.gradle +++ /dev/null @@ -1,43 +0,0 @@ -apply plugin: 'devicefarm' - -def getAccessKeyDeviceFarm() { - if (project.hasProperty('AWS_ACCESS_KEY_ID_DEVICE_FARM')) { - return AWS_ACCESS_KEY_ID_DEVICE_FARM - } else { - println("Could not locate AWS_ACCESS_KEY_ID_DEVICE_FARM in gradle.properties") - return "" - } -} - -def getSecretAccessKeyDeviceFarm() { - if (project.hasProperty('AWS_SECRET_ACCESS_KEY_DEVICE_FARM')) { - return AWS_SECRET_ACCESS_KEY_DEVICE_FARM - } else { - println("Could not locate AWS_SECRET_ACCESS_KEY_DEVICE_FARM in gradle.properties") - return "" - } -} - -devicefarm { - - projectName "Mapbox GL Android" // required: Must already exists. - devicePool "sanity" // optional: Defaults to "Top Devices" - - authentication { - accessKey getAccessKeyDeviceFarm() - secretKey getSecretAccessKeyDeviceFarm() - } - - devicestate { - wifi "on" - bluetooth "off" - gps "on" - nfc "on" - latitude 47.6204 // default - longitude - 122.3491 // default - } - - instrumentation { - - } -} diff --git a/platform/android/MapboxGLAndroidSDKTestApp/gradle-spoon.gradle b/platform/android/MapboxGLAndroidSDKTestApp/gradle-spoon.gradle deleted file mode 100644 index 7a5b966443..0000000000 --- a/platform/android/MapboxGLAndroidSDKTestApp/gradle-spoon.gradle +++ /dev/null @@ -1,8 +0,0 @@ -println "configuring spoon" -apply plugin: 'spoon' -spoon { - // Spoon: distributes instrumentation tests to all your Androids - // for more options see https://github.com/stanfy/spoon-gradle-plugin - grantAllPermissions = true - debug = true -} diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/MapboxMapTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/MapboxMapTest.java index 294d57bce1..3dbbaceb1a 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/MapboxMapTest.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/MapboxMapTest.java @@ -14,6 +14,7 @@ import com.mapbox.mapboxsdk.annotations.Polygon; import com.mapbox.mapboxsdk.annotations.PolygonOptions; import com.mapbox.mapboxsdk.annotations.Polyline; import com.mapbox.mapboxsdk.annotations.PolylineOptions; +import com.mapbox.mapboxsdk.camera.CameraUpdateFactory; import com.mapbox.mapboxsdk.constants.MapboxConstants; import com.mapbox.mapboxsdk.exceptions.InvalidMarkerPositionException; import com.mapbox.mapboxsdk.geometry.LatLng; @@ -31,9 +32,12 @@ import org.junit.Test; import java.util.ArrayList; import java.util.List; +import timber.log.Timber; + import static android.support.test.espresso.Espresso.onView; import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed; import static android.support.test.espresso.matcher.ViewMatchers.withId; +import static com.mapbox.mapboxsdk.testapp.utils.TestConstants.LAT_LNG_DELTA; import static junit.framework.TestCase.assertFalse; import static junit.framework.TestCase.assertNotNull; import static org.junit.Assert.assertEquals; @@ -90,9 +94,34 @@ public class MapboxMapTest extends BaseActivityTest { } // - // CameraForLatLngBounds + // Camera tests // @Test + public void testCameraPositionOnFinish() { + ViewUtils.checkViewIsDisplayed(R.id.mapView); + onView(withId(R.id.mapView)).perform(new MapboxMapAction(new InvokeViewAction() { + @Override + public void onViewAction(UiController uiController, View view) { + + final LatLng latLng = new LatLng(30.0, 30.0); + mapboxMap.moveCamera(CameraUpdateFactory.newLatLng(latLng), new MapboxMap.CancelableCallback() { + @Override + public void onCancel() { + } + + @Override + public void onFinish() { + LatLng cameraPositionLatLng = mapboxMap.getCameraPosition().target; + Timber.d(cameraPositionLatLng.toString()); + assertEquals(cameraPositionLatLng.getLatitude(), latLng.getLatitude(), LAT_LNG_DELTA); + assertEquals(cameraPositionLatLng.getLongitude(), latLng.getLongitude(), LAT_LNG_DELTA); + } + }); + } + })); + } + + @Test public void testCameraForLatLngBounds() { ViewUtils.checkViewIsDisplayed(R.id.mapView); onView(withId(R.id.mapView)).perform(new MapboxMapAction(new InvokeViewAction() { diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/activity/BaseActivityTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/activity/BaseActivityTest.java index c029bc09c4..61bff1f113 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/activity/BaseActivityTest.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/activity/BaseActivityTest.java @@ -49,8 +49,9 @@ public abstract class BaseActivityTest { throw new RuntimeException("Could not start test for " + getActivityClass().getSimpleName() + ".\n" + "The ViewHierarchy doesn't contain a view with resource id = R.id.mapView or \n" + "the Activity doesn't contain an instance variable with a name equal to mapboxMap.\n" - + "You can resolve this issue be implementing the requirements above or\n add " - + getActivityClass().getSimpleName() + " to the excludeActivities array in `generate-test-code.js`.\n"); + + "You can resolve this issue by adding the requirements above or\n add " + + getActivityClass().getSimpleName() + " to the platform/android/scripts/exclude-activity-gen.json to blacklist" + + " the Activity from being generated.\n"); } } @@ -67,8 +68,7 @@ public abstract class BaseActivityTest { protected abstract Class getActivityClass(); protected void checkViewIsDisplayed(int id) { - onView(withId(id)) - .check(matches(isDisplayed())); + onView(withId(id)).check(matches(isDisplayed())); } protected void waitLoop() { diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/widgets/AttributionTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/widgets/AttributionTest.java index d37c6db2d5..a20426c29c 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/widgets/AttributionTest.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/widgets/AttributionTest.java @@ -21,6 +21,7 @@ import com.mapbox.mapboxsdk.testapp.activity.espresso.EspressoTestActivity; import org.hamcrest.Matcher; import org.junit.After; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import static android.support.test.espresso.Espresso.onData; @@ -67,6 +68,7 @@ public class AttributionTest extends BaseActivityTest { } @Test + @Ignore public void testMapboxStreetsMapboxAttributionLink() { validateTestSetup(); if (urlSpans == null) { @@ -87,6 +89,7 @@ public class AttributionTest extends BaseActivityTest { } @Test + @Ignore public void testMapboxStreetsOpenStreetMapAttributionLink() { validateTestSetup(); if (urlSpans == null) { @@ -107,6 +110,7 @@ public class AttributionTest extends BaseActivityTest { } @Test + @Ignore public void testImproveMapLink() { validateTestSetup(); if (urlSpans == null) { diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/utils/OnMapReadyIdlingResource.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/utils/OnMapReadyIdlingResource.java index 1c4981ca5e..0e2e4587ee 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/utils/OnMapReadyIdlingResource.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/utils/OnMapReadyIdlingResource.java @@ -13,10 +13,8 @@ public class OnMapReadyIdlingResource implements IdlingResource, OnMapReadyCallb private MapboxMap mapboxMap; private IdlingResource.ResourceCallback resourceCallback; - private Activity activity; public OnMapReadyIdlingResource(Activity activity) { - this.activity = activity; try { Field field = activity.getClass().getDeclaredField("mapView"); field.setAccessible(true); @@ -24,7 +22,6 @@ public class OnMapReadyIdlingResource implements IdlingResource, OnMapReadyCallb } catch (Exception err) { throw new RuntimeException(err); } - } @Override @@ -53,4 +50,4 @@ public class OnMapReadyIdlingResource implements IdlingResource, OnMapReadyCallb resourceCallback.onTransitionToIdle(); } } -} +}
\ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/CameraAnimatorActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/CameraAnimatorActivity.java index cc44ac9715..c8c5c6bd37 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/CameraAnimatorActivity.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/CameraAnimatorActivity.java @@ -5,13 +5,20 @@ import android.animation.AnimatorSet; import android.animation.TypeEvaluator; import android.animation.ValueAnimator; import android.os.Bundle; +import android.support.v4.util.LongSparseArray; import android.support.v4.view.animation.FastOutLinearInInterpolator; import android.support.v4.view.animation.FastOutSlowInInterpolator; +import android.support.v4.view.animation.PathInterpolatorCompat; import android.support.v7.app.AppCompatActivity; +import android.view.Menu; +import android.view.MenuItem; import android.view.View; import android.view.animation.AnticipateOvershootInterpolator; +import android.view.animation.BounceInterpolator; +import android.view.animation.Interpolator; import com.mapbox.mapboxsdk.camera.CameraPosition; +import com.mapbox.mapboxsdk.camera.CameraUpdateFactory; import com.mapbox.mapboxsdk.geometry.LatLng; import com.mapbox.mapboxsdk.maps.MapView; import com.mapbox.mapboxsdk.maps.MapboxMap; @@ -24,6 +31,51 @@ import com.mapbox.mapboxsdk.testapp.R; public class CameraAnimatorActivity extends AppCompatActivity implements OnMapReadyCallback { private static final double ANIMATION_DELAY_FACTOR = 1.5; + private static final LatLng START_LAT_LNG = new LatLng(37.787947, -122.407432); + + private final LongSparseArray<AnimatorBuilder> animators = new LongSparseArray<AnimatorBuilder>() { + { + put(R.id.menu_action_accelerate_decelerate_interpolator, new AnimatorBuilder() { + @Override + public Animator build() { + AnimatorSet animatorSet = new AnimatorSet(); + animatorSet.playTogether( + createLatLngAnimator(START_LAT_LNG, new LatLng(37.826715, -122.422795)), + obtainExampleInterpolator(new FastOutSlowInInterpolator(), 2500) + ); + return animatorSet; + } + }); + + put(R.id.menu_action_bounce_interpolator, new AnimatorBuilder() { + @Override + public Animator build() { + AnimatorSet animatorSet = new AnimatorSet(); + animatorSet.playTogether( + createLatLngAnimator(START_LAT_LNG, new LatLng(37.787947, -122.407432)), + obtainExampleInterpolator(new BounceInterpolator(), 3750) + ); + return animatorSet; + } + }); + + put(R.id.menu_action_anticipate_overshoot_interpolator, new AnimatorBuilder() { + @Override + public Animator build() { + return obtainExampleInterpolator(new AnticipateOvershootInterpolator(), 2500); + } + }); + + put(R.id.menu_action_path_interpolator, new AnimatorBuilder() { + @Override + public Animator build() { + return obtainExampleInterpolator( + PathInterpolatorCompat.create(.22f, .68f, 0, 1.71f), 2500); + } + }); + } + }; + private MapView mapView; private MapboxMap mapboxMap; @@ -32,7 +84,6 @@ public class CameraAnimatorActivity extends AppCompatActivity implements OnMapRe protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_camera_animator); - mapView = (MapView) findViewById(R.id.mapView); if (mapView != null) { mapView.onCreate(savedInstanceState); @@ -43,27 +94,42 @@ public class CameraAnimatorActivity extends AppCompatActivity implements OnMapRe @Override public void onMapReady(final MapboxMap map) { mapboxMap = map; + initFab(); + } + + private void initFab() { findViewById(R.id.fab).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { view.setVisibility(View.GONE); - createAnimator(mapboxMap.getCameraPosition()).start(); + + CameraPosition animatedPosition = new CameraPosition.Builder() + .target(new LatLng(37.789992, -122.402214)) + .tilt(60) + .zoom(14.5f) + .bearing(135) + .build(); + + createExampleAnimator(mapboxMap.getCameraPosition(), animatedPosition).start(); } }); } - private Animator createAnimator(CameraPosition currentPosition) { + // + // Animator API used for the animation on the FAB + // + + private Animator createExampleAnimator(CameraPosition currentPosition, CameraPosition targetPosition) { AnimatorSet animatorSet = new AnimatorSet(); - animatorSet.play(createLatLngAnimator(currentPosition.target)); - animatorSet.play(createZoomAnimator(currentPosition.zoom)); - animatorSet.play(createBearingAnimator(currentPosition.bearing)); - animatorSet.play(createTiltAnimator(currentPosition.tilt)); + animatorSet.play(createLatLngAnimator(currentPosition.target, targetPosition.target)); + animatorSet.play(createZoomAnimator(currentPosition.zoom, targetPosition.zoom)); + animatorSet.play(createBearingAnimator(currentPosition.bearing, targetPosition.bearing)); + animatorSet.play(createTiltAnimator(currentPosition.tilt, targetPosition.tilt)); return animatorSet; } - private Animator createLatLngAnimator(LatLng currentPosition) { - LatLng target = new LatLng(37.789992, -122.402214); - ValueAnimator latLngAnimator = ValueAnimator.ofObject(new LatLngEvaluator(), currentPosition, target); + private Animator createLatLngAnimator(LatLng currentPosition, LatLng targetPosition) { + ValueAnimator latLngAnimator = ValueAnimator.ofObject(new LatLngEvaluator(), currentPosition, targetPosition); latLngAnimator.setDuration((long) (1000 * ANIMATION_DELAY_FACTOR)); latLngAnimator.setInterpolator(new FastOutSlowInInterpolator()); latLngAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @@ -75,8 +141,8 @@ public class CameraAnimatorActivity extends AppCompatActivity implements OnMapRe return latLngAnimator; } - private Animator createZoomAnimator(double currentZoom) { - ValueAnimator zoomAnimator = ValueAnimator.ofFloat((float) currentZoom, 14.5f); + private Animator createZoomAnimator(double currentZoom, double targetZoom) { + ValueAnimator zoomAnimator = ValueAnimator.ofFloat((float) currentZoom, (float) targetZoom); zoomAnimator.setDuration((long) (2200 * ANIMATION_DELAY_FACTOR)); zoomAnimator.setStartDelay((long) (600 * ANIMATION_DELAY_FACTOR)); zoomAnimator.setInterpolator(new AnticipateOvershootInterpolator()); @@ -89,8 +155,8 @@ public class CameraAnimatorActivity extends AppCompatActivity implements OnMapRe return zoomAnimator; } - private Animator createBearingAnimator(double currentBearing) { - ValueAnimator bearingAnimator = ValueAnimator.ofFloat((float) currentBearing, 135); + private Animator createBearingAnimator(double currentBearing, double targetBearing) { + ValueAnimator bearingAnimator = ValueAnimator.ofFloat((float) currentBearing, (float) targetBearing); bearingAnimator.setDuration((long) (1000 * ANIMATION_DELAY_FACTOR)); bearingAnimator.setStartDelay((long) (1000 * ANIMATION_DELAY_FACTOR)); bearingAnimator.setInterpolator(new FastOutLinearInInterpolator()); @@ -103,8 +169,8 @@ public class CameraAnimatorActivity extends AppCompatActivity implements OnMapRe return bearingAnimator; } - private Animator createTiltAnimator(double currentTilt) { - ValueAnimator tiltAnimator = ValueAnimator.ofFloat((float) currentTilt, 60); + private Animator createTiltAnimator(double currentTilt, double targetTilt) { + ValueAnimator tiltAnimator = ValueAnimator.ofFloat((float) currentTilt, (float) targetTilt); tiltAnimator.setDuration((long) (1000 * ANIMATION_DELAY_FACTOR)); tiltAnimator.setStartDelay((long) (1500 * ANIMATION_DELAY_FACTOR)); tiltAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @@ -116,20 +182,66 @@ public class CameraAnimatorActivity extends AppCompatActivity implements OnMapRe return tiltAnimator; } - private static class LatLngEvaluator implements TypeEvaluator<LatLng> { + // + // Interpolator examples + // - private final LatLng latLng = new LatLng(); + private Animator obtainExampleInterpolator(int menuItemId) { + return animators.get(menuItemId).build(); + } - @Override - public LatLng evaluate(float fraction, LatLng startValue, LatLng endValue) { - latLng.setLatitude(startValue.getLatitude() - + ((endValue.getLatitude() - startValue.getLatitude()) * fraction)); - latLng.setLongitude(startValue.getLongitude() - + ((endValue.getLongitude() - startValue.getLongitude()) * fraction)); - return latLng; + @Override + public boolean onCreateOptionsMenu(Menu menu) { + getMenuInflater().inflate(R.menu.menu_animator, menu); + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + if (mapboxMap == null) { + return false; } + findViewById(R.id.fab).setVisibility(View.GONE); + resetCameraPosition(); + playAnimation(item.getItemId()); + return super.onOptionsItemSelected(item); } + private void resetCameraPosition() { + mapboxMap.moveCamera(CameraUpdateFactory.newCameraPosition( + new CameraPosition.Builder() + .target(START_LAT_LNG) + .zoom(11) + .bearing(0) + .tilt(0) + .build() + )); + } + + private void playAnimation(int itemId) { + Animator animator = obtainExampleInterpolator(itemId); + if (animator != null) { + animator.start(); + } + } + + private Animator obtainExampleInterpolator(Interpolator interpolator, long duration) { + ValueAnimator zoomAnimator = ValueAnimator.ofFloat(11.0f, 16.0f); + zoomAnimator.setDuration((long) (duration * ANIMATION_DELAY_FACTOR)); + zoomAnimator.setInterpolator(interpolator); + zoomAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + mapboxMap.setZoom((Float) animation.getAnimatedValue()); + } + }); + return zoomAnimator; + } + + // + // MapView lifecycle + // + @Override protected void onStart() { super.onStart(); @@ -171,4 +283,25 @@ public class CameraAnimatorActivity extends AppCompatActivity implements OnMapRe super.onLowMemory(); mapView.onLowMemory(); } + + /** + * Helper class to evaluate LatLng objects with a ValueAnimator + */ + private static class LatLngEvaluator implements TypeEvaluator<LatLng> { + + private final LatLng latLng = new LatLng(); + + @Override + public LatLng evaluate(float fraction, LatLng startValue, LatLng endValue) { + latLng.setLatitude(startValue.getLatitude() + + ((endValue.getLatitude() - startValue.getLatitude()) * fraction)); + latLng.setLongitude(startValue.getLongitude() + + ((endValue.getLongitude() - startValue.getLongitude()) * fraction)); + return latLng; + } + } + + interface AnimatorBuilder { + Animator build(); + } } diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/CameraPositionActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/CameraPositionActivity.java index 2820bdbd53..e5c6a3f584 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/CameraPositionActivity.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/CameraPositionActivity.java @@ -1,6 +1,5 @@ package com.mapbox.mapboxsdk.testapp.activity.camera; -import android.annotation.SuppressLint; import android.content.Context; import android.content.DialogInterface; import android.os.Bundle; @@ -28,11 +27,13 @@ import timber.log.Timber; /** * Test activity showcasing how to listen to camera change events. */ -public class CameraPositionActivity extends AppCompatActivity implements OnMapReadyCallback { +public class CameraPositionActivity extends AppCompatActivity implements OnMapReadyCallback, View.OnClickListener, + MapboxMap.OnMapLongClickListener { private MapView mapView; private MapboxMap mapboxMap; private FloatingActionButton fab; + private boolean logCameraChanges; @Override protected void onCreate(Bundle savedInstanceState) { @@ -47,96 +48,48 @@ public class CameraPositionActivity extends AppCompatActivity implements OnMapRe @Override public void onMapReady(@NonNull final MapboxMap map) { mapboxMap = map; - - mapboxMap.setOnCameraIdleListener(new MapboxMap.OnCameraIdleListener() { - @Override - public void onCameraIdle() { - Timber.e("OnCameraIdle"); - fab.setColorFilter(ContextCompat.getColor(CameraPositionActivity.this, android.R.color.holo_green_dark)); - } - }); - - mapboxMap.setOnCameraMoveCancelListener(new MapboxMap.OnCameraMoveCanceledListener() { - @Override - public void onCameraMoveCanceled() { - Timber.e("OnCameraMoveCanceled"); - } - }); - - mapboxMap.setOnCameraMoveListener(new MapboxMap.OnCameraMoveListener() { - @Override - public void onCameraMove() { - Timber.e("OnCameraMove"); - fab.setColorFilter(ContextCompat.getColor(CameraPositionActivity.this, android.R.color.holo_orange_dark)); - } - }); - - mapboxMap.setOnCameraMoveStartedListener(new MapboxMap.OnCameraMoveStartedListener() { - - private final String[] REASONS = {"REASON_API_GESTURE", "REASON_DEVELOPER_ANIMATION", "REASON_API_ANIMATION"}; - - @Override - public void onCameraMoveStarted(int reason) { - // reason ranges from 1 <-> 3 - fab.setColorFilter(ContextCompat.getColor(CameraPositionActivity.this, android.R.color.holo_red_dark)); - Timber.e("OnCameraMoveStarted: %s", REASONS[reason - 1]); - } - }); + toggleLogCameraChanges(); // add a listener to FAB fab = (FloatingActionButton) findViewById(R.id.fab); fab.setColorFilter(ContextCompat.getColor(CameraPositionActivity.this, R.color.primary)); - fab.setOnClickListener(new View.OnClickListener() { - @SuppressLint("InflateParams") - @Override - public void onClick(View view) { - Context context = view.getContext(); - final View dialogContent = LayoutInflater.from(context).inflate(R.layout.dialog_camera_position, null); - AlertDialog.Builder builder = new AlertDialog.Builder( - context, com.mapbox.mapboxsdk.R.style.mapbox_AlertDialogStyle); - builder.setTitle(R.string.dialog_camera_position); - builder.setView(onInflateDialogContent(dialogContent)); - builder.setPositiveButton("Animate", new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - double latitude = Double.parseDouble( - ((TextView) dialogContent.findViewById(R.id.value_lat)).getText().toString()); - double longitude = Double.parseDouble( - ((TextView) dialogContent.findViewById(R.id.value_lon)).getText().toString()); - double zoom = Double.parseDouble( - ((TextView) dialogContent.findViewById(R.id.value_zoom)).getText().toString()); - double bearing = Double.parseDouble( - ((TextView) dialogContent.findViewById(R.id.value_bearing)).getText().toString()); - double tilt = Double.parseDouble( - ((TextView) dialogContent.findViewById(R.id.value_tilt)).getText().toString()); - - CameraPosition cameraPosition = new CameraPosition.Builder() - .target(new LatLng(latitude, longitude)) - .zoom(zoom) - .bearing(bearing) - .tilt(tilt) - .build(); - - mapboxMap.animateCamera(CameraUpdateFactory.newCameraPosition(cameraPosition), 5000, - new MapboxMap.CancelableCallback() { - @Override - public void onCancel() { - Timber.v("OnCancel called"); - } - - @Override - public void onFinish() { - Timber.v("OnFinish called"); - } - }); - Timber.v(cameraPosition.toString()); - } - }); - builder.setNegativeButton("Cancel", null); - builder.setCancelable(false); - builder.show(); - } - }); + fab.setOnClickListener(this); + + // listen to long click events to toggle logging camera changes + mapboxMap.setOnMapLongClickListener(this); + } + + @Override + public void onMapLongClick(@NonNull LatLng point) { + toggleLogCameraChanges(); + } + + @Override + public void onClick(View view) { + Context context = view.getContext(); + final View dialogContent = LayoutInflater.from(context).inflate(R.layout.dialog_camera_position, null); + AlertDialog.Builder builder = new AlertDialog.Builder(context); + builder.setTitle(R.string.dialog_camera_position); + builder.setView(onInflateDialogContent(dialogContent)); + builder.setPositiveButton("Animate", new DialogClickListener(mapboxMap, dialogContent)); + builder.setNegativeButton("Cancel", null); + builder.setCancelable(false); + builder.show(); + } + + private void toggleLogCameraChanges() { + logCameraChanges = !logCameraChanges; + if (logCameraChanges) { + mapboxMap.addOnCameraIdleListener(idleListener); + mapboxMap.addOnCameraMoveCancelListener(moveCanceledListener); + mapboxMap.addOnCameraMoveListener(moveListener); + mapboxMap.addOnCameraMoveStartedListener(moveStartedListener); + } else { + mapboxMap.removeOnCameraIdleListener(idleListener); + mapboxMap.removeOnCameraMoveCancelListener(moveCanceledListener); + mapboxMap.removeOnCameraMoveListener(moveListener); + mapboxMap.removeOnCameraMoveStartedListener(moveStartedListener); + } } @Override @@ -193,6 +146,42 @@ public class CameraPositionActivity extends AppCompatActivity implements OnMapRe seekBar.setProgress(defaultValue); } + private MapboxMap.OnCameraIdleListener idleListener = new MapboxMap.OnCameraIdleListener() { + @Override + public void onCameraIdle() { + Timber.e("OnCameraIdle"); + fab.setColorFilter(ContextCompat.getColor(CameraPositionActivity.this, android.R.color.holo_green_dark)); + } + }; + + private MapboxMap.OnCameraMoveListener moveListener = new MapboxMap.OnCameraMoveListener() { + @Override + public void onCameraMove() { + Timber.e("OnCameraMove"); + fab.setColorFilter(ContextCompat.getColor(CameraPositionActivity.this, android.R.color.holo_orange_dark)); + } + }; + + private MapboxMap.OnCameraMoveCanceledListener moveCanceledListener = new MapboxMap.OnCameraMoveCanceledListener() { + @Override + public void onCameraMoveCanceled() { + Timber.e("OnCameraMoveCanceled"); + + } + }; + + private MapboxMap.OnCameraMoveStartedListener moveStartedListener = new MapboxMap.OnCameraMoveStartedListener() { + + private final String[] REASONS = {"REASON_API_GESTURE", "REASON_DEVELOPER_ANIMATION", "REASON_API_ANIMATION"}; + + @Override + public void onCameraMoveStarted(int reason) { + // reason ranges from 1 <-> 3 + fab.setColorFilter(ContextCompat.getColor(CameraPositionActivity.this, android.R.color.holo_red_dark)); + Timber.e("OnCameraMoveStarted: %s", REASONS[reason - 1]); + } + }; + private class ValueChangeListener implements SeekBar.OnSeekBarChangeListener { protected TextView textView; @@ -224,4 +213,50 @@ public class CameraPositionActivity extends AppCompatActivity implements OnMapRe super.onProgressChanged(seekBar, progress - 180, fromUser); } } + + private static class DialogClickListener implements DialogInterface.OnClickListener { + + private MapboxMap mapboxMap; + private View dialogContent; + + public DialogClickListener(MapboxMap mapboxMap, View view) { + this.mapboxMap = mapboxMap; + this.dialogContent = view; + } + + @Override + public void onClick(DialogInterface dialog, int which) { + double latitude = Double.parseDouble( + ((TextView) dialogContent.findViewById(R.id.value_lat)).getText().toString()); + double longitude = Double.parseDouble( + ((TextView) dialogContent.findViewById(R.id.value_lon)).getText().toString()); + double zoom = Double.parseDouble( + ((TextView) dialogContent.findViewById(R.id.value_zoom)).getText().toString()); + double bearing = Double.parseDouble( + ((TextView) dialogContent.findViewById(R.id.value_bearing)).getText().toString()); + double tilt = Double.parseDouble( + ((TextView) dialogContent.findViewById(R.id.value_tilt)).getText().toString()); + + CameraPosition cameraPosition = new CameraPosition.Builder() + .target(new LatLng(latitude, longitude)) + .zoom(zoom) + .bearing(bearing) + .tilt(tilt) + .build(); + + mapboxMap.animateCamera(CameraUpdateFactory.newCameraPosition(cameraPosition), 5000, + new MapboxMap.CancelableCallback() { + @Override + public void onCancel() { + Timber.v("OnCancel called"); + } + + @Override + public void onFinish() { + Timber.v("OnFinish called"); + } + }); + Timber.v(cameraPosition.toString()); + } + } } diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/OfflineActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/OfflineActivity.java index 5bffd4d930..3a59e0628d 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/OfflineActivity.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/OfflineActivity.java @@ -264,6 +264,7 @@ public class OfflineActivity extends AppCompatActivity if (status.isComplete()) { // Download complete endProgress("Region downloaded successfully."); + offlineRegion.setDownloadState(OfflineRegion.STATE_INACTIVE); offlineRegion.setObserver(null); return; } else if (status.isRequiredResourceCountPrecise()) { @@ -281,11 +282,13 @@ public class OfflineActivity extends AppCompatActivity @Override public void onError(OfflineRegionError error) { Timber.e("onError: %s, %s", error.getReason(), error.getMessage()); + offlineRegion.setDownloadState(OfflineRegion.STATE_INACTIVE); } @Override public void mapboxTileCountLimitExceeded(long limit) { Timber.e("Mapbox tile count limit exceeded: %s", limit); + offlineRegion.setDownloadState(OfflineRegion.STATE_INACTIVE); } }); diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/SymbolGeneratorActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/SymbolGeneratorActivity.java index 0eaccfef0c..6e9e45cfaa 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/SymbolGeneratorActivity.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/SymbolGeneratorActivity.java @@ -1,13 +1,14 @@ package com.mapbox.mapboxsdk.testapp.activity.style; +import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; -import android.support.v7.app.AppCompatActivity; import android.graphics.Color; import android.graphics.PointF; +import android.os.AsyncTask; import android.os.Bundle; import android.support.annotation.NonNull; - +import android.support.v7.app.AppCompatActivity; import android.view.Menu; import android.view.MenuItem; import android.view.View; @@ -32,7 +33,7 @@ import com.mapbox.services.commons.geojson.custom.PositionDeserializer; import com.mapbox.services.commons.models.Position; import java.io.IOException; - +import java.util.HashMap; import java.util.List; import timber.log.Timber; @@ -64,49 +65,10 @@ public class SymbolGeneratorActivity extends AppCompatActivity implements OnMapR } @Override - public void onMapReady(MapboxMap map) { + public void onMapReady(final MapboxMap map) { mapboxMap = map; - try { - // read local geojson from raw folder - String tinyCountriesJson = ResourceUtils.readRawResource(this, R.raw.tiny_countries); - - // convert geojson to a model - FeatureCollection featureCollection = new GsonBuilder() - .registerTypeAdapter(Geometry.class, new GeometryDeserializer()) - .registerTypeAdapter(Position.class, new PositionDeserializer()) - .create().fromJson(tinyCountriesJson, FeatureCollection.class); - - // add a geojson to the map - Source source = new GeoJsonSource(SOURCE_ID, featureCollection); - mapboxMap.addSource(source); - - // for each feature add a symbolLayer - for (Feature feature : featureCollection.getFeatures()) { - String countryName = feature.getStringProperty(FEATURE_ID); - - // create View - TextView textView = new TextView(this); - textView.setBackgroundColor(getResources().getColor(R.color.blueAccent)); - textView.setPadding(10, 5, 10, 5); - textView.setTextColor(Color.WHITE); - textView.setText(countryName); - - // create bitmap from view - mapboxMap.addImage(countryName, SymbolGenerator.generate(textView)); - } - - // create layer use - mapboxMap.addLayer(new SymbolLayer(LAYER_ID, SOURCE_ID) - .withProperties( - iconImage("{" + FEATURE_ID + "}"), // { } is a token notation - iconAllowOverlap(false) - ) - ); - - addSymbolClickListener(); - } catch (IOException exception) { - Timber.e(exception); - } + addSymbolClickListener(); + new LoadDataTask(map, SymbolGeneratorActivity.this).execute(); } private void addSymbolClickListener() { @@ -213,4 +175,91 @@ public class SymbolGeneratorActivity extends AppCompatActivity implements OnMapR return bitmap; } } -} + + private static class LoadDataTask extends AsyncTask<Void, Void, FeatureCollection> { + + private final MapboxMap mapboxMap; + private final Context context; + + LoadDataTask(MapboxMap mapboxMap, Context context) { + this.mapboxMap = mapboxMap; + this.context = context; + } + + @Override + protected FeatureCollection doInBackground(Void... params) { + try { + // read local geojson from raw folder + String tinyCountriesJson = ResourceUtils.readRawResource(context, R.raw.tiny_countries); + + // convert geojson to a model + FeatureCollection featureCollection = new GsonBuilder() + .registerTypeAdapter(Geometry.class, new GeometryDeserializer()) + .registerTypeAdapter(Position.class, new PositionDeserializer()) + .create().fromJson(tinyCountriesJson, FeatureCollection.class); + + return featureCollection; + } catch (IOException exception) { + return null; + } + } + + + @Override + protected void onPostExecute(FeatureCollection featureCollection) { + super.onPostExecute(featureCollection); + if (featureCollection == null) { + return; + } + + // add a geojson to the map + Source source = new GeoJsonSource(SOURCE_ID, featureCollection); + mapboxMap.addSource(source); + + // create layer use + mapboxMap.addLayer(new SymbolLayer(LAYER_ID, SOURCE_ID) + .withProperties( + iconImage("{" + FEATURE_ID + "}"), // { } is a token notation + iconAllowOverlap(false) + ) + ); + + new GenerateSymbolTask(mapboxMap, context).execute(featureCollection); + } + } + + private static class GenerateSymbolTask extends AsyncTask<FeatureCollection, Void, HashMap<String, Bitmap>> { + + private MapboxMap mapboxMap; + private Context context; + + GenerateSymbolTask(MapboxMap mapboxMap, Context context) { + this.mapboxMap = mapboxMap; + this.context = context; + } + + @SuppressWarnings("WrongThread") + @Override + protected HashMap<String, Bitmap> doInBackground(FeatureCollection... params) { + FeatureCollection featureCollection = params[0]; + + HashMap<String, Bitmap> imagesMap = new HashMap<>(); + for (Feature feature : featureCollection.getFeatures()) { + String countryName = feature.getStringProperty(FEATURE_ID); + TextView textView = new TextView(context); + textView.setBackgroundColor(context.getResources().getColor(R.color.blueAccent)); + textView.setPadding(10, 5, 10, 5); + textView.setTextColor(Color.WHITE); + textView.setText(countryName); + imagesMap.put(countryName, SymbolGenerator.generate(textView)); + } + return imagesMap; + } + + @Override + protected void onPostExecute(HashMap<String, Bitmap> bitmapHashMap) { + super.onPostExecute(bitmapHashMap); + mapboxMap.addImages(bitmapHashMap); + } + } +}
\ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/ZoomFunctionSymbolLayerActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/ZoomFunctionSymbolLayerActivity.java index 95c3929c1d..abfd7ae529 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/ZoomFunctionSymbolLayerActivity.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/ZoomFunctionSymbolLayerActivity.java @@ -12,6 +12,7 @@ import com.mapbox.mapboxsdk.geometry.LatLng; import com.mapbox.mapboxsdk.maps.MapView; import com.mapbox.mapboxsdk.maps.MapboxMap; import com.mapbox.mapboxsdk.maps.OnMapReadyCallback; +import com.mapbox.mapboxsdk.style.layers.Property; import com.mapbox.mapboxsdk.style.layers.SymbolLayer; import com.mapbox.mapboxsdk.style.sources.GeoJsonSource; import com.mapbox.mapboxsdk.testapp.R; @@ -32,6 +33,7 @@ import static com.mapbox.mapboxsdk.style.functions.stops.Stops.interval; import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconAllowOverlap; import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconImage; import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconSize; +import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.visibility; /** * Test activity showcasing changing the icon with a zoom function and adding selection state to a SymbolLayer. @@ -49,9 +51,11 @@ public class ZoomFunctionSymbolLayerActivity extends AppCompatActivity { private MapView mapView; private MapboxMap mapboxMap; private GeoJsonSource source; + private SymbolLayer layer; private boolean isInitialPosition = true; private boolean isSelected = false; + private boolean isShowingSymbolLayer = true; @Override public void onCreate(Bundle savedInstanceState) { @@ -81,6 +85,13 @@ public class ZoomFunctionSymbolLayerActivity extends AppCompatActivity { } } + private void toggleSymbolLayerVisibility() { + layer.setProperties( + visibility(isShowingSymbolLayer ? Property.NONE : Property.VISIBLE) + ); + isShowingSymbolLayer = !isShowingSymbolLayer; + } + private FeatureCollection createFeatureCollection() { Position position = isInitialPosition ? Position.fromCoordinates(-74.01618140, 40.701745) @@ -95,7 +106,7 @@ public class ZoomFunctionSymbolLayerActivity extends AppCompatActivity { } private void addLayer() { - SymbolLayer layer = new SymbolLayer(LAYER_ID, SOURCE_ID); + layer = new SymbolLayer(LAYER_ID, SOURCE_ID); layer.setProperties( iconImage( zoom( @@ -145,9 +156,13 @@ public class ZoomFunctionSymbolLayerActivity extends AppCompatActivity { @Override public boolean onOptionsItemSelected(MenuItem item) { - if (mapboxMap != null && item.getItemId() == R.id.menu_action_change_location) { - isInitialPosition = !isInitialPosition; - updateSource(); + if (mapboxMap != null) { + if (item.getItemId() == R.id.menu_action_change_location) { + isInitialPosition = !isInitialPosition; + updateSource(); + } else if (item.getItemId() == R.id.menu_action_toggle_source) { + toggleSymbolLayerVisibility(); + } } return super.onOptionsItemSelected(item); } diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_camera_animator.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_camera_animator.xml index d4933bfb9a..cb14aab91f 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_camera_animator.xml +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_camera_animator.xml @@ -10,8 +10,8 @@ android:id="@id/mapView" android:layout_width="match_parent" android:layout_height="match_parent" - app:mapbox_cameraTargetLat="37.774913" - app:mapbox_cameraTargetLng="-122.419368" + app:mapbox_cameraTargetLat="37.787947" + app:mapbox_cameraTargetLng="-122.407432" app:mapbox_cameraZoom="11" app:mapbox_styleUrl="@string/mapbox_style_mapbox_streets"/> diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_animator.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_animator.xml new file mode 100644 index 0000000000..db5a62d2cb --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_animator.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<menu xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto"> + <item + android:id="@+id/menu_action_accelerate_decelerate_interpolator" + android:title="@string/menuitem_title_accelerate_decelerate" + app:showAsAction="never"/> + <item + android:id="@+id/menu_action_bounce_interpolator" + android:title="@string/menuitem_title_bounce" + app:showAsAction="never"/> + <item + android:id="@+id/menu_action_anticipate_overshoot_interpolator" + android:title="@string/menuitem_title_anticipate_overshoot" + app:showAsAction="never"/> + <item + android:id="@+id/menu_action_path_interpolator" + android:title="@string/menuitem_title_path" + app:showAsAction="never"/> +</menu> diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_symbols.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_symbols.xml index 3e5c8ab14c..7f3c44262d 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_symbols.xml +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_symbols.xml @@ -5,4 +5,8 @@ android:id="@+id/menu_action_change_location" android:title="@string/menuitem_change_location" app:showAsAction="never"/> + <item + android:id="@+id/menu_action_toggle_source" + android:title="@string/menuitem_toggle_symbol_layer_visibility" + app:showAsAction="never"/> </menu> diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/actions.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/actions.xml index 4ca19def71..5c0828ab74 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/actions.xml +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/actions.xml @@ -12,6 +12,11 @@ <string name="menuitem_title_change_location_source_null">Reset location source to null</string> <string name="menuitem_change_icon_overlap">Toggle icon overlap</string> <string name="menuitem_change_location">Change location</string> + <string name="menuitem_title_accelerate_decelerate">Accelerate/Decelerate interpolator</string> + <string name="menuitem_title_bounce">Bounce interpolator</string> + <string name="menuitem_title_anticipate_overshoot">Anticipate/Overshoot interpolator</string> + <string name="menuitem_title_path">PathInterpolator interpolator</string> + <string name="menuitem_toggle_symbol_layer_visibility">Toggle Symbol Layer Visibility</string> <string name="button_camera_move">Move</string> <string name="button_camera_ease">Ease</string> <string name="button_camera_animate">Animate</string> |