[core, darwin, android] Add onDidEnterIdle to MapObserver.
didEnterIdle fires whenever render completes and no repaint is scheduled.
This commit is contained in:
@@ -39,6 +39,7 @@ public:
|
||||
virtual void onDidFinishRenderingMap(RenderMode) {}
|
||||
virtual void onDidFinishLoadingStyle() {}
|
||||
virtual void onSourceChanged(style::Source&) {}
|
||||
virtual void onDidEnterIdle() {}
|
||||
};
|
||||
|
||||
} // namespace mbgl
|
||||
|
||||
@@ -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<>();
|
||||
@@ -170,6 +172,20 @@ class MapChangeReceiver implements NativeMapView.StateCallback {
|
||||
}
|
||||
}
|
||||
|
||||
@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 {
|
||||
@@ -278,6 +294,14 @@ class MapChangeReceiver implements NativeMapView.StateCallback {
|
||||
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);
|
||||
}
|
||||
@@ -305,6 +329,7 @@ class MapChangeReceiver implements NativeMapView.StateCallback {
|
||||
onDidFinishRenderingFrameList.clear();
|
||||
onWillStartRenderingMapListenerList.clear();
|
||||
onDidFinishRenderingMapListenerList.clear();
|
||||
onDidEnterIdleListenerList.clear();
|
||||
onDidFinishLoadingStyleListenerList.clear();
|
||||
onSourceChangedListenerList.clear();
|
||||
}
|
||||
|
||||
@@ -691,12 +691,32 @@ public class MapView extends FrameLayout implements NativeMapView.ViewCallback {
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
@@ -870,6 +890,19 @@ public class MapView extends FrameLayout implements NativeMapView.ViewCallback {
|
||||
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>
|
||||
|
||||
@@ -1009,6 +1009,11 @@ final class NativeMapView {
|
||||
}
|
||||
}
|
||||
|
||||
@Keep
|
||||
private void onDidEnterIdle() {
|
||||
stateCallback.onDidEnterIdle();
|
||||
}
|
||||
|
||||
@Keep
|
||||
private void onDidFinishLoadingStyle() {
|
||||
if (stateCallback != null) {
|
||||
@@ -1472,6 +1477,8 @@ final class NativeMapView {
|
||||
|
||||
void onDidFinishRenderingMap(boolean fully);
|
||||
|
||||
void onDidEnterIdle();
|
||||
|
||||
void onSourceChanged(String sourceId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,6 +55,9 @@ public class MapChangeReceiverTest {
|
||||
@Mock
|
||||
private MapView.OnDidFinishRenderingMapListener onDidFinishRenderingMapListener;
|
||||
|
||||
@Mock
|
||||
private MapView.OnDidEnterIdleListener onDidEnterIdleListener;
|
||||
|
||||
@Mock
|
||||
private MapView.OnDidFinishLoadingStyleListener onDidFinishLoadingStyleListener;
|
||||
|
||||
@@ -491,6 +494,36 @@ public class MapChangeReceiverTest {
|
||||
}
|
||||
}
|
||||
|
||||
@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);
|
||||
|
||||
@@ -32,6 +32,7 @@ public class MapChangeActivity extends AppCompatActivity {
|
||||
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"));
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -67,6 +67,7 @@ public:
|
||||
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;
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -934,6 +934,16 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
- (void)mapViewDidEnterIdle {
|
||||
if (!_mbglMap) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ([self.delegate respondsToSelector:@selector(mapViewDidEnterIdle)]) {
|
||||
[self.delegate mapViewDidEnterIdle:self];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)mapViewDidFinishLoadingStyle {
|
||||
if (!_mbglMap) {
|
||||
return;
|
||||
@@ -3050,6 +3060,10 @@ public:
|
||||
bool fullyRendered = mode == mbgl::MapObserver::RenderMode::Full;
|
||||
[nativeView mapViewDidFinishRenderingMapFullyRendered:fullyRendered];
|
||||
}
|
||||
|
||||
void onDidEnterIdle() override {
|
||||
[nativeView mapViewDidEnterIdle];
|
||||
}
|
||||
|
||||
void onDidFinishLoadingStyle() override {
|
||||
[nativeView mapViewDidFinishLoadingStyle];
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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) {}
|
||||
|
||||
|
||||
6
scripts/changelog_staging/idle-event.json
Normal file
6
scripts/changelog_staging/idle-event.json
Normal file
@@ -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
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user