Skip to content

Commit cb7d61e

Browse files
fix!: native state issues on Android when multiple engines are used (#525)
* refactoring android navigator instance management * BREAKING CHANGE: On Android `GoogleMapsNavigator.initializeNavigationSession` method must be called again after `cleanUp` --------- Co-authored-by: Ville Välimaa <[email protected]>
1 parent b53bbf0 commit cb7d61e

File tree

25 files changed

+648
-314
lines changed

25 files changed

+648
-314
lines changed

.github/workflows/test-and-build.yaml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,17 @@ jobs:
276276
run: flutter pub global activate patrol_cli ${{ env.patrol_cli_version }}
277277
- name: Run flutter pub get
278278
run: flutter pub get
279+
- name: Clean up runner disk space (if needed)
280+
run: |
281+
echo "Running cleanup..."
282+
283+
# Remove large, unneeded packages
284+
sudo rm -rf /usr/share/dotnet
285+
sudo rm -rf /opt/ghc
286+
sudo rm -rf /usr/local/share/boost
287+
288+
echo "Cleanup complete. Free space after cleanup:"
289+
df -h
279290
- name: Create and start emulator
280291
run: |
281292
echo "Installing system image"

android/src/main/kotlin/com/google/maps/flutter/navigation/AndroidAutoBaseScreen.kt

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -56,12 +56,8 @@ open class AndroidAutoBaseScreen(carContext: CarContext) :
5656
private fun initializeNavigationListener() {
5757
GoogleMapsNavigationSessionManager.navigationReadyListener = this
5858
mIsNavigationReady =
59-
try {
60-
GoogleMapsNavigationSessionManager.getInstance().isInitialized()
61-
} catch (exception: RuntimeException) {
62-
// If GoogleMapsNavigationSessionManager is not initialized navigation is not ready.
63-
false
64-
}
59+
GoogleMapsNavigatorHolder.getInitializationState() ==
60+
GoogleNavigatorInitializationState.INITIALIZED
6561
}
6662

6763
private fun initializeSurfaceCallback() {

android/src/main/kotlin/com/google/maps/flutter/navigation/GoogleMapsNavigationInspectorHandler.kt

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,11 @@ package com.google.maps.flutter.navigation
1616

1717
class GoogleMapsNavigationInspectorHandler(private val viewRegistry: GoogleMapsViewRegistry) :
1818
NavigationInspector {
19-
private fun manager(): GoogleMapsNavigationSessionManager {
20-
return GoogleMapsNavigationSessionManager.getInstance()
21-
}
22-
2319
override fun isViewAttachedToSession(viewId: Long): Boolean {
2420
/// Is session exists, it's automatically attached to any existing view.
2521
if (viewRegistry.getNavigationView(viewId.toInt()) != null) {
26-
return manager().isInitialized()
22+
return GoogleMapsNavigatorHolder.getInitializationState() ==
23+
GoogleNavigatorInitializationState.INITIALIZED
2724
}
2825
return false
2926
}

android/src/main/kotlin/com/google/maps/flutter/navigation/GoogleMapsNavigationPlugin.kt

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package com.google.maps.flutter.navigation
1818

19+
import android.app.Application
1920
import androidx.lifecycle.Lifecycle
2021
import io.flutter.embedding.engine.plugins.FlutterPlugin
2122
import io.flutter.embedding.engine.plugins.activity.ActivityAware
@@ -25,10 +26,11 @@ import io.flutter.embedding.engine.plugins.lifecycle.FlutterLifecycleAdapter
2526
/** GoogleMapsNavigationPlugin */
2627
class GoogleMapsNavigationPlugin : FlutterPlugin, ActivityAware {
2728
companion object {
28-
private var instance: GoogleMapsNavigationPlugin? = null
29+
private val instances = mutableListOf<GoogleMapsNavigationPlugin>()
2930

31+
/** Returns the first instance, which should always be the main Flutter engine. */
3032
fun getInstance(): GoogleMapsNavigationPlugin? {
31-
return instance
33+
return instances.firstOrNull()
3234
}
3335
}
3436

@@ -40,11 +42,12 @@ class GoogleMapsNavigationPlugin : FlutterPlugin, ActivityAware {
4042
private var viewMessageHandler: GoogleMapsViewMessageHandler? = null
4143
private var imageRegistryMessageHandler: GoogleMapsImageRegistryMessageHandler? = null
4244
private var autoViewMessageHandler: GoogleMapsAutoViewMessageHandler? = null
45+
internal var sessionManager: GoogleMapsNavigationSessionManager? = null
4346

4447
private var lifecycle: Lifecycle? = null
4548

4649
override fun onAttachedToEngine(binding: FlutterPlugin.FlutterPluginBinding) {
47-
instance = this
50+
synchronized(instances) { instances.add(this) }
4851

4952
// Init view registry and its method channel handlers
5053
viewRegistry = GoogleMapsViewRegistry()
@@ -57,18 +60,25 @@ class GoogleMapsNavigationPlugin : FlutterPlugin, ActivityAware {
5760
imageRegistryMessageHandler = GoogleMapsImageRegistryMessageHandler(imageRegistry!!)
5861
ImageRegistryApi.setUp(binding.binaryMessenger, imageRegistryMessageHandler)
5962

63+
// Setup auto map view method channel handlers
64+
autoViewMessageHandler = GoogleMapsAutoViewMessageHandler(viewRegistry!!)
65+
AutoMapViewApi.setUp(binding.binaryMessenger, autoViewMessageHandler)
66+
autoViewEventApi = AutoViewEventApi(binding.binaryMessenger)
67+
68+
// Setup navigation session manager
69+
val app = binding.applicationContext as Application
70+
val navigationSessionEventApi = NavigationSessionEventApi(binding.binaryMessenger)
71+
sessionManager = GoogleMapsNavigationSessionManager(navigationSessionEventApi, app)
72+
6073
// Setup platform view factory and its method channel handlers
6174
viewEventApi = ViewEventApi(binding.binaryMessenger)
6275
val factory = GoogleMapsViewFactory(viewRegistry!!, viewEventApi!!, imageRegistry!!)
6376
binding.platformViewRegistry.registerViewFactory("google_navigation_flutter", factory)
6477

65-
// Setup auto map view method channel handlers
66-
autoViewMessageHandler = GoogleMapsAutoViewMessageHandler(viewRegistry!!)
67-
AutoMapViewApi.setUp(binding.binaryMessenger, autoViewMessageHandler)
68-
autoViewEventApi = AutoViewEventApi(binding.binaryMessenger)
78+
// Setup navigation session message handler with this instance's session manager
79+
val sessionMessageHandler = GoogleMapsNavigationSessionMessageHandler(sessionManager!!)
80+
NavigationSessionApi.setUp(binding.binaryMessenger, sessionMessageHandler)
6981

70-
// Setup navigation session manager and its method channel handlers
71-
GoogleMapsNavigationSessionManager.createInstance(binding.binaryMessenger)
7282
val inspectorHandler = GoogleMapsNavigationInspectorHandler(viewRegistry!!)
7383
NavigationInspector.setUp(binding.binaryMessenger, inspectorHandler)
7484
}
@@ -80,36 +90,37 @@ class GoogleMapsNavigationPlugin : FlutterPlugin, ActivityAware {
8090
AutoMapViewApi.setUp(binding.binaryMessenger, null)
8191
NavigationInspector.setUp(binding.binaryMessenger, null)
8292

83-
GoogleMapsNavigationSessionManager.destroyInstance()
8493
binding.applicationContext.unregisterComponentCallbacks(viewRegistry)
8594

8695
// Cleanup references
96+
sessionManager = null
8797
viewRegistry = null
8898
viewMessageHandler = null
8999
imageRegistryMessageHandler = null
90100
viewEventApi = null
91101
imageRegistry = null
92102
autoViewMessageHandler = null
93103
autoViewEventApi = null
94-
instance = null
104+
105+
synchronized(instances) { instances.remove(this) }
95106
}
96107

97108
private fun attachActivity(binding: ActivityPluginBinding) {
98109
lifecycle =
99110
FlutterLifecycleAdapter.getActivityLifecycle(binding).also { lc ->
100111
viewRegistry?.let(lc::addObserver)
101-
GoogleMapsNavigationSessionManager.getInstanceOrNull()?.let(lc::addObserver)
112+
sessionManager?.let(lc::addObserver)
102113
}
103-
GoogleMapsNavigationSessionManager.getInstanceOrNull()?.onActivityCreated(binding.activity)
114+
sessionManager?.onActivityCreated(binding.activity)
104115
}
105116

106117
private fun detachActivity(forConfigChange: Boolean) {
107118
lifecycle?.let { lc ->
108119
viewRegistry?.let(lc::removeObserver)
109-
GoogleMapsNavigationSessionManager.getInstanceOrNull()?.let(lc::removeObserver)
120+
sessionManager?.let(lc::removeObserver)
110121
}
111122

112-
GoogleMapsNavigationSessionManager.getInstanceOrNull()?.onActivityDestroyed(forConfigChange)
123+
sessionManager?.onActivityDestroyed(forConfigChange)
113124
lifecycle = null
114125
}
115126

0 commit comments

Comments
 (0)