didChangeAppLifecycleState method
Called when the system puts the app in the background or returns the app to the foreground.
An example of implementing this method is provided in the class-level documentation for the WidgetsBindingObserver class.
This method exposes notifications from SystemChannels.lifecycle.
See also:
- AppLifecycleListener, an alternative API for responding to application lifecycle changes.
Implementation
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
// The session observes the lifecycle itself (D11).
if (state == AppLifecycleState.resumed) {
// The trampoline relaunches the host's Activity, so a warm debug-settings
// deeplink arrives here rather than as a route push.
unawaited(_consumeRelayedDebugDeepLink());
}
// Pause the PiP's player and close its open expanded span while the app is
// away, so `engaged_ms` counts only time the window was actually watchable.
// Without this the span stays open across the whole background stretch.
//
// `inactive` is deliberately excluded: it fires for transient interruptions
// the user is still looking through — the app switcher, an incoming call,
// Control Centre — and pausing playback for those would stutter the window
// on every glance. `hidden` and `paused` are the real "no longer on screen"
// signals, which is where Android's ON_STOP draws the same line.
switch (state) {
case AppLifecycleState.resumed:
_pipOrchestrator.setAppForegrounded(true);
_floaterStoryOrchestrator.setAppForegrounded(true);
case AppLifecycleState.hidden:
case AppLifecycleState.paused:
case AppLifecycleState.detached:
case AppLifecycleState.inactive:
_coordinator.noteAppLeftForeground();
_pipOrchestrator.setAppForegrounded(false);
_floaterStoryOrchestrator.setAppForegrounded(false);
break;
}
// detached = permanent process destruction. Not paused (every background).
_services?.analyticsService.appLifecycleChanged(state);
if (state == AppLifecycleState.detached) {
final plugin = _activePlugin;
if (plugin != null) {
// Same ordering as register(): settle what the plugin owns while its
// bridge is alive, then tear it down.
_coordinator.detach(plugin.id);
plugin.detach();
}
_activePlugin = null;
}
// Closes/reopens the live-test stream on background/resume so a stale
// presence lease isn't held between heartbeats.
_services?.liveTestService.onAppLifecycleChanged(state);
}