Skip to content

Commit

Permalink
Add NavigationCamera#update for MapboxMap animations
Browse files Browse the repository at this point in the history
  • Loading branch information
danesfeder committed Mar 28, 2019
1 parent b911e4e commit a39cf73
Show file tree
Hide file tree
Showing 11 changed files with 325 additions and 27 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import android.os.VibrationEffect;
import android.os.Vibrator;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.constraint.ConstraintLayout;
import android.support.design.widget.BaseTransientBottomBar;
import android.support.design.widget.FloatingActionButton;
Expand All @@ -26,6 +27,7 @@
import com.mapbox.geojson.Point;
import com.mapbox.mapboxsdk.Mapbox;
import com.mapbox.mapboxsdk.camera.CameraPosition;
import com.mapbox.mapboxsdk.camera.CameraUpdate;
import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.geometry.LatLngBounds;
Expand All @@ -38,6 +40,7 @@
import com.mapbox.services.android.navigation.testapp.activity.HistoryActivity;
import com.mapbox.services.android.navigation.ui.v5.camera.DynamicCamera;
import com.mapbox.services.android.navigation.ui.v5.camera.NavigationCamera;
import com.mapbox.services.android.navigation.ui.v5.camera.NavigationCameraUpdate;
import com.mapbox.services.android.navigation.ui.v5.instruction.InstructionView;
import com.mapbox.services.android.navigation.ui.v5.map.NavigationMapboxMap;
import com.mapbox.services.android.navigation.ui.v5.voice.NavigationSpeechPlayer;
Expand Down Expand Up @@ -171,7 +174,6 @@ public boolean onMapLongClick(@NonNull LatLng point) {

@OnClick(R.id.startNavigationFab)
public void onStartNavigationClick(FloatingActionButton floatingActionButton) {
navigationMap.updateCameraTrackingMode(NavigationCamera.NAVIGATION_TRACKING_MODE_GPS);
// Transition to navigation state
mapState = MapState.NAVIGATION;

Expand All @@ -188,6 +190,14 @@ public void onStartNavigationClick(FloatingActionButton floatingActionButton) {

// Location updates will be received from ProgressChangeListener
removeLocationEngineListener();

// TODO remove example usage
navigationMap.resetCameraPositionWith(NavigationCamera.NAVIGATION_TRACKING_MODE_GPS);
CameraUpdate cameraUpdate = cameraOverheadUpdate();
if (cameraUpdate != null) {
NavigationCameraUpdate navUpdate = new NavigationCameraUpdate(cameraUpdate);
navigationMap.retrieveCamera().update(navUpdate);
}
}

@OnClick(R.id.cancelNavigationFab)
Expand Down Expand Up @@ -388,6 +398,15 @@ private void moveCameraOverhead() {
);
}

@Nullable
private CameraUpdate cameraOverheadUpdate() {
if (lastLocation == null) {
return null;
}
CameraPosition cameraPosition = buildCameraPositionFrom(lastLocation, DEFAULT_BEARING);
return CameraUpdateFactory.newCameraPosition(cameraPosition);
}

@NonNull
private CameraPosition buildCameraPositionFrom(Location location, double bearing) {
return new CameraPosition.Builder()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@

import com.mapbox.api.directions.v5.models.DirectionsRoute;
import com.mapbox.geojson.Point;
import com.mapbox.services.android.navigation.ui.v5.camera.NavigationCamera;

public interface NavigationContract {

Expand All @@ -21,8 +20,6 @@ interface View {

void updateWayNameView(@NonNull String wayName);

void updateCameraTrackingMode(@NavigationCamera.TrackingMode int trackingMode);

void resetCameraPosition();

void showRecenterBtn();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
import com.mapbox.api.directions.v5.models.DirectionsRoute;
import com.mapbox.core.utils.TextUtils;
import com.mapbox.geojson.Point;
import com.mapbox.services.android.navigation.ui.v5.camera.NavigationCamera;

class NavigationPresenter {

Expand All @@ -34,7 +33,6 @@ void onCameraTrackingDismissed() {
if (!view.isSummaryBottomSheetHidden()) {
view.setSummaryBehaviorHideable(true);
view.setSummaryBehaviorState(BottomSheetBehavior.STATE_HIDDEN);
view.updateCameraTrackingMode(NavigationCamera.NAVIGATION_TRACKING_MODE_NONE);
view.updateWayNameVisibility(false);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -243,14 +243,6 @@ public boolean isSummaryBottomSheetHidden() {
return summaryBehavior.getState() == BottomSheetBehavior.STATE_HIDDEN;
}


@Override
public void updateCameraTrackingMode(int trackingMode) {
if (navigationMap != null) {
navigationMap.updateCameraTrackingMode(trackingMode);
}
}

@Override
public void resetCameraPosition() {
if (navigationMap != null) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.mapbox.services.android.navigation.ui.v5.camera;

import com.mapbox.mapboxsdk.camera.CameraUpdate;
import com.mapbox.mapboxsdk.location.modes.CameraMode;
import com.mapbox.mapboxsdk.maps.MapboxMap;

class CameraAnimationDelegate {

private final MapboxMap mapboxMap;

CameraAnimationDelegate(MapboxMap mapboxMap) {
this.mapboxMap = mapboxMap;
}

void render(NavigationCameraUpdate update, int durationMs, MapboxMap.CancelableCallback callback) {
CameraUpdateMode mode = update.getMode();
CameraUpdate cameraUpdate = update.getCameraUpdate();
if (mode == CameraUpdateMode.OVERRIDE) {
mapboxMap.getLocationComponent().setCameraMode(CameraMode.NONE);
mapboxMap.animateCamera(cameraUpdate, durationMs, callback);
} else if (!isTracking()) {
mapboxMap.animateCamera(cameraUpdate, durationMs, callback);
}
}

private boolean isTracking() {
int cameraMode = mapboxMap.getLocationComponent().getCameraMode();
return cameraMode != CameraMode.NONE;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.mapbox.services.android.navigation.ui.v5.camera;

/**
* This class is passed to {@link NavigationCameraUpdate} to
* determine the update's behavior when passed to {@link NavigationCamera}.
*/
public enum CameraUpdateMode {

/**
* For a given {@link NavigationCameraUpdate}, this default mode means the
* {@link NavigationCamera} will ignore the update when tracking is already
* enabled.
* <p>
* If tracking is disabled, the update animation will execute.
*/
DEFAULT,

/**
* For a given {@link NavigationCameraUpdate}, this override mode means the
* {@link NavigationCamera} will stop tracking (if tracking) and execute the
* given update animation.
*/
OVERRIDE
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,11 @@
import com.mapbox.mapboxsdk.camera.CameraPosition;
import com.mapbox.mapboxsdk.camera.CameraUpdate;
import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
import com.mapbox.mapboxsdk.constants.MapboxConstants;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.geometry.LatLngBounds;
import com.mapbox.mapboxsdk.location.LocationComponent;
import com.mapbox.mapboxsdk.location.OnCameraTrackingChangedListener;
import com.mapbox.mapboxsdk.location.OnLocationCameraTransitionListener;
import com.mapbox.mapboxsdk.location.modes.CameraMode;
import com.mapbox.mapboxsdk.maps.MapboxMap;
Expand Down Expand Up @@ -74,6 +76,8 @@ public class NavigationCamera implements LifecycleObserver {
= new CopyOnWriteArrayList<>();
private final OnLocationCameraTransitionListener cameraTransitionListener
= new NavigationCameraTransitionListener(this);
private final OnCameraTrackingChangedListener cameraTrackingChangedListener
= new NavigationCameraTrackingChangedListener(this);
private MapboxMap mapboxMap;
private LocationComponent locationComponent;
private MapboxNavigation navigation;
Expand All @@ -82,6 +86,7 @@ public class NavigationCamera implements LifecycleObserver {
@TrackingMode
private int trackingCameraMode = NAVIGATION_TRACKING_MODE_GPS;
private boolean isCameraResetting;
private CameraAnimationDelegate animationDelegate;
private ProgressChangeListener progressChangeListener = new ProgressChangeListener() {
@Override
public void onProgressChange(Location location, RouteProgress routeProgress) {
Expand All @@ -107,6 +112,8 @@ public NavigationCamera(@NonNull MapboxMap mapboxMap, @NonNull MapboxNavigation
this.mapboxMap = mapboxMap;
this.navigation = navigation;
this.locationComponent = locationComponent;
this.animationDelegate = new CameraAnimationDelegate(mapboxMap);
this.locationComponent.addOnCameraTrackingChangedListener(cameraTrackingChangedListener);
initializeWith(navigation);
}

Expand All @@ -121,6 +128,8 @@ public NavigationCamera(@NonNull MapboxMap mapboxMap, @NonNull MapboxNavigation
public NavigationCamera(@NonNull MapboxMap mapboxMap, LocationComponent locationComponent) {
this.mapboxMap = mapboxMap;
this.locationComponent = locationComponent;
this.animationDelegate = new CameraAnimationDelegate(mapboxMap);
this.locationComponent.addOnCameraTrackingChangedListener(cameraTrackingChangedListener);
updateCameraTrackingMode(trackingCameraMode);
}

Expand Down Expand Up @@ -212,6 +221,57 @@ public void showRouteOverview(int[] padding) {
animateCameraForRouteOverview(routeInformation, padding);
}

/**
* Animate the camera to a new location defined within {@link CameraUpdate} passed to the
* {@link NavigationCameraUpdate} using a transition animation that evokes powered flight.
* If the camera is in a tracking mode, this animation is going to be ignored, or break the tracking,
* based on the {@link CameraUpdateMode).
*
* @param update the change that should be applied to the camera.
* @see CameraUpdateMode for how this update interacts with the current tracking
*/
public void update(NavigationCameraUpdate update) {
animationDelegate.render(update, MapboxConstants.ANIMATION_DURATION, null);
}

/**
* Animate the camera to a new location defined within {@link CameraUpdate} passed to the
* {@link NavigationCameraUpdate} using a transition animation that evokes powered flight.
* The animation will last a specified amount of time given in milliseconds. If the camera is in a tracking mode,
* this animation is going to be ignored, or break the tracking, based on the {@link CameraUpdateMode).
*
* @param update the change that should be applied to the camera.
* @param durationMs the duration of the animation in milliseconds. This must be strictly
* positive, otherwise an IllegalArgumentException will be thrown.
* @see CameraUpdateMode for how this update interacts with the current tracking
*/
public void update(NavigationCameraUpdate update, int durationMs) {
animationDelegate.render(update, durationMs, null);
}

/**
* Animate the camera to a new location defined within {@link CameraUpdate} passed to the
* {@link NavigationCameraUpdate} using a transition animation that evokes powered flight. The animation will
* last a specified amount of time given in milliseconds. A callback can be used to be notified when animating
* the camera stops. During the animation, a call to {@link MapboxMap#getCameraPosition()} returns an intermediate
* location of the camera in flight. If the camera is in a tracking mode,
* this animation is going to be ignored, or break the tracking, based on the {@link CameraUpdateMode).
*
* @param update the change that should be applied to the camera.
* @param durationMs the duration of the animation in milliseconds. This must be strictly
* positive, otherwise an IllegalArgumentException will be thrown.
* @param callback an optional callback to be notified from the main thread when the animation
* stops. If the animation stops due to its natural completion, the callback
* will be notified with onFinish(). If the animation stops due to interruption
* by a later camera movement or a user gesture, onCancel() will be called.
* Do not update or animate the camera from within onCancel(). If a callback
* isn't required, leave it as null.
* @see CameraUpdateMode for how this update interacts with the current tracking
*/
public void update(NavigationCameraUpdate update, int durationMs, @Nullable MapboxMap.CancelableCallback callback) {
animationDelegate.render(update, durationMs, callback);
}

/**
* Call in {@link FragmentActivity#onStart()} to properly add the {@link ProgressChangeListener}
* for the camera and prevent any leaks or further updates.
Expand Down Expand Up @@ -309,6 +369,19 @@ void updateTransitionListenersCancelled(@CameraMode.Mode int cameraMode) {
}
}

@Nullable
Integer findTrackingModeFor(@CameraMode.Mode int cameraMode) {
if (cameraMode == CameraMode.TRACKING_GPS) {
return NAVIGATION_TRACKING_MODE_GPS;
} else if (cameraMode == CameraMode.TRACKING_GPS_NORTH) {
return NAVIGATION_TRACKING_MODE_NORTH;
} else if (cameraMode == CameraMode.NONE) {
return NAVIGATION_TRACKING_MODE_NONE;
} else {
return null;
}
}

void updateIsResetting(boolean isResetting) {
this.isCameraResetting = isResetting;
}
Expand Down Expand Up @@ -429,19 +502,6 @@ private Integer findCameraModeFor(@TrackingMode int trackingCameraMode) {
}
}

@Nullable
private Integer findTrackingModeFor(@CameraMode.Mode int cameraMode) {
if (cameraMode == CameraMode.TRACKING_GPS) {
return NAVIGATION_TRACKING_MODE_GPS;
} else if (cameraMode == CameraMode.TRACKING_GPS_NORTH) {
return NAVIGATION_TRACKING_MODE_NORTH;
} else if (cameraMode == CameraMode.NONE) {
return NAVIGATION_TRACKING_MODE_NONE;
} else {
return null;
}
}

private void updateTrackingModeListenersWith(@TrackingMode int trackingMode) {
for (OnTrackingModeChangedListener listener : onTrackingModeChangedListeners) {
listener.onTrackingModeChanged(trackingMode);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.mapbox.services.android.navigation.ui.v5.camera;

import com.mapbox.mapboxsdk.location.OnCameraTrackingChangedListener;

class NavigationCameraTrackingChangedListener implements OnCameraTrackingChangedListener {

private final NavigationCamera camera;

NavigationCameraTrackingChangedListener(NavigationCamera camera) {
this.camera = camera;
}

@Override
public void onCameraTrackingDismissed() {
camera.updateCameraTrackingMode(NavigationCamera.NAVIGATION_TRACKING_MODE_NONE);
}

@Override
public void onCameraTrackingChanged(int currentMode) {
Integer trackingMode = camera.findTrackingModeFor(currentMode);
if (trackingMode != null) {
camera.updateCameraTrackingMode(trackingMode);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package com.mapbox.services.android.navigation.ui.v5.camera;

import android.support.annotation.NonNull;

import com.mapbox.mapboxsdk.camera.CameraUpdate;

/**
* Used with {@link NavigationCamera#update(NavigationCameraUpdate)}.
* <p>
* This class wraps a Maps SDK {@link CameraUpdate}. It adds an option
* for {@link CameraUpdateMode} that determine how the camera update behaves
* with tracking modes.
*/
public class NavigationCameraUpdate {

private final CameraUpdate cameraUpdate;
private CameraUpdateMode mode = CameraUpdateMode.DEFAULT;

/**
* Creates and instance of this class, taking a {@link CameraUpdate}
* that has already been built.
*
* @param cameraUpdate with map camera parameters
*/
public NavigationCameraUpdate(@NonNull CameraUpdate cameraUpdate) {
this.cameraUpdate = cameraUpdate;
}

/**
* Updates the {@link CameraUpdateMode} that will determine this updates
* behavior based on the current tracking mode in {@link NavigationCamera}.
*
* @param mode either default or override
*/
public void setMode(CameraUpdateMode mode) {
this.mode = mode;
}

@NonNull
CameraUpdate getCameraUpdate() {
return cameraUpdate;
}

@NonNull
CameraUpdateMode getMode() {
return mode;
}
}
Loading

0 comments on commit a39cf73

Please sign in to comment.