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

Commit

Permalink
[core, darwin, android] Add onDidEnterIdle to MapObserver.
Browse files Browse the repository at this point in the history
didEnterIdle fires whenever render completes and no repaint is scheduled.
  • Loading branch information
ChrisLoer committed Dec 11, 2018
1 parent 13e117b commit 70c2d5a
Show file tree
Hide file tree
Showing 14 changed files with 161 additions and 1 deletion.
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 onDidEnterIdle() {}
};

} // 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.OnDidEnterIdleListener> onDidEnterIdleListenerList
= 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 onDidEnterIdle() {
try {
if (!onDidEnterIdleListenerList.isEmpty()) {
for (MapView.OnDidEnterIdleListener listener : onDidEnterIdleListenerList) {
listener.onDidEnterIdle();
}
}
} catch (Throwable err) {
Logger.e(TAG, "Exception in onDidEnterIdle", err);
throw err;
}
}

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

void addOnDidEnterIdleListener(MapView.OnDidEnterIdleListener listener) {
onDidEnterIdleListenerList.add(listener);
}

void removeOnDidEnterIdleListener(MapView.OnDidEnterIdleListener listener) {
onDidEnterIdleListenerList.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();
onDidEnterIdleListenerList.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 addOnDidEnterIdleListener(OnDidEnterIdleListener listener) {
mapChangeReceiver.addOnDidEnterIdleListener(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 removeOnDidEnterIdleListener(OnDidEnterIdleListener listener) {
mapChangeReceiver.removeOnDidEnterIdleListener(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#addOnDidEnterIdleListener(OnDidEnterIdleListener)}
* </p>
*/
public interface OnDidEnterIdleListener {
/**
* Called when the map has entered the idle state.
*/
void onDidEnterIdle();
}

/**
* 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 @@ -1009,6 +1009,11 @@ private void onDidFinishRenderingMap(boolean fully) {
}
}

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

@Keep
private void onDidFinishLoadingStyle() {
if (stateCallback != null) {
Expand Down Expand Up @@ -1472,6 +1477,8 @@ interface StateCallback extends StyleCallback {

void onDidFinishRenderingMap(boolean fully);

void onDidEnterIdle();

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.OnDidEnterIdleListener onDidEnterIdleListener;

@Mock
private MapView.OnDidFinishLoadingStyleListener onDidFinishLoadingStyleListener;

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

@Test
public void testOnDidEnterIdleListener() {
mapChangeEventManager.addOnDidEnterIdleListener(onDidEnterIdleListener);
mapChangeEventManager.onDidEnterIdle();
verify(onDidEnterIdleListener).onDidEnterIdle();
mapChangeEventManager.removeOnDidEnterIdleListener(onDidEnterIdleListener);
mapChangeEventManager.onDidEnterIdle();
verify(onDidEnterIdleListener).onDidEnterIdle();

mapChangeEventManager.addOnDidEnterIdleListener(onDidEnterIdleListener);
Logger.setLoggerDefinition(loggerDefinition);
Exception exc = new RuntimeException();
doThrow(exc).when(onDidEnterIdleListener).onDidEnterIdle();
try {
mapChangeEventManager.onDidEnterIdle();
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(onDidEnterIdleListener).onDidEnterIdle();
try {
mapChangeEventManager.onDidEnterIdle();
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.addOnDidEnterIdleListener(() -> Timber.v("OnDidEnterIdle"));
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::onDidEnterIdle() {
assert(vm != nullptr);

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

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 onDidEnterIdle() 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)mapViewDidEnterIdle:(MGLMapView *)mapView;

/**
Tells the delegate that the map has just finished loading a style.
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)mapViewDidEnterIdle {
if (!_mbglMap) {
return;
}

if ([self.delegate respondsToSelector:@selector(mapViewDidEnterIdle)]) {
[self.delegate mapViewDidEnterIdle: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 onDidEnterIdle() override {
[nativeView mapViewDidEnterIdle];
}

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)mapViewDidEnterIdle:(MGLMapView *)mapView;

/**
Tells the delegate that the map has just finished loading a style.
Expand Down
2 changes: 2 additions & 0 deletions platform/macos/test/MGLMapViewDelegateIntegrationTests.swift
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 mapViewDidEnterIdle(_ 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.onDidEnterIdle();
}
} else if (stillImageRequest && rendererFullyLoaded) {
auto request = std::move(stillImageRequest);
Expand Down

0 comments on commit 70c2d5a

Please sign in to comment.