diff options
author | Łukasz Paczos <lukas.paczos@gmail.com> | 2018-05-14 18:52:24 +0200 |
---|---|---|
committer | Łukasz Paczos <lukasz.paczos@mapbox.com> | 2018-05-22 20:27:37 +0200 |
commit | 90beb3820d272de5a77b3fe9995502ab8b464159 (patch) | |
tree | 0db4916cb06a47dd6a9464f5e535426daa792af4 | |
parent | 52855f4c04358e38b12219426b65373ee86a0e6b (diff) | |
download | qtlocation-mapboxgl-90beb3820d272de5a77b3fe9995502ab8b464159.tar.gz |
[android] - cleaned up UiSettings, removed View references
11 files changed, 503 insertions, 355 deletions
diff --git a/platform/android/MapboxGLAndroidSDK/build.gradle b/platform/android/MapboxGLAndroidSDK/build.gradle index dc3de5e059..846170ae29 100644 --- a/platform/android/MapboxGLAndroidSDK/build.gradle +++ b/platform/android/MapboxGLAndroidSDK/build.gradle @@ -17,6 +17,7 @@ dependencies { testImplementation dependenciesList.junit testImplementation dependenciesList.mockito testImplementation dependenciesList.robolectric + testImplementation dependenciesList.archCoreTesting } android { diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MapboxConstants.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MapboxConstants.java index 640c70282c..d8f1bb372c 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MapboxConstants.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MapboxConstants.java @@ -120,40 +120,7 @@ public class MapboxConstants { // Save instance state keys public static final String STATE_HAS_SAVED_STATE = "mapbox_savedState"; public static final String STATE_CAMERA_POSITION = "mapbox_cameraPosition"; - public static final String STATE_ZOOM_ENABLED = "mapbox_zoomEnabled"; - public static final String STATE_SCROLL_ENABLED = "mapbox_scrollEnabled"; - public static final String STATE_ROTATE_ENABLED = "mapbox_rotateEnabled"; - public static final String STATE_TILT_ENABLED = "mapbox_tiltEnabled"; - public static final String STATE_ZOOM_CONTROLS_ENABLED = "mapbox_zoomControlsEnabled"; - public static final String STATE_DOUBLE_TAP_ENABLED = "mapbox_doubleTapEnabled"; public static final String STATE_DEBUG_ACTIVE = "mapbox_debugActive"; public static final String STATE_STYLE_URL = "mapbox_styleUrl"; - public static final String STATE_COMPASS_ENABLED = "mapbox_compassEnabled"; - public static final String STATE_COMPASS_GRAVITY = "mapbox_compassGravity"; - public static final String STATE_COMPASS_MARGIN_LEFT = "mapbox_compassMarginLeft"; - public static final String STATE_COMPASS_MARGIN_TOP = "mapbox_compassMarginTop"; - public static final String STATE_COMPASS_MARGIN_RIGHT = "mapbox_compassMarginRight"; - public static final String STATE_COMPASS_MARGIN_BOTTOM = "mapbox_compassMarginBottom"; - public static final String STATE_COMPASS_FADE_WHEN_FACING_NORTH = "mapbox_compassFade"; - public static final String STATE_COMPASS_IMAGE_BITMAP = "mapbox_compassImage"; - public static final String STATE_LOGO_GRAVITY = "mapbox_logoGravity"; - public static final String STATE_LOGO_MARGIN_LEFT = "mapbox_logoMarginLeft"; - public static final String STATE_LOGO_MARGIN_TOP = "mapbox_logoMarginTop"; - public static final String STATE_LOGO_MARGIN_RIGHT = "mapbox_logoMarginRight"; - public static final String STATE_LOGO_MARGIN_BOTTOM = "mapbox_logoMarginBottom"; - public static final String STATE_LOGO_ENABLED = "mapbox_logoEnabled"; - public static final String STATE_ATTRIBUTION_GRAVITY = "mapbox_attrGravity"; - public static final String STATE_ATTRIBUTION_MARGIN_LEFT = "mapbox_attrMarginLeft"; - public static final String STATE_ATTRIBUTION_MARGIN_TOP = "mapbox_attrMarginTop"; - public static final String STATE_ATTRIBUTION_MARGIN_RIGHT = "mapbox_attrMarginRight"; - public static final String STATE_ATTRIBUTION_MARGIN_BOTTOM = "mapbox_atrrMarginBottom"; - public static final String STATE_ATTRIBUTION_ENABLED = "mapbox_atrrEnabled"; - public static final String STATE_DESELECT_MARKER_ON_TAP = "mapbox_deselectMarkerOnTap"; - public static final String STATE_USER_FOCAL_POINT = "mapbox_userFocalPoint"; - public static final String STATE_SCALE_ANIMATION_ENABLED = "mapbox_scaleAnimationEnabled"; - public static final String STATE_ROTATE_ANIMATION_ENABLED = "mapbox_rotateAnimationEnabled"; - public static final String STATE_FLING_ANIMATION_ENABLED = "mapbox_flingAnimationEnabled"; - public static final String STATE_INCREASE_ROTATE_THRESHOLD = "mapbox_increaseRotateThreshold"; - public static final String STATE_INCREASE_SCALE_THRESHOLD = "mapbox_increaseScaleThreshold"; } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapGestureDetector.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapGestureDetector.java index de9b4fdbc2..0075e0e499 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapGestureDetector.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapGestureDetector.java @@ -82,6 +82,7 @@ final class MapGestureDetector { * User-set focal point. */ private PointF focalPoint; + private float screenDensity; private AndroidGesturesManager gesturesManager; private boolean executeDoubleTap; @@ -106,6 +107,8 @@ final class MapGestureDetector { // Checking for context != null for testing purposes if (context != null) { + screenDensity = context.getResources().getDisplayMetrics().density; + // Initialize gestures manager AndroidGesturesManager androidGesturesManager = new AndroidGesturesManager(context); initializeGesturesManager(androidGesturesManager, true); @@ -401,8 +404,6 @@ final class MapGestureDetector { return false; } - float screenDensity = uiSettings.getPixelRatio(); - // calculate velocity vector for xy dimensions, independent from screen size double velocityXY = Math.hypot(velocityX / screenDensity, velocityY / screenDensity); if (velocityXY < MapboxConstants.VELOCITY_THRESHOLD_IGNORE_FLING) { diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java index 468c2fd961..6a2f292ad7 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java @@ -43,6 +43,7 @@ import com.mapbox.mapboxsdk.maps.renderer.MapRenderer; import com.mapbox.mapboxsdk.maps.renderer.glsurfaceview.GLSurfaceViewMapRenderer; import com.mapbox.mapboxsdk.maps.renderer.textureview.TextureViewMapRenderer; import com.mapbox.mapboxsdk.maps.widgets.CompassView; +import com.mapbox.mapboxsdk.maps.widgets.WidgetUpdater; import com.mapbox.mapboxsdk.net.ConnectivityReceiver; import com.mapbox.mapboxsdk.offline.OfflineRegionDefinition; import com.mapbox.mapboxsdk.offline.OfflineTilePyramidRegionDefinition; @@ -88,10 +89,13 @@ public class MapView extends FrameLayout implements NativeMapView.ViewCallback { private boolean destroyed; private boolean hasSurface; + private UiSettings uiSettings; private CompassView compassView; private PointF focalPoint; private ImageView attrView; + private AttributionClickListener attributionClickListener; private ImageView logoView; + private WidgetUpdater widgetUpdater; private MapGestureDetector mapGestureDetector; private MapKeyListener mapKeyListener; @@ -137,6 +141,9 @@ public class MapView extends FrameLayout implements NativeMapView.ViewCallback { attrView = (ImageView) view.findViewById(R.id.attributionView); logoView = (ImageView) view.findViewById(R.id.logoView); + // create widget updater + widgetUpdater = new WidgetUpdater(context, compassView, attrView, logoView); + // add accessibility support setContentDescription(context.getString(R.string.mapbox_mapActionDescription)); setWillNotDraw(false); @@ -157,8 +164,8 @@ public class MapView extends FrameLayout implements NativeMapView.ViewCallback { // setup components for MapboxMap creation Projection proj = new Projection(nativeMapView); - UiSettings uiSettings = ViewModelProviders.of((FragmentActivity) context).get(UiSettings.class); - uiSettings.initialiseViews(proj, compassView, attrView, logoView); + uiSettings = ViewModelProviders.of((FragmentActivity) context).get(UiSettings.class); + uiSettings.initialiseProjection(proj); uiSettings.getFocalPointObservable().observe((LifecycleOwner) context, point -> this.focalPoint = point); LongSparseArray<Annotation> annotationsArray = new LongSparseArray<>(); @@ -193,7 +200,8 @@ public class MapView extends FrameLayout implements NativeMapView.ViewCallback { compassView.injectCompassAnimationListener(createCompassAnimationListener(cameraChangeDispatcher)); compassView.setOnClickListener(createCompassClickListener(cameraChangeDispatcher)); // inject widgets with MapboxMap - attrView.setOnClickListener(new AttributionClickListener(context, mapboxMap)); + attributionClickListener = new AttributionClickListener(context, mapboxMap); + attrView.setOnClickListener(attributionClickListener); // Ensure this view is interactable setClickable(true); @@ -410,6 +418,7 @@ public class MapView extends FrameLayout implements NativeMapView.ViewCallback { destroyed = true; onMapChangedListeners.clear(); mapCallback.clearOnMapReadyCallbacks(); + uiSettings.onMapDestroy(); if (nativeMapView != null && hasSurface) { // null when destroying an activity programmatically mapbox-navigation-android/issues/503 @@ -655,6 +664,30 @@ public class MapView extends FrameLayout implements NativeMapView.ViewCallback { } } + /** + * Set a custom attribution dialog manager. + * <p> + * Set to null to reset to default behaviour. + * <p> + * You need to reset your custom manager with every {@link MapView} re-creation. + * + * @param attributionDialogManager the manager class used for showing attribution + */ + @UiThread + public void setAttributionDialogManager(@Nullable AttributionDialogManager attributionDialogManager) { + attributionClickListener.setCurrentDialogManager(attributionDialogManager); + } + + /** + * Get the current attribution dialog manager. + * + * @return the active manager class used for showing attribution + */ + @NonNull + public AttributionDialogManager getAttributionDialogManager() { + return attributionClickListener.getAttributionDialogManager(); + } + private boolean isMapInitialized() { return nativeMapView != null; } @@ -1164,20 +1197,31 @@ public class MapView extends FrameLayout implements NativeMapView.ViewCallback { private static class AttributionClickListener implements OnClickListener { private final AttributionDialogManager defaultDialogManager; - private UiSettings uiSettings; + private AttributionDialogManager currentDialogManager; private AttributionClickListener(Context context, MapboxMap mapboxMap) { this.defaultDialogManager = new AttributionDialogManager(context, mapboxMap); - this.uiSettings = mapboxMap.getUiSettings(); + currentDialogManager = defaultDialogManager; + + UiSettings uiSettings = ViewModelProviders.of((FragmentActivity) context).get(UiSettings.class); + uiSettings.getAttributionDialogManagerObservable().observe( + (LifecycleOwner) context, this::setCurrentDialogManager); } @Override public void onClick(View v) { - AttributionDialogManager customDialogManager = uiSettings.getAttributionDialogManager(); - if (customDialogManager != null) { - uiSettings.getAttributionDialogManager().onClick(v); + currentDialogManager.onClick(v); + } + + private AttributionDialogManager getAttributionDialogManager() { + return currentDialogManager == null ? defaultDialogManager : currentDialogManager; + } + + private void setCurrentDialogManager(AttributionDialogManager manager) { + if (manager == null) { + currentDialogManager = defaultDialogManager; } else { - defaultDialogManager.onClick(v); + currentDialogManager = manager; } } } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java index c58f4e871d..2474bc45fc 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java @@ -114,7 +114,7 @@ public final class MapboxMap { */ void onStop() { } - +// TODO: 15.05.18 cleanup mapbx map save state /** * Called when the hosting Activity/Fragment is going to be destroyed and map state needs to be saved. * @@ -124,7 +124,6 @@ public final class MapboxMap { outState.putParcelable(MapboxConstants.STATE_CAMERA_POSITION, transform.getCameraPosition()); outState.putBoolean(MapboxConstants.STATE_DEBUG_ACTIVE, nativeMapView.getDebug()); outState.putString(MapboxConstants.STATE_STYLE_URL, nativeMapView.getStyleUrl()); - uiSettings.onSaveInstanceState(outState); } /** @@ -135,8 +134,6 @@ public final class MapboxMap { void onRestoreInstanceState(@NonNull Bundle savedInstanceState) { final CameraPosition cameraPosition = savedInstanceState.getParcelable(MapboxConstants.STATE_CAMERA_POSITION); - uiSettings.onRestoreInstanceState(savedInstanceState); - if (cameraPosition != null) { moveCamera(CameraUpdateFactory.newCameraPosition( new CameraPosition.Builder(cameraPosition).build()) @@ -184,7 +181,7 @@ public final class MapboxMap { void onUpdateFullyRendered() { CameraPosition cameraPosition = transform.invalidateCameraPosition(); if (cameraPosition != null) { - uiSettings.update(cameraPosition); + uiSettings.updateCompass(cameraPosition); } } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UiSettings.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UiSettings.java index 830ce80d4c..ea0665d372 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UiSettings.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UiSettings.java @@ -5,57 +5,54 @@ import android.arch.lifecycle.ViewModel; import android.content.Context; import android.content.pm.PackageManager; import android.content.res.Resources; -import android.graphics.Color; import android.graphics.PointF; import android.graphics.drawable.Drawable; -import android.os.Build; -import android.os.Bundle; import android.support.annotation.ColorInt; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.annotation.UiThread; -import android.support.v4.content.ContextCompat; import android.support.v4.content.res.ResourcesCompat; -import android.view.View; -import android.widget.FrameLayout; -import android.widget.ImageView; import com.mapbox.mapboxsdk.R; import com.mapbox.mapboxsdk.camera.CameraPosition; -import com.mapbox.mapboxsdk.constants.MapboxConstants; -import com.mapbox.mapboxsdk.maps.widgets.CompassView; -import com.mapbox.mapboxsdk.utils.BitmapUtils; import com.mapbox.mapboxsdk.utils.ColorUtils; /** * Settings for the user interface of a MapboxMap. To obtain this interface, call getUiSettings(). */ +@UiThread public final class UiSettings extends ViewModel { - - private Projection projection; // TODO: 14.05.18 clear projection during maps destroy? - - private CompassView compassView; - private ImageView attributionsView; - private View logoView; - private float pixelRatio; - private int[] compassMargins = new int[4]; - private final int[] logoMargins = new int[4]; - private final int[] attributionsMargins = new int[4]; - private AttributionDialogManager attributionDialogManager; - - + private Projection projection; + + // compass settings + private final MutableLiveData<Integer> compassGravity = new MutableLiveData<>(); + private final MutableLiveData<Drawable> compassImage = new MutableLiveData<>(); + private final MutableLiveData<Boolean> compassEnabled = new MutableLiveData<>(); + private final MutableLiveData<Boolean> compassFadeFacingNorth = new MutableLiveData<>(); + private final MutableLiveData<Integer[]> compassMargins = new MutableLiveData<>(); + private final MutableLiveData<Double> compassRotation = new MutableLiveData<>(); + + // attribution settings + private final MutableLiveData<Integer> attributionGravity = new MutableLiveData<>(); + private final MutableLiveData<Boolean> attributionEnabled = new MutableLiveData<>(); + private final MutableLiveData<Integer> attributionTintColor = new MutableLiveData<>(); + private final MutableLiveData<Integer[]> attributionMargins = new MutableLiveData<>(); + private final MutableLiveData<AttributionDialogManager> attributionDialogManager = new MutableLiveData<>(); + + // logo view + private final MutableLiveData<Integer> logoGravity = new MutableLiveData<>(); + private final MutableLiveData<Boolean> logoEnabled = new MutableLiveData<>(); + private final MutableLiveData<Integer[]> logoMargins = new MutableLiveData<>(); + + // gestures private boolean rotateGesturesEnabled = true; - private boolean tiltGesturesEnabled = true; - private boolean zoomGesturesEnabled = true; - private boolean scrollGesturesEnabled = true; + private boolean doubleTapGesturesEnabled = true; private boolean zoomControlsEnabled; - private boolean doubleTapGesturesEnabled = true; - private boolean scaleVelocityAnimationEnabled = true; private boolean rotateVelocityAnimationEnabled = true; private boolean flingVelocityAnimationEnabled = true; @@ -65,17 +62,10 @@ public final class UiSettings extends ViewModel { private boolean deselectMarkersOnTap = true; - private MutableLiveData<PointF> userProvidedFocalPoint; + private final MutableLiveData<PointF> userProvidedFocalPoint = new MutableLiveData<>(); - void initialiseViews(@NonNull Projection projection, @NonNull CompassView compassView, - @NonNull ImageView attributionsView, @NonNull View logoView) { + void initialiseProjection(@NonNull Projection projection) { this.projection = projection; - this.compassView = compassView; - this.attributionsView = attributionsView; - this.logoView = logoView; - if (logoView.getResources() != null) { - this.pixelRatio = logoView.getResources().getDisplayMetrics().density; - } } void initialiseOptions(@NonNull Context context, @NonNull MapboxMapOptions options) { @@ -87,27 +77,7 @@ public final class UiSettings extends ViewModel { initialiseZoomControl(context); } - void onSaveInstanceState(Bundle outState) { - saveGestures(outState); - saveCompass(outState); - saveLogo(outState); - saveAttribution(outState); - saveZoomControl(outState); - saveDeselectMarkersOnTap(outState); - saveFocalPoint(outState); - } - - void onRestoreInstanceState(@NonNull Bundle savedInstanceState) { - restoreGestures(savedInstanceState); - restoreCompass(savedInstanceState); - restoreLogo(savedInstanceState); - restoreAttribution(savedInstanceState); - restoreZoomControl(savedInstanceState); - restoreDeselectMarkersOnTap(savedInstanceState); - restoreFocalPoint(savedInstanceState); - } - - private void initialiseGestures(MapboxMapOptions options) { + void initialiseGestures(MapboxMapOptions options) { setZoomGesturesEnabled(options.getZoomGesturesEnabled()); setScrollGesturesEnabled(options.getScrollGesturesEnabled()); setRotateGesturesEnabled(options.getRotateGesturesEnabled()); @@ -116,76 +86,25 @@ public final class UiSettings extends ViewModel { setDoubleTapGesturesEnabled(options.getDoubleTapGesturesEnabled()); } - private void saveGestures(Bundle outState) { - outState.putBoolean(MapboxConstants.STATE_ZOOM_ENABLED, isZoomGesturesEnabled()); - outState.putBoolean(MapboxConstants.STATE_SCROLL_ENABLED, isScrollGesturesEnabled()); - outState.putBoolean(MapboxConstants.STATE_ROTATE_ENABLED, isRotateGesturesEnabled()); - outState.putBoolean(MapboxConstants.STATE_TILT_ENABLED, isTiltGesturesEnabled()); - outState.putBoolean(MapboxConstants.STATE_DOUBLE_TAP_ENABLED, isDoubleTapGesturesEnabled()); - outState.putBoolean(MapboxConstants.STATE_SCALE_ANIMATION_ENABLED, isScaleVelocityAnimationEnabled()); - outState.putBoolean(MapboxConstants.STATE_ROTATE_ANIMATION_ENABLED, isRotateVelocityAnimationEnabled()); - outState.putBoolean(MapboxConstants.STATE_FLING_ANIMATION_ENABLED, isFlingVelocityAnimationEnabled()); - outState.putBoolean(MapboxConstants.STATE_INCREASE_ROTATE_THRESHOLD, isIncreaseRotateThresholdWhenScaling()); - outState.putBoolean(MapboxConstants.STATE_INCREASE_SCALE_THRESHOLD, isIncreaseScaleThresholdWhenRotating()); - } - - private void restoreGestures(Bundle savedInstanceState) { - setZoomGesturesEnabled(savedInstanceState.getBoolean(MapboxConstants.STATE_ZOOM_ENABLED)); - setScrollGesturesEnabled(savedInstanceState.getBoolean(MapboxConstants.STATE_SCROLL_ENABLED)); - setRotateGesturesEnabled(savedInstanceState.getBoolean(MapboxConstants.STATE_ROTATE_ENABLED)); - setTiltGesturesEnabled(savedInstanceState.getBoolean(MapboxConstants.STATE_TILT_ENABLED)); - setDoubleTapGesturesEnabled(savedInstanceState.getBoolean(MapboxConstants.STATE_DOUBLE_TAP_ENABLED)); - setScaleVelocityAnimationEnabled(savedInstanceState.getBoolean(MapboxConstants.STATE_SCALE_ANIMATION_ENABLED)); - setRotateVelocityAnimationEnabled(savedInstanceState.getBoolean(MapboxConstants.STATE_ROTATE_ANIMATION_ENABLED)); - setFlingVelocityAnimationEnabled(savedInstanceState.getBoolean(MapboxConstants.STATE_FLING_ANIMATION_ENABLED)); - setIncreaseRotateThresholdWhenScaling( - savedInstanceState.getBoolean(MapboxConstants.STATE_INCREASE_ROTATE_THRESHOLD)); - setIncreaseScaleThresholdWhenRotating( - savedInstanceState.getBoolean(MapboxConstants.STATE_INCREASE_SCALE_THRESHOLD)); - } - - private void initialiseCompass(MapboxMapOptions options, Resources resources) { + void initialiseCompass(MapboxMapOptions options, Resources resources) { setCompassEnabled(options.getCompassEnabled()); setCompassGravity(options.getCompassGravity()); int[] compassMargins = options.getCompassMargins(); if (compassMargins != null) { setCompassMargins(compassMargins[0], compassMargins[1], compassMargins[2], compassMargins[3]); } else { - int tenDp = (int) resources.getDimension(R.dimen.mapbox_four_dp); - setCompassMargins(tenDp, tenDp, tenDp, tenDp); + int fourDP = (int) resources.getDimension(R.dimen.mapbox_four_dp); + setCompassMargins(fourDP, fourDP, fourDP, fourDP); } setCompassFadeFacingNorth(options.getCompassFadeFacingNorth()); if (options.getCompassImage() == null) { options.compassImage(ResourcesCompat.getDrawable(resources, R.drawable.mapbox_compass_icon, null)); } setCompassImage(options.getCompassImage()); + updateCompass(CameraPosition.DEFAULT); } - private void saveCompass(Bundle outState) { - outState.putBoolean(MapboxConstants.STATE_COMPASS_ENABLED, isCompassEnabled()); - outState.putInt(MapboxConstants.STATE_COMPASS_GRAVITY, getCompassGravity()); - outState.putInt(MapboxConstants.STATE_COMPASS_MARGIN_LEFT, getCompassMarginLeft()); - outState.putInt(MapboxConstants.STATE_COMPASS_MARGIN_TOP, getCompassMarginTop()); - outState.putInt(MapboxConstants.STATE_COMPASS_MARGIN_BOTTOM, getCompassMarginBottom()); - outState.putInt(MapboxConstants.STATE_COMPASS_MARGIN_RIGHT, getCompassMarginRight()); - outState.putBoolean(MapboxConstants.STATE_COMPASS_FADE_WHEN_FACING_NORTH, isCompassFadeWhenFacingNorth()); - outState.putByteArray(MapboxConstants.STATE_COMPASS_IMAGE_BITMAP, - BitmapUtils.getByteArrayFromDrawable(getCompassImage())); - } - - private void restoreCompass(Bundle savedInstanceState) { - setCompassEnabled(savedInstanceState.getBoolean(MapboxConstants.STATE_COMPASS_ENABLED)); - setCompassGravity(savedInstanceState.getInt(MapboxConstants.STATE_COMPASS_GRAVITY)); - setCompassMargins(savedInstanceState.getInt(MapboxConstants.STATE_COMPASS_MARGIN_LEFT), - savedInstanceState.getInt(MapboxConstants.STATE_COMPASS_MARGIN_TOP), - savedInstanceState.getInt(MapboxConstants.STATE_COMPASS_MARGIN_RIGHT), - savedInstanceState.getInt(MapboxConstants.STATE_COMPASS_MARGIN_BOTTOM)); - setCompassFadeFacingNorth(savedInstanceState.getBoolean(MapboxConstants.STATE_COMPASS_FADE_WHEN_FACING_NORTH)); - setCompassImage(BitmapUtils.getDrawableFromByteArray( - compassView.getContext(), savedInstanceState.getByteArray(MapboxConstants.STATE_COMPASS_IMAGE_BITMAP))); - } - - private void initialiseLogo(MapboxMapOptions options, Resources resources) { + void initialiseLogo(MapboxMapOptions options, Resources resources) { setLogoEnabled(options.getLogoEnabled()); setLogoGravity(options.getLogoGravity()); setLogoMargins(resources, options.getLogoMargins()); @@ -201,25 +120,7 @@ public final class UiSettings extends ViewModel { } } - private void saveLogo(Bundle outState) { - outState.putInt(MapboxConstants.STATE_LOGO_GRAVITY, getLogoGravity()); - outState.putInt(MapboxConstants.STATE_LOGO_MARGIN_LEFT, getLogoMarginLeft()); - outState.putInt(MapboxConstants.STATE_LOGO_MARGIN_TOP, getLogoMarginTop()); - outState.putInt(MapboxConstants.STATE_LOGO_MARGIN_RIGHT, getLogoMarginRight()); - outState.putInt(MapboxConstants.STATE_LOGO_MARGIN_BOTTOM, getLogoMarginBottom()); - outState.putBoolean(MapboxConstants.STATE_LOGO_ENABLED, isLogoEnabled()); - } - - private void restoreLogo(Bundle savedInstanceState) { - setLogoEnabled(savedInstanceState.getBoolean(MapboxConstants.STATE_LOGO_ENABLED)); - setLogoGravity(savedInstanceState.getInt(MapboxConstants.STATE_LOGO_GRAVITY)); - setLogoMargins(savedInstanceState.getInt(MapboxConstants.STATE_LOGO_MARGIN_LEFT), - savedInstanceState.getInt(MapboxConstants.STATE_LOGO_MARGIN_TOP), - savedInstanceState.getInt(MapboxConstants.STATE_LOGO_MARGIN_RIGHT), - savedInstanceState.getInt(MapboxConstants.STATE_LOGO_MARGIN_BOTTOM)); - } - - private void initialiseAttribution(Context context, MapboxMapOptions options) { + void initialiseAttribution(Context context, MapboxMapOptions options) { setAttributionEnabled(options.getAttributionEnabled()); setAttributionGravity(options.getAttributionGravity()); setAttributionMargins(context, options.getAttributionMargins()); @@ -241,38 +142,12 @@ public final class UiSettings extends ViewModel { } } - private void saveAttribution(Bundle outState) { - outState.putInt(MapboxConstants.STATE_ATTRIBUTION_GRAVITY, getAttributionGravity()); - outState.putInt(MapboxConstants.STATE_ATTRIBUTION_MARGIN_LEFT, getAttributionMarginLeft()); - outState.putInt(MapboxConstants.STATE_ATTRIBUTION_MARGIN_TOP, getAttributionMarginTop()); - outState.putInt(MapboxConstants.STATE_ATTRIBUTION_MARGIN_RIGHT, getAttributionMarginRight()); - outState.putInt(MapboxConstants.STATE_ATTRIBUTION_MARGIN_BOTTOM, getAttributionMarginBottom()); - outState.putBoolean(MapboxConstants.STATE_ATTRIBUTION_ENABLED, isAttributionEnabled()); - } - - private void restoreAttribution(Bundle savedInstanceState) { - setAttributionEnabled(savedInstanceState.getBoolean(MapboxConstants.STATE_ATTRIBUTION_ENABLED)); - setAttributionGravity(savedInstanceState.getInt(MapboxConstants.STATE_ATTRIBUTION_GRAVITY)); - setAttributionMargins(savedInstanceState.getInt(MapboxConstants.STATE_ATTRIBUTION_MARGIN_LEFT), - savedInstanceState.getInt(MapboxConstants.STATE_ATTRIBUTION_MARGIN_TOP), - savedInstanceState.getInt(MapboxConstants.STATE_ATTRIBUTION_MARGIN_RIGHT), - savedInstanceState.getInt(MapboxConstants.STATE_ATTRIBUTION_MARGIN_BOTTOM)); - } - - private void initialiseZoomControl(Context context) { + void initialiseZoomControl(Context context) { if (!context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN_MULTITOUCH)) { setZoomControlsEnabled(true); } } - private void saveZoomControl(Bundle outState) { - outState.putBoolean(MapboxConstants.STATE_ZOOM_CONTROLS_ENABLED, isZoomControlsEnabled()); - } - - private void restoreZoomControl(Bundle savedInstanceState) { - setZoomControlsEnabled(savedInstanceState.getBoolean(MapboxConstants.STATE_ZOOM_CONTROLS_ENABLED)); - } - /** * <p> * Enables or disables the compass. The compass is an icon on the map that indicates the @@ -282,10 +157,10 @@ public final class UiSettings extends ViewModel { * </p> * By default, the compass is enabled. * - * @param compassEnabled True to enable the compass; false to disable the compass. + * @param enabled True to enable the compass; false to disable the compass. */ - public void setCompassEnabled(boolean compassEnabled) { - compassView.setEnabled(compassEnabled); + public void setCompassEnabled(boolean enabled) { + compassEnabled.setValue(enabled); } /** @@ -294,7 +169,16 @@ public final class UiSettings extends ViewModel { * @return True if the compass is enabled; false if the compass is disabled. */ public boolean isCompassEnabled() { - return compassView.isEnabled(); + return compassEnabled.getValue(); + } + + /** + * Returns whether the compass is enabled observable. + * + * @return Compass enabled observable. + */ + public MutableLiveData<Boolean> isCompassEnabledObservable() { + return compassEnabled; } /** @@ -308,7 +192,7 @@ public final class UiSettings extends ViewModel { */ @UiThread public void setCompassGravity(int gravity) { - setWidgetGravity(compassView, gravity); + compassGravity.setValue(gravity); } /** @@ -317,10 +201,10 @@ public final class UiSettings extends ViewModel { * By default this feature is enabled * </p> * - * @param compassFadeFacingNorth True to enable the fading animation; false to disable it + * @param fadeFacingNorth True to enable the fading animation; false to disable it */ - public void setCompassFadeFacingNorth(boolean compassFadeFacingNorth) { - compassView.fadeCompassViewFacingNorth(compassFadeFacingNorth); + public void setCompassFadeFacingNorth(boolean fadeFacingNorth) { + compassFadeFacingNorth.setValue(fadeFacingNorth); } /** @@ -332,7 +216,7 @@ public final class UiSettings extends ViewModel { * @param compass the drawable to show as image compass */ public void setCompassImage(@NonNull Drawable compass) { - compassView.setCompassImage(compass); + compassImage.setValue(compass); } /** @@ -341,7 +225,16 @@ public final class UiSettings extends ViewModel { * @return True if the compass will fade, false if it remains visible */ public boolean isCompassFadeWhenFacingNorth() { - return compassView.isFadeCompassViewFacingNorth(); + return compassFadeFacingNorth.getValue(); + } + + /** + * Returns whether the compass performs a fading animation out when facing north observable. + * + * @return Compass fading north observable. + */ + public MutableLiveData<Boolean> isCompassFadeWhenFacingNorthObservable() { + return compassFadeFacingNorth; } /** @@ -350,7 +243,16 @@ public final class UiSettings extends ViewModel { * @return The gravity */ public int getCompassGravity() { - return ((FrameLayout.LayoutParams) compassView.getLayoutParams()).gravity; + return compassGravity.getValue(); + } + + /** + * Returns the compass gravity value observable + * + * @return The gravity observable + */ + public MutableLiveData<Integer> getCompassGravityObservable() { + return compassGravity; } /** @@ -364,7 +266,7 @@ public final class UiSettings extends ViewModel { */ @UiThread public void setCompassMargins(int left, int top, int right, int bottom) { - setWidgetMargins(compassView, compassMargins, left, top, right, bottom); + compassMargins.setValue(new Integer[] {left, top, right, bottom}); } /** @@ -373,7 +275,7 @@ public final class UiSettings extends ViewModel { * @return The left margin in pixels */ public int getCompassMarginLeft() { - return compassMargins[0]; + return compassMargins.getValue()[0]; } /** @@ -382,7 +284,7 @@ public final class UiSettings extends ViewModel { * @return The top margin in pixels */ public int getCompassMarginTop() { - return compassMargins[1]; + return compassMargins.getValue()[1]; } /** @@ -391,7 +293,7 @@ public final class UiSettings extends ViewModel { * @return The right margin in pixels */ public int getCompassMarginRight() { - return compassMargins[2]; + return compassMargins.getValue()[2]; } /** @@ -400,7 +302,16 @@ public final class UiSettings extends ViewModel { * @return The bottom margin in pixels */ public int getCompassMarginBottom() { - return compassMargins[3]; + return compassMargins.getValue()[3]; + } + + /** + * Get Compass View margins observable. + * + * @return Compass View margins observable. + */ + public MutableLiveData<Integer[]> getCompassMarginsObservable() { + return compassMargins; } /** @@ -410,16 +321,25 @@ public final class UiSettings extends ViewModel { */ @NonNull public Drawable getCompassImage() { - return compassView.getCompassImage(); + return compassImage.getValue(); } - void update(@NonNull CameraPosition cameraPosition) { - if (!isCompassEnabled()) { - return; - } + /** + * Get the CompassView image observable. + * + * @return the observable of the drawable used as compass image + */ + public MutableLiveData<Drawable> getCompassImageObservable() { + return compassImage; + } + void updateCompass(@NonNull CameraPosition cameraPosition) { double clockwiseBearing = -cameraPosition.bearing; - compassView.update(clockwiseBearing); + compassRotation.setValue(clockwiseBearing); + } + + public MutableLiveData<Double> getCompassRotationObservable() { + return compassRotation; } /** @@ -431,7 +351,7 @@ public final class UiSettings extends ViewModel { * @param enabled True to enable the logo; false to disable the logo. */ public void setLogoEnabled(boolean enabled) { - logoView.setVisibility(enabled ? View.VISIBLE : View.GONE); + logoEnabled.setValue(enabled); } /** @@ -440,7 +360,16 @@ public final class UiSettings extends ViewModel { * @return True if the logo is enabled; false if the logo is disabled. */ public boolean isLogoEnabled() { - return logoView.getVisibility() == View.VISIBLE; + return logoEnabled.getValue(); + } + + /** + * Returns whether the logo is enabled observable. + * + * @return Logo is enabled observable. + */ + public MutableLiveData<Boolean> isLogoEnabledObservable() { + return logoEnabled; } /** @@ -453,7 +382,7 @@ public final class UiSettings extends ViewModel { * @param gravity Android SDK Gravity. */ public void setLogoGravity(int gravity) { - setWidgetGravity(logoView, gravity); + logoGravity.setValue(gravity); } /** @@ -462,7 +391,16 @@ public final class UiSettings extends ViewModel { * @return The gravity */ public int getLogoGravity() { - return ((FrameLayout.LayoutParams) logoView.getLayoutParams()).gravity; + return logoGravity.getValue(); + } + + /** + * Returns the observable gravity value of the logo + * + * @return The observable gravity + */ + public MutableLiveData<Integer> getLogoGravityObservable() { + return logoGravity; } /** @@ -475,7 +413,7 @@ public final class UiSettings extends ViewModel { * @param bottom The bottom margin in pixels. */ public void setLogoMargins(int left, int top, int right, int bottom) { - setWidgetMargins(logoView, logoMargins, left, top, right, bottom); + logoMargins.setValue(new Integer[] {left, top, right, bottom}); } /** @@ -484,7 +422,7 @@ public final class UiSettings extends ViewModel { * @return The left margin in pixels */ public int getLogoMarginLeft() { - return logoMargins[0]; + return logoMargins.getValue()[0]; } /** @@ -493,7 +431,7 @@ public final class UiSettings extends ViewModel { * @return The top margin in pixels */ public int getLogoMarginTop() { - return logoMargins[1]; + return logoMargins.getValue()[1]; } /** @@ -502,7 +440,7 @@ public final class UiSettings extends ViewModel { * @return The right margin in pixels */ public int getLogoMarginRight() { - return logoMargins[2]; + return logoMargins.getValue()[2]; } /** @@ -511,7 +449,16 @@ public final class UiSettings extends ViewModel { * @return The bottom margin in pixels */ public int getLogoMarginBottom() { - return logoMargins[3]; + return logoMargins.getValue()[3]; + } + + /** + * Returns Logo view margins observable. + * + * @return Logo view margins observable. + */ + public MutableLiveData<Integer[]> getLogoMarginsObservable() { + return logoMargins; } /** @@ -523,7 +470,7 @@ public final class UiSettings extends ViewModel { * @param enabled True to enable the attribution; false to disable the attribution. */ public void setAttributionEnabled(boolean enabled) { - attributionsView.setVisibility(enabled ? View.VISIBLE : View.GONE); + attributionEnabled.setValue(enabled); } /** @@ -532,29 +479,53 @@ public final class UiSettings extends ViewModel { * @return True if the attribution is enabled; false if the attribution is disabled. */ public boolean isAttributionEnabled() { - return attributionsView.getVisibility() == View.VISIBLE; + return attributionEnabled.getValue(); } + /** + * Returns whether the attribution is enabled observable. + * + * @return Attribution is enabled observable. + */ + public MutableLiveData<Boolean> isAttributionEnabledObservable() { + return attributionEnabled; + } /** * Set a custom attribution dialog manager. * <p> * Set to null to reset to default behaviour. - * </p> + * <p> + * You need to reset your custom manager with every {@link MapView} re-creation. * * @param attributionDialogManager the manager class used for showing attribution + * @deprecated This method might cause memory leaks. + * Use {@link MapView#setAttributionDialogManager(AttributionDialogManager)} instead. */ - public void setAttributionDialogManager(@NonNull AttributionDialogManager attributionDialogManager) { - this.attributionDialogManager = attributionDialogManager; + @Deprecated + public void setAttributionDialogManager(@Nullable AttributionDialogManager attributionDialogManager) { + this.attributionDialogManager.setValue(attributionDialogManager); } /** * Get the custom attribution dialog manager. * * @return the active manager class used for showing attribution + * @deprecated This method might lead to the memory leaks. + * Use {@link MapView#setAttributionDialogManager(AttributionDialogManager)} instead. */ - @NonNull + @Deprecated + @Nullable public AttributionDialogManager getAttributionDialogManager() { + return attributionDialogManager.getValue(); + } + + /** + * Get the custom attribution dialog manager observable. + * + * @return Custom attribution dialog manager observable. + */ + public MutableLiveData<AttributionDialogManager> getAttributionDialogManagerObservable() { return attributionDialogManager; } @@ -567,7 +538,7 @@ public final class UiSettings extends ViewModel { * @param gravity Android SDK Gravity. */ public void setAttributionGravity(int gravity) { - setWidgetGravity(attributionsView, gravity); + attributionGravity.setValue(gravity); } /** @@ -576,7 +547,16 @@ public final class UiSettings extends ViewModel { * @return The gravity */ public int getAttributionGravity() { - return ((FrameLayout.LayoutParams) attributionsView.getLayoutParams()).gravity; + return attributionGravity.getValue(); + } + + /** + * Returns the gravity value of the logo observable. + * + * @return The gravity observable. + */ + public MutableLiveData<Integer> getAttributionGravityObservable() { + return attributionGravity; } /** @@ -588,7 +568,7 @@ public final class UiSettings extends ViewModel { * @param bottom The bottom margin in pixels. */ public void setAttributionMargins(int left, int top, int right, int bottom) { - setWidgetMargins(attributionsView, attributionsMargins, left, top, right, bottom); + attributionMargins.setValue(new Integer[] {left, top, right, bottom}); } /** @@ -600,13 +580,16 @@ public final class UiSettings extends ViewModel { * @param tintColor Color to tint the attribution. */ public void setAttributionTintColor(@ColorInt int tintColor) { - // Check that the tint color being passed in isn't transparent. - if (Color.alpha(tintColor) == 0) { - ColorUtils.setTintList(attributionsView, - ContextCompat.getColor(attributionsView.getContext(), R.color.mapbox_blue)); - } else { - ColorUtils.setTintList(attributionsView, tintColor); - } + attributionTintColor.setValue(tintColor); + } + + /** + * Get Attribution tint color observable. + * + * @return Attribution tint color observable. + */ + public MutableLiveData<Integer> getAttributionTintColorObservable() { + return attributionTintColor; } /** @@ -615,7 +598,7 @@ public final class UiSettings extends ViewModel { * @return The left margin in pixels */ public int getAttributionMarginLeft() { - return attributionsMargins[0]; + return attributionMargins.getValue()[0]; } /** @@ -624,7 +607,7 @@ public final class UiSettings extends ViewModel { * @return The top margin in pixels */ public int getAttributionMarginTop() { - return attributionsMargins[1]; + return attributionMargins.getValue()[1]; } /** @@ -633,7 +616,7 @@ public final class UiSettings extends ViewModel { * @return The right margin in pixels */ public int getAttributionMarginRight() { - return attributionsMargins[2]; + return attributionMargins.getValue()[2]; } /** @@ -642,7 +625,16 @@ public final class UiSettings extends ViewModel { * @return The bottom margin in pixels */ public int getAttributionMarginBottom() { - return attributionsMargins[3]; + return attributionMargins.getValue()[3]; + } + + /** + * Returns Attribution margins observable. + * + * @return Attribution margins observable. + */ + public MutableLiveData<Integer[]> getAttributionMarginsObservable() { + return attributionMargins; } /** @@ -771,14 +763,6 @@ public final class UiSettings extends ViewModel { return doubleTapGesturesEnabled; } - private void restoreDeselectMarkersOnTap(Bundle savedInstanceState) { - setDeselectMarkersOnTap(savedInstanceState.getBoolean(MapboxConstants.STATE_DESELECT_MARKER_ON_TAP)); - } - - private void saveDeselectMarkersOnTap(Bundle outState) { - outState.putBoolean(MapboxConstants.STATE_DESELECT_MARKER_ON_TAP, isDeselectMarkersOnTap()); - } - /** * Gets whether the markers are automatically deselected (and therefore, their infowindows * closed) when a map tap is detected. @@ -949,31 +933,21 @@ public final class UiSettings extends ViewModel { setDoubleTapGesturesEnabled(enabled); } - private void saveFocalPoint(Bundle outState) { - outState.putParcelable(MapboxConstants.STATE_USER_FOCAL_POINT, getFocalPoint()); - } - - private void restoreFocalPoint(Bundle savedInstanceState) { - PointF pointF = savedInstanceState.getParcelable(MapboxConstants.STATE_USER_FOCAL_POINT); - if (pointF != null) { - setFocalPoint(pointF); - } - } - /** - * Sets the focal point used as center for a gesture + * Sets the focal point used as center for a gestures transformations. * * @param focalPoint the focal point to be used. */ public void setFocalPoint(@Nullable PointF focalPoint) { - userProvidedFocalPoint.postValue(focalPoint); + userProvidedFocalPoint.setValue(focalPoint); } /** - * Returns the gesture focal point + * Returns the gestures focal point if set. * - * @return The focal point + * @return The focal point if set, otherwise null. */ + @Nullable public PointF getFocalPoint() { return userProvidedFocalPoint.getValue(); } @@ -991,7 +965,9 @@ public final class UiSettings extends ViewModel { * Returns the measured height of the MapView * * @return height in pixels + * @deprecated Use {@link MapView#getHeight()} instead. */ + @Deprecated public float getHeight() { return projection.getHeight(); } @@ -1000,15 +976,13 @@ public final class UiSettings extends ViewModel { * Returns the measured width of the MapView * * @return widht in pixels + * @deprecated Use {@link MapView#getWidth()} instead. */ + @Deprecated public float getWidth() { return projection.getWidth(); } - float getPixelRatio() { - return pixelRatio; - } - /** * Invalidates the ViewSettings instances shown on top of the MapView */ @@ -1019,29 +993,12 @@ public final class UiSettings extends ViewModel { getAttributionMarginBottom()); } - private void setWidgetGravity(@NonNull final View view, int gravity) { - FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) view.getLayoutParams(); - layoutParams.gravity = gravity; - view.setLayoutParams(layoutParams); - } - - private void setWidgetMargins(@NonNull final View view, int[] initMargins, int left, int top, int right, int bottom) { - // keep state of initially set margins - initMargins[0] = left; - initMargins[1] = top; - initMargins[2] = right; - initMargins[3] = bottom; - - // convert initial margins with padding - FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) view.getLayoutParams(); - layoutParams.setMargins(left, top, right, bottom); - - // support RTL - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { - layoutParams.setMarginStart(left); - layoutParams.setMarginEnd(right); - } - - view.setLayoutParams(layoutParams); + /** + * Method used to cleanup resources that might leak during configuration change, + * like deprecated {@link #setAttributionDialogManager(AttributionDialogManager)} or {@link #getWidth()}. + */ + void onMapDestroy() { + setAttributionDialogManager(null); + projection = null; } } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/CompassView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/CompassView.java index fb2c70cb73..0c8f6f48d3 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/CompassView.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/CompassView.java @@ -1,9 +1,12 @@ package com.mapbox.mapboxsdk.maps.widgets; import android.annotation.SuppressLint; +import android.arch.lifecycle.ViewModelProviders; import android.content.Context; import android.graphics.drawable.Drawable; import android.support.annotation.NonNull; +import android.support.annotation.UiThread; +import android.support.v4.app.FragmentActivity; import android.support.v4.view.ViewCompat; import android.support.v4.view.ViewPropertyAnimatorCompat; import android.support.v4.view.ViewPropertyAnimatorListenerAdapter; @@ -13,6 +16,7 @@ import android.view.ViewGroup; import android.widget.ImageView; import com.mapbox.mapboxsdk.maps.MapboxMap; +import com.mapbox.mapboxsdk.maps.UiSettings; /** * UI element overlaid on a map to show the map's bearing when it isn't true north (0.0). Tapping @@ -24,6 +28,7 @@ import com.mapbox.mapboxsdk.maps.MapboxMap; * </p> */ @SuppressLint("AppCompatCustomView") +@UiThread public final class CompassView extends ImageView implements Runnable { public static final long TIME_WAIT_IDLE = 500; @@ -36,6 +41,8 @@ public final class CompassView extends ImageView implements Runnable { private MapboxMap.OnCompassAnimationListener compassAnimationListener; private boolean isAnimating = false; + private UiSettings uiSettings; + public CompassView(Context context) { super(context); initialize(context); @@ -52,7 +59,7 @@ public final class CompassView extends ImageView implements Runnable { } private void initialize(Context context) { - setEnabled(false); + uiSettings = ViewModelProviders.of((FragmentActivity) context).get(UiSettings.class); // Layout params float screenDensity = context.getResources().getDisplayMetrics().density; @@ -96,14 +103,27 @@ public final class CompassView extends ImageView implements Runnable { setAlpha(0.0f); setVisibility(View.INVISIBLE); } + + if (uiSettings != null && uiSettings.isCompassEnabled() != enabled) { + // store the right state in the LiveData object + uiSettings.setCompassEnabled(enabled); + } } /** * Updates the direction of the compass. * * @param bearing the direction value of the map + * @deprecated Use {@link UiSettings#getCompassRotationObservable()} instead. */ + @Deprecated public void update(final double bearing) { + if (uiSettings.getCompassRotationObservable().getValue() != bearing) { + uiSettings.getCompassRotationObservable().setValue(bearing); + } + } + + void updateBearing(double bearing) { rotation = (float) bearing; if (!isEnabled()) { @@ -126,28 +146,51 @@ public final class CompassView extends ImageView implements Runnable { setRotation(rotation); } + /** + * @deprecated Use {@link UiSettings#setCompassFadeFacingNorth(boolean)} instead. + */ + @Deprecated public void fadeCompassViewFacingNorth(boolean compassFadeFacingNorth) { - fadeCompassViewFacingNorth = compassFadeFacingNorth; + if (uiSettings != null && uiSettings.isCompassFadeWhenFacingNorth() != compassFadeFacingNorth) { + // store the right state in the LiveData object + uiSettings.setCompassFadeFacingNorth(compassFadeFacingNorth); + } } + /** + * @deprecated Use {@link UiSettings#isCompassFadeWhenFacingNorth()} instead. + */ + @Deprecated public boolean isFadeCompassViewFacingNorth() { return fadeCompassViewFacingNorth; } + void hideCompassViewFacingNorth(boolean compassFadeFacingNorth) { + fadeCompassViewFacingNorth = compassFadeFacingNorth; + } + /** * Set the CompassView image. * * @param compass the drawable to use as compass image + * @deprecated Use {@link UiSettings#setCompassImage(Drawable)} instead. */ + @Deprecated public void setCompassImage(Drawable compass) { - setImageDrawable(compass); + if (uiSettings != null) { + uiSettings.setCompassImage(compass); + } else { + setImageDrawable(compass); + } } /** * Get the current configured CompassView image. * * @return the drawable used as compass image + * @deprecated Use {@link UiSettings#getCompassImage()} instead. */ + @Deprecated public Drawable getCompassImage() { return getDrawable(); } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/WidgetUpdater.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/WidgetUpdater.java new file mode 100644 index 0000000000..799d90fcf2 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/WidgetUpdater.java @@ -0,0 +1,107 @@ +package com.mapbox.mapboxsdk.maps.widgets; + +import android.arch.lifecycle.LifecycleOwner; +import android.arch.lifecycle.ViewModelProviders; +import android.content.Context; +import android.graphics.Color; +import android.support.annotation.NonNull; +import android.support.v4.app.FragmentActivity; +import android.support.v4.content.ContextCompat; +import android.view.View; +import android.widget.ImageView; + +import com.mapbox.mapboxsdk.R; +import com.mapbox.mapboxsdk.maps.UiSettings; +import com.mapbox.mapboxsdk.utils.ColorUtils; +import com.mapbox.mapboxsdk.utils.ViewUtils; + +/** + * Internal class used to update widget views to reflect {@link UiSettings} changes. + */ +public final class WidgetUpdater { + private final CompassView compassView; + private final ImageView attributionView; + private final View logoView; + + private final UiSettings uiSettings; + + public WidgetUpdater(@NonNull Context context, @NonNull CompassView compassView, + @NonNull ImageView attributionView, @NonNull View logoView) { + this.compassView = compassView; + this.attributionView = attributionView; + this.logoView = logoView; + + uiSettings = ViewModelProviders.of((FragmentActivity) context).get(UiSettings.class); + initialiseCompassObservableSettings(context); + initialiseAttributionObservableSettings(context); + initialiseLogoObservableSettings(context); + } + + private void initialiseCompassObservableSettings(Context context) { + LifecycleOwner lifecycleOwner = (LifecycleOwner) context; + + // gravity + uiSettings.getCompassGravityObservable().observe(lifecycleOwner, + gravity -> ViewUtils.setViewGravity(compassView, gravity)); + + // image + uiSettings.getCompassImageObservable().observe(lifecycleOwner, compassView::setImageDrawable); + + // enabled + uiSettings.isCompassEnabledObservable().observe(lifecycleOwner, compassView::setEnabled); + + // fading north + uiSettings.isCompassFadeWhenFacingNorthObservable().observe(lifecycleOwner, + compassView::hideCompassViewFacingNorth); + + // margins + uiSettings.getCompassMarginsObservable().observe(lifecycleOwner, margins -> + ViewUtils.setViewMargins(compassView, margins[0], margins[1], margins[2], margins[3])); + + // rotation + uiSettings.getCompassRotationObservable().observe(lifecycleOwner, compassView::updateBearing); + } + + private void initialiseAttributionObservableSettings(Context context) { + LifecycleOwner lifecycleOwner = (LifecycleOwner) context; + + // gravity + uiSettings.getAttributionGravityObservable().observe(lifecycleOwner, + gravity -> ViewUtils.setViewGravity(attributionView, gravity)); + + // enabled + uiSettings.isAttributionEnabledObservable().observe(lifecycleOwner, + enabled -> attributionView.setVisibility(enabled ? View.VISIBLE : View.GONE)); + + // tint color + uiSettings.getAttributionTintColorObservable().observe(lifecycleOwner, tintColor -> { + // Check that the tint color being passed in isn't transparent. + if (Color.alpha(tintColor) == 0) { + ColorUtils.setTintList(attributionView, + ContextCompat.getColor(attributionView.getContext(), R.color.mapbox_blue)); + } else { + ColorUtils.setTintList(attributionView, tintColor); + } + }); + + // margins + uiSettings.getAttributionMarginsObservable().observe(lifecycleOwner, margins -> + ViewUtils.setViewMargins(attributionView, margins[0], margins[1], margins[2], margins[3])); + } + + private void initialiseLogoObservableSettings(Context context) { + LifecycleOwner lifecycleOwner = (LifecycleOwner) context; + + // gravity + uiSettings.getLogoGravityObservable().observe(lifecycleOwner, + gravity -> ViewUtils.setViewGravity(logoView, gravity)); + + // enabled + uiSettings.isLogoEnabledObservable().observe(lifecycleOwner, + enabled -> logoView.setVisibility(enabled ? View.VISIBLE : View.GONE)); + + // margins + uiSettings.getLogoMarginsObservable().observe(lifecycleOwner, margins -> + ViewUtils.setViewMargins(logoView, margins[0], margins[1], margins[2], margins[3])); + } +} diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/ViewUtils.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/ViewUtils.java new file mode 100644 index 0000000000..d92741e52c --- /dev/null +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/ViewUtils.java @@ -0,0 +1,44 @@ +package com.mapbox.mapboxsdk.utils; + +import android.os.Build; +import android.support.annotation.NonNull; +import android.view.View; +import android.widget.FrameLayout; + +public class ViewUtils { + + /** + * Programatically set View's gravity. + * + * @param view the view + * @param gravity the gravity + */ + public static void setViewGravity(@NonNull final View view, int gravity) { + FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) view.getLayoutParams(); + layoutParams.gravity = gravity; + view.setLayoutParams(layoutParams); + } + + /** + * Programatically set View's margins. + * @param view the view + * @param initMargins initial margins + * @param left left margin + * @param top top margin + * @param right right margin + * @param bottom bottom margin + */ + public static void setViewMargins(@NonNull final View view, int left, int top, int right, int bottom) { + // convert initial margins with padding + FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) view.getLayoutParams(); + layoutParams.setMargins(left, top, right, bottom); + + // support RTL + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { + layoutParams.setMarginStart(left); + layoutParams.setMarginEnd(right); + } + + view.setLayoutParams(layoutParams); + } +} diff --git a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/UiSettingsTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/UiSettingsTest.java index 160b63b945..6ef9f55033 100644 --- a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/UiSettingsTest.java +++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/UiSettingsTest.java @@ -1,14 +1,18 @@ package com.mapbox.mapboxsdk.maps; +import android.arch.core.executor.testing.InstantTaskExecutorRule; +import android.content.Context; +import android.content.pm.PackageManager; +import android.content.res.Resources; import android.view.Gravity; -import android.view.View; -import android.widget.FrameLayout; -import android.widget.ImageView; -import com.mapbox.mapboxsdk.maps.widgets.CompassView; +import com.mapbox.mapboxsdk.R; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; import org.mockito.InjectMocks; import static org.junit.Assert.assertEquals; @@ -18,29 +22,41 @@ import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +@RunWith(JUnit4.class) public class UiSettingsTest { - @InjectMocks - Projection projection = mock(Projection.class); + @Rule + public InstantTaskExecutorRule instantExecutorRule = new InstantTaskExecutorRule(); @InjectMocks - CompassView compassView = mock(CompassView.class); + Projection projection = mock(Projection.class); @InjectMocks - ImageView imageView = mock(ImageView.class); + Context context = mock(Context.class); @InjectMocks - ImageView logoView = mock(ImageView.class); + Resources resources = mock(Resources.class); @InjectMocks - FrameLayout.LayoutParams layoutParams = mock(FrameLayout.LayoutParams.class); + PackageManager packageManager = mock(PackageManager.class); private UiSettings uiSettings; @Before public void beforeTest() { + when(context.getResources()).thenReturn(resources); + when(resources.getDimension(R.dimen.mapbox_four_dp)).thenReturn(25f); + when(context.getPackageManager()).thenReturn(packageManager); + when(packageManager.hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN_MULTITOUCH)).thenReturn(true); + + MapboxMapOptions options = new MapboxMapOptions(); uiSettings = new UiSettings(); - uiSettings.initialiseViews(projection, compassView, imageView, logoView); + uiSettings.initialiseProjection(projection); + uiSettings.initialiseGestures(options); + uiSettings.initialiseCompass(options, resources); + uiSettings.initialiseLogo(options, resources); + uiSettings.initialiseAttribution(context, options); + uiSettings.initialiseZoomControl(context); } @Test @@ -50,7 +66,6 @@ public class UiSettingsTest { @Test public void testCompassEnabled() { - when(compassView.isEnabled()).thenReturn(true); uiSettings.setCompassEnabled(true); assertEquals("Compass should be enabled", true, uiSettings.isCompassEnabled()); } @@ -63,20 +78,12 @@ public class UiSettingsTest { @Test public void testCompassGravity() { - when(compassView.getLayoutParams()).thenReturn(layoutParams); - layoutParams.gravity = Gravity.START; uiSettings.setCompassGravity(Gravity.START); assertEquals("Compass gravity should be same", Gravity.START, uiSettings.getCompassGravity()); } @Test public void testCompassMargins() { - when(projection.getContentPadding()).thenReturn(new int[] {0, 0, 0, 0}); - when(compassView.getLayoutParams()).thenReturn(layoutParams); - layoutParams.leftMargin = 1; - layoutParams.topMargin = 2; - layoutParams.rightMargin = 3; - layoutParams.bottomMargin = 4; uiSettings.setCompassMargins(1, 2, 3, 4); assertTrue("Compass margin left should be same", uiSettings.getCompassMarginLeft() == 1); assertTrue("Compass margin top should be same", uiSettings.getCompassMarginTop() == 2); @@ -86,10 +93,8 @@ public class UiSettingsTest { @Test public void testCompassFadeWhenFacingNorth() { - when(compassView.isFadeCompassViewFacingNorth()).thenReturn(true); assertTrue("Compass should fade when facing north by default.", uiSettings.isCompassFadeWhenFacingNorth()); uiSettings.setCompassFadeFacingNorth(false); - when(compassView.isFadeCompassViewFacingNorth()).thenReturn(false); assertFalse("Compass fading should be disabled", uiSettings.isCompassFadeWhenFacingNorth()); } @@ -101,27 +106,18 @@ public class UiSettingsTest { @Test public void testLogoDisabled() { - when(logoView.getVisibility()).thenReturn(View.GONE); uiSettings.setLogoEnabled(false); assertEquals("Logo should be disabled", false, uiSettings.isLogoEnabled()); } @Test public void testLogoGravity() { - layoutParams.gravity = Gravity.END; - when(logoView.getLayoutParams()).thenReturn(layoutParams); uiSettings.setLogoGravity(Gravity.END); assertEquals("Logo gravity should be same", Gravity.END, uiSettings.getLogoGravity()); } @Test public void testLogoMargins() { - when(projection.getContentPadding()).thenReturn(new int[] {0, 0, 0, 0}); - when(logoView.getLayoutParams()).thenReturn(layoutParams); - layoutParams.leftMargin = 1; - layoutParams.topMargin = 2; - layoutParams.rightMargin = 3; - layoutParams.bottomMargin = 4; uiSettings.setLogoMargins(1, 2, 3, 4); assertTrue("Compass margin left should be same", uiSettings.getLogoMarginLeft() == 1); assertTrue("Compass margin top should be same", uiSettings.getLogoMarginTop() == 2); @@ -131,34 +127,24 @@ public class UiSettingsTest { @Test public void testAttributionEnabled() { - when(imageView.getVisibility()).thenReturn(View.VISIBLE); uiSettings.setAttributionEnabled(true); assertEquals("Attribution should be enabled", true, uiSettings.isAttributionEnabled()); } @Test public void testAttributionDisabled() { - when(imageView.getVisibility()).thenReturn(View.GONE); uiSettings.setAttributionEnabled(false); assertEquals("Attribution should be disabled", false, uiSettings.isAttributionEnabled()); } @Test public void testAttributionGravity() { - when(imageView.getLayoutParams()).thenReturn(layoutParams); - layoutParams.gravity = Gravity.END; uiSettings.setAttributionGravity(Gravity.END); assertEquals("Attribution gravity should be same", Gravity.END, uiSettings.getAttributionGravity()); } @Test public void testAttributionMargins() { - when(imageView.getLayoutParams()).thenReturn(layoutParams); - when(projection.getContentPadding()).thenReturn(new int[] {0, 0, 0, 0}); - layoutParams.leftMargin = 1; - layoutParams.topMargin = 2; - layoutParams.rightMargin = 3; - layoutParams.bottomMargin = 4; uiSettings.setAttributionMargins(1, 2, 3, 4); assertTrue("Attribution margin left should be same", uiSettings.getAttributionMarginLeft() == 1); assertTrue("Attribution margin top should be same", uiSettings.getAttributionMarginTop() == 2); diff --git a/platform/android/gradle/dependencies.gradle b/platform/android/gradle/dependencies.gradle index b7e6feaf81..f254dac677 100644 --- a/platform/android/gradle/dependencies.gradle +++ b/platform/android/gradle/dependencies.gradle @@ -50,6 +50,7 @@ ext { archLifecycleExtensions : "android.arch.lifecycle:extensions:${versions.archLifecycle}", archLifecycleAnnotations: "android.arch.lifecycle:common-java8:${versions.archLifecycle}", + archCoreTesting : "android.arch.core:core-testing:${versions.archLifecycle}", gmsLocation : 'com.google.android.gms:play-services-location:11.0.4', timber : "com.jakewharton.timber:timber:${versions.timber}", |