Skip to content
This repository has been archived by the owner on Aug 8, 2023. It is now read-only.

[core, darwin, android] Add onDidBecomeIdle to MapObserver. #13513

Merged
merged 2 commits into from
Dec 11, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions include/mbgl/map/map_observer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ class MapObserver {
virtual void onDidFinishRenderingMap(RenderMode) {}
virtual void onDidFinishLoadingStyle() {}
virtual void onSourceChanged(style::Source&) {}
virtual void onDidBecomeIdle() {}
};

} // namespace mbgl
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ class MapChangeReceiver implements NativeMapView.StateCallback {
= new CopyOnWriteArrayList<>();
private final List<MapView.OnDidFinishRenderingMapListener> onDidFinishRenderingMapListenerList
= new CopyOnWriteArrayList<>();
private final List<MapView.OnDidBecomeIdleListener> onDidBecomeIdleListenerList
= new CopyOnWriteArrayList<>();
private final List<MapView.OnDidFinishLoadingStyleListener> onDidFinishLoadingStyleListenerList
= new CopyOnWriteArrayList<>();
private final List<MapView.OnSourceChangedListener> onSourceChangedListenerList = new CopyOnWriteArrayList<>();
Expand Down Expand Up @@ -170,6 +172,20 @@ public void onDidFinishRenderingMap(boolean fully) {
}
}

@Override
public void onDidBecomeIdle() {
try {
if (!onDidBecomeIdleListenerList.isEmpty()) {
for (MapView.OnDidBecomeIdleListener listener : onDidBecomeIdleListenerList) {
listener.onDidBecomeIdle();
}
}
} catch (Throwable err) {
Logger.e(TAG, "Exception in onDidBecomeIdle", err);
throw err;
}
}

@Override
public void onDidFinishLoadingStyle() {
try {
Expand Down Expand Up @@ -278,6 +294,14 @@ void removeOnDidFinishRenderingMapListener(MapView.OnDidFinishRenderingMapListen
onDidFinishRenderingMapListenerList.remove(listener);
}

void addOnDidBecomeIdleListener(MapView.OnDidBecomeIdleListener listener) {
onDidBecomeIdleListenerList.add(listener);
}

void removeOnDidBecomeIdleListener(MapView.OnDidBecomeIdleListener listener) {
onDidBecomeIdleListenerList.remove(listener);
}

void addOnDidFinishLoadingStyleListener(MapView.OnDidFinishLoadingStyleListener listener) {
onDidFinishLoadingStyleListenerList.add(listener);
}
Expand Down Expand Up @@ -305,6 +329,7 @@ void clear() {
onDidFinishRenderingFrameList.clear();
onWillStartRenderingMapListenerList.clear();
onDidFinishRenderingMapListenerList.clear();
onDidBecomeIdleListenerList.clear();
onDidFinishLoadingStyleListenerList.clear();
onSourceChangedListenerList.clear();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -691,12 +691,32 @@ public void addOnDidFinishRenderingMapListener(OnDidFinishRenderingMapListener l
/**
* Remove a callback that's invoked when the map has finished rendering.
*
* @param listener The callback that's invoked when the map has finished rendering
* @param listener The callback that's invoked when the map has has finished rendering.
*/
public void removeOnDidFinishRenderingMapListener(OnDidFinishRenderingMapListener listener) {
mapChangeReceiver.removeOnDidFinishRenderingMapListener(listener);
}

/**
* Set a callback that's invoked when the map has entered the idle state.
*
* @param listener The callback that's invoked when the map has entered the idle state.
*/
public void addOnDidBecomeIdleListener(OnDidBecomeIdleListener listener) {
mapChangeReceiver.addOnDidBecomeIdleListener(listener);
}

/**
* Remove a callback that's invoked when the map has entered the idle state.
*
* @param listener The callback that's invoked when the map has entered the idle state.
*/
public void removeOnDidBecomeIdleListener(OnDidBecomeIdleListener listener) {
mapChangeReceiver.removeOnDidBecomeIdleListener(listener);
}

/**

/**
* Set a callback that's invoked when the style has finished loading.
*
Expand Down Expand Up @@ -870,6 +890,19 @@ public interface OnDidFinishRenderingMapListener {
void onDidFinishRenderingMap(boolean fully);
}

/**
* Interface definition for a callback to be invoked when the map has entered the idle state.
* <p>
* {@link MapView#addOnDidBecomeIdleListener(OnDidBecomeIdleListener)}
* </p>
*/
public interface OnDidBecomeIdleListener {
/**
* Called when the map has entered the idle state.
*/
void onDidBecomeIdle();
}

/**
* Interface definition for a callback to be invoked when the map has loaded the style.
* <p>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -970,6 +970,11 @@ private void onDidFinishRenderingMap(boolean fully) {
stateCallback.onDidFinishRenderingMap(fully);
}

@Keep
private void onDidBecomeIdle() {
stateCallback.onDidBecomeIdle();
}

@Keep
private void onDidFinishLoadingStyle() {
stateCallback.onDidFinishLoadingStyle();
Expand Down Expand Up @@ -1426,6 +1431,8 @@ interface StateCallback extends StyleCallback {

void onDidFinishRenderingMap(boolean fully);

void onDidBecomeIdle();

void onSourceChanged(String sourceId);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ public class MapChangeReceiverTest {
@Mock
private MapView.OnDidFinishRenderingMapListener onDidFinishRenderingMapListener;

@Mock
private MapView.OnDidBecomeIdleListener onDidBecomeIdleListener;

@Mock
private MapView.OnDidFinishLoadingStyleListener onDidFinishLoadingStyleListener;

Expand Down Expand Up @@ -491,6 +494,36 @@ public void testOnDidFinishRenderingMapFullyRenderedListener() {
}
}

@Test
public void testOnDidBecomeIdleListener() {
mapChangeEventManager.addOnDidBecomeIdleListener(onDidBecomeIdleListener);
mapChangeEventManager.onDidBecomeIdle();
verify(onDidBecomeIdleListener).onDidBecomeIdle();
mapChangeEventManager.removeOnDidBecomeIdleListener(onDidBecomeIdleListener);
mapChangeEventManager.onDidBecomeIdle();
verify(onDidBecomeIdleListener).onDidBecomeIdle();

mapChangeEventManager.addOnDidBecomeIdleListener(onDidBecomeIdleListener);
Logger.setLoggerDefinition(loggerDefinition);
Exception exc = new RuntimeException();
doThrow(exc).when(onDidBecomeIdleListener).onDidBecomeIdle();
try {
mapChangeEventManager.onDidBecomeIdle();
Assert.fail("The exception should've been re-thrown.");
} catch (RuntimeException throwable) {
verify(loggerDefinition).e(anyString(), anyString(), eq(exc));
}

Error err = new ExecutionError("", new Error());
doThrow(err).when(onDidBecomeIdleListener).onDidBecomeIdle();
try {
mapChangeEventManager.onDidBecomeIdle();
Assert.fail("The exception should've been re-thrown.");
} catch (ExecutionError throwable) {
verify(loggerDefinition).e(anyString(), anyString(), eq(err));
}
}

@Test
public void testOnDidFinishLoadingStyleListener() {
mapChangeEventManager.addOnDidFinishLoadingStyleListener(onDidFinishLoadingStyleListener);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ protected void onCreate(Bundle savedInstanceState) {
mapView.addOnDidFinishLoadingStyleListener(() -> Timber.v("OnDidFinishLoadingStyle"));
mapView.addOnDidFinishRenderingFrameListener(fully -> Timber.v("OnDidFinishRenderingFrame: fully: %s", fully));
mapView.addOnDidFinishRenderingMapListener(fully -> Timber.v("OnDidFinishRenderingMap: fully: %s", fully));
mapView.addOnDidBecomeIdleListener(() -> Timber.v("OnDidBecomeIdle"));
mapView.addOnSourceChangedListener(sourceId -> Timber.v("OnSourceChangedListener: source with id: %s", sourceId));
mapView.addOnWillStartLoadingMapListener(() -> Timber.v("OnWillStartLoadingMap"));
mapView.addOnWillStartRenderingFrameListener(() -> Timber.v("OnWillStartRenderingFrame"));
Expand Down
9 changes: 9 additions & 0 deletions platform/android/src/native_map_view.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,15 @@ void NativeMapView::onDidFinishRenderingMap(MapObserver::RenderMode mode) {
javaPeer.get(*_env).Call(*_env, onDidFinishRenderingMap, (jboolean) (mode != MapObserver::RenderMode::Partial));
}

void NativeMapView::onDidBecomeIdle() {
assert(vm != nullptr);

android::UniqueEnv _env = android::AttachEnv();
static auto& javaClass = jni::Class<NativeMapView>::Singleton(*_env);
static auto onDidBecomeIdle = javaClass.GetMethod<void ()>(*_env, "onDidBecomeIdle");
javaPeer.get(*_env).Call(*_env, onDidBecomeIdle);
}

void NativeMapView::onDidFinishLoadingStyle() {
assert(vm != nullptr);

Expand Down
1 change: 1 addition & 0 deletions platform/android/src/native_map_view.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ class NativeMapView : public MapObserver {
void onDidFinishRenderingFrame(MapObserver::RenderMode) override;
void onWillStartRenderingMap() override;
void onDidFinishRenderingMap(MapObserver::RenderMode) override;
void onDidBecomeIdle() override;
void onDidFinishLoadingStyle() override;
void onSourceChanged(mbgl::style::Source&) override;

Expand Down
13 changes: 13 additions & 0 deletions platform/ios/src/MGLMapViewDelegate.h
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,19 @@ NS_ASSUME_NONNULL_BEGIN
*/
- (void)mapViewDidFinishRenderingFrame:(MGLMapView *)mapView fullyRendered:(BOOL)fullyRendered;

/**
Tells the delegate that the map view is entering an idle state, and no more
drawing will be necessary until new data is loaded or there is some interaction
with the map.

- No camera transitions are in progress
- All currently requested tiles have loaded
- All fade/transition animations have completed

@param mapView The map view that has just entered the idle state.
*/
- (void)mapViewDidBecomeIdle:(MGLMapView *)mapView;

/**
Tells the delegate that the map has just finished loading a style.

Expand Down
2 changes: 2 additions & 0 deletions platform/ios/test/MGLMapViewDelegateIntegrationTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ extension MGLMapViewDelegateIntegrationTests: MGLMapViewDelegate {
func mapView(_ mapView: MGLMapView, didUpdate userLocation: MGLUserLocation?) {}

func mapViewDidFinishRenderingMap(_ mapView: MGLMapView, fullyRendered: Bool) {}

func mapViewDidBecomeIdle(_ mapView: MGLMapView) {}

func mapView(_ mapView: MGLMapView, didFailToLocateUserWithError error: Error) {}

Expand Down
14 changes: 14 additions & 0 deletions platform/macos/src/MGLMapView.mm
Original file line number Diff line number Diff line change
Expand Up @@ -934,6 +934,16 @@ - (void)mapViewDidFinishRenderingMapFullyRendered:(BOOL)fullyRendered {
}
}

- (void)mapViewDidBecomeIdle {
if (!_mbglMap) {
return;
}

if ([self.delegate respondsToSelector:@selector(mapViewDidBecomeIdle)]) {
[self.delegate mapViewDidBecomeIdle:self];
}
}

- (void)mapViewDidFinishLoadingStyle {
if (!_mbglMap) {
return;
Expand Down Expand Up @@ -3050,6 +3060,10 @@ void onDidFinishRenderingMap(mbgl::MapObserver::RenderMode mode) override {
bool fullyRendered = mode == mbgl::MapObserver::RenderMode::Full;
[nativeView mapViewDidFinishRenderingMapFullyRendered:fullyRendered];
}

void onDidBecomeIdle() override {
[nativeView mapViewDidBecomeIdle];
}

void onDidFinishLoadingStyle() override {
[nativeView mapViewDidFinishLoadingStyle];
Expand Down
13 changes: 13 additions & 0 deletions platform/macos/src/MGLMapViewDelegate.h
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,19 @@ NS_ASSUME_NONNULL_BEGIN
*/
- (void)mapViewDidFinishRenderingFrame:(MGLMapView *)mapView fullyRendered:(BOOL)fullyRendered;

/**
Tells the delegate that the map view is entering an idle state, and no more
drawing will be necessary until new data is loaded or there is some interaction
with the map.

- No camera transitions are in progress
- All currently requested tiles have loaded
- All fade/transition animations have completed

@param mapView The map view that has just entered the idle state.
*/
- (void)mapViewDidBecomeIdle:(MGLMapView *)mapView;

/**
Tells the delegate that the map has just finished loading a style.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ extension MGLMapViewDelegateIntegrationTests: MGLMapViewDelegate {
func mapViewDidFinishRenderingFrame(_ mapView: MGLMapView, fullyRendered: Bool) {}

func mapViewDidFinishRenderingMap(_ mapView: MGLMapView, fullyRendered: Bool) {}

func mapViewDidBecomeIdle(_ mapView: MGLMapView) {}

func mapViewDidFailLoadingMap(_ mapView: MGLMapView, withError error: Error) {}

Expand Down
6 changes: 6 additions & 0 deletions scripts/changelog_staging/idle-event.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"core": "Add onDidEnterIdle to MapObserver, which fires whenever render completes and no repaint is scheduled.",
"darwin": "Add mapViewDidEnterIdle to MGLMapViewDelegate, which fires whenever render completes and no repaint is scheduled.",
"android": "Add onDidEnterIdle listener to MapView, which fires whenever render completes and no repaint is scheduled.",
"issue": 13469
}
2 changes: 2 additions & 0 deletions src/mbgl/map/map.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,8 @@ void Map::Impl::onDidFinishRenderingFrame(RenderMode renderMode, bool needsRepai

if (needsRepaint || transform.inTransition()) {
onUpdate();
} else if (rendererFullyLoaded) {
observer.onDidBecomeIdle();
}
} else if (stillImageRequest && rendererFullyLoaded) {
auto request = std::move(stillImageRequest);
Expand Down