expo-gaode-map-navigation 2.0.8 → 2.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +233 -3
- package/android/src/main/java/expo/modules/gaodemap/map/ExpoGaodeMapModule.kt +4 -2
- package/android/src/main/java/expo/modules/gaodemap/navigation/ExpoGaodeMapNaviView.kt +931 -391
- package/android/src/main/java/expo/modules/gaodemap/navigation/ExpoGaodeMapNaviViewModule.kt +86 -1
- package/android/src/main/java/expo/modules/gaodemap/navigation/ExpoGaodeMapNavigationModule.kt +4 -5
- package/android/src/main/java/expo/modules/gaodemap/navigation/listeners/IndependentRouteListener.kt +4 -3
- package/android/src/main/java/expo/modules/gaodemap/navigation/listeners/RouteCalculateListener.kt +2 -2
- package/android/src/main/java/expo/modules/gaodemap/navigation/managers/IndependentRouteManager.kt +96 -14
- package/android/src/main/java/expo/modules/gaodemap/navigation/routes/drive/DriveTruckRouteCalculator.kt +2 -0
- package/android/src/main/java/expo/modules/gaodemap/navigation/utils/Converters.kt +19 -10
- package/android/src/main/res/drawable/landback_0.png +0 -0
- package/android/src/main/res/drawable/landback_1.png +0 -0
- package/android/src/main/res/drawable/landback_2.png +0 -0
- package/android/src/main/res/drawable/landback_3.png +0 -0
- package/android/src/main/res/drawable/landback_4.png +0 -0
- package/android/src/main/res/drawable/landback_5.png +0 -0
- package/android/src/main/res/drawable/landback_6.png +0 -0
- package/android/src/main/res/drawable/landback_7.png +0 -0
- package/android/src/main/res/drawable/landback_8.png +0 -0
- package/android/src/main/res/drawable/landback_9.png +0 -0
- package/android/src/main/res/drawable/landback_a.png +0 -0
- package/android/src/main/res/drawable/landback_b.png +0 -0
- package/android/src/main/res/drawable/landback_c.png +0 -0
- package/android/src/main/res/drawable/landback_d.png +0 -0
- package/android/src/main/res/drawable/landback_e.png +0 -0
- package/android/src/main/res/drawable/landback_f.png +0 -0
- package/android/src/main/res/drawable/landback_g.png +0 -0
- package/android/src/main/res/drawable/landback_h.png +0 -0
- package/android/src/main/res/drawable/landback_i.png +0 -0
- package/android/src/main/res/drawable/landback_j.png +0 -0
- package/android/src/main/res/drawable/landback_k.png +0 -0
- package/android/src/main/res/drawable/landback_l.png +0 -0
- package/android/src/main/res/drawable/landfront_0.png +0 -0
- package/android/src/main/res/drawable/landfront_00.png +0 -0
- package/android/src/main/res/drawable/landfront_1.png +0 -0
- package/android/src/main/res/drawable/landfront_11.png +0 -0
- package/android/src/main/res/drawable/landfront_20.png +0 -0
- package/android/src/main/res/drawable/landfront_21.png +0 -0
- package/android/src/main/res/drawable/landfront_22.png +0 -0
- package/android/src/main/res/drawable/landfront_3.png +0 -0
- package/android/src/main/res/drawable/landfront_33.png +0 -0
- package/android/src/main/res/drawable/landfront_40.png +0 -0
- package/android/src/main/res/drawable/landfront_43.png +0 -0
- package/android/src/main/res/drawable/landfront_44.png +0 -0
- package/android/src/main/res/drawable/landfront_5.png +0 -0
- package/android/src/main/res/drawable/landfront_55.png +0 -0
- package/android/src/main/res/drawable/landfront_61.png +0 -0
- package/android/src/main/res/drawable/landfront_63.png +0 -0
- package/android/src/main/res/drawable/landfront_66.png +0 -0
- package/android/src/main/res/drawable/landfront_70.png +0 -0
- package/android/src/main/res/drawable/landfront_71.png +0 -0
- package/android/src/main/res/drawable/landfront_73.png +0 -0
- package/android/src/main/res/drawable/landfront_77.png +0 -0
- package/android/src/main/res/drawable/landfront_8.png +0 -0
- package/android/src/main/res/drawable/landfront_88.png +0 -0
- package/android/src/main/res/drawable/landfront_90.png +0 -0
- package/android/src/main/res/drawable/landfront_95.png +0 -0
- package/android/src/main/res/drawable/landfront_99.png +0 -0
- package/android/src/main/res/drawable/landfront_a0.png +0 -0
- package/android/src/main/res/drawable/landfront_a8.png +0 -0
- package/android/src/main/res/drawable/landfront_aa.png +0 -0
- package/android/src/main/res/drawable/landfront_b1.png +0 -0
- package/android/src/main/res/drawable/landfront_b5.png +0 -0
- package/android/src/main/res/drawable/landfront_bb.png +0 -0
- package/android/src/main/res/drawable/landfront_c3.png +0 -0
- package/android/src/main/res/drawable/landfront_c8.png +0 -0
- package/android/src/main/res/drawable/landfront_cc.png +0 -0
- package/android/src/main/res/drawable/landfront_d.png +0 -0
- package/android/src/main/res/drawable/landfront_dd.png +0 -0
- package/android/src/main/res/drawable/landfront_e1.png +0 -0
- package/android/src/main/res/drawable/landfront_e5.png +0 -0
- package/android/src/main/res/drawable/landfront_ee.png +0 -0
- package/android/src/main/res/drawable/landfront_f0.png +0 -0
- package/android/src/main/res/drawable/landfront_f1.png +0 -0
- package/android/src/main/res/drawable/landfront_f5.png +0 -0
- package/android/src/main/res/drawable/landfront_ff.png +0 -0
- package/android/src/main/res/drawable/landfront_g3.png +0 -0
- package/android/src/main/res/drawable/landfront_g5.png +0 -0
- package/android/src/main/res/drawable/landfront_gg.png +0 -0
- package/android/src/main/res/drawable/landfront_h1.png +0 -0
- package/android/src/main/res/drawable/landfront_h3.png +0 -0
- package/android/src/main/res/drawable/landfront_h5.png +0 -0
- package/android/src/main/res/drawable/landfront_hh.png +0 -0
- package/android/src/main/res/drawable/landfront_i0.png +0 -0
- package/android/src/main/res/drawable/landfront_i3.png +0 -0
- package/android/src/main/res/drawable/landfront_i5.png +0 -0
- package/android/src/main/res/drawable/landfront_ii.png +0 -0
- package/android/src/main/res/drawable/landfront_j1.png +0 -0
- package/android/src/main/res/drawable/landfront_j8.png +0 -0
- package/android/src/main/res/drawable/landfront_jj.png +0 -0
- package/android/src/main/res/drawable/landfront_kk.png +0 -0
- package/android/src/main/res/drawable/landfront_ll.png +0 -0
- package/android/src/main/res/drawable/navi_arrow_leftline.png +0 -0
- package/android/src/main/res/drawable/navi_lane_shape_bg_center.xml +5 -0
- package/android/src/main/res/drawable/navi_lane_shape_bg_left.xml +8 -0
- package/android/src/main/res/drawable/navi_lane_shape_bg_over.xml +6 -0
- package/android/src/main/res/drawable/navi_lane_shape_bg_right.xml +8 -0
- package/build/ExpoGaodeMapNaviView.d.ts +8 -0
- package/build/ExpoGaodeMapNaviView.d.ts.map +1 -1
- package/build/ExpoGaodeMapNaviView.js +38 -1
- package/build/ExpoGaodeMapNaviView.js.map +1 -1
- package/build/index.d.ts +8 -4
- package/build/index.d.ts.map +1 -1
- package/build/index.js +408 -4
- package/build/index.js.map +1 -1
- package/build/types/independent.types.d.ts +91 -0
- package/build/types/independent.types.d.ts.map +1 -1
- package/build/types/independent.types.js.map +1 -1
- package/build/types/naviview.types.d.ts +256 -12
- package/build/types/naviview.types.d.ts.map +1 -1
- package/build/types/naviview.types.js.map +1 -1
- package/build/types/route.types.d.ts +2 -0
- package/build/types/route.types.d.ts.map +1 -1
- package/build/types/route.types.js.map +1 -1
- package/ios/ExpoGaodeMapNaviView.swift +888 -66
- package/ios/ExpoGaodeMapNaviViewModule.swift +87 -1
- package/ios/ExpoGaodeMapNavigationModule.swift +1 -1
- package/ios/managers/IndependentRouteManager.swift +1 -0
- package/ios/map/ExpoGaodeMapModule.swift +9 -4
- package/ios/map/ExpoGaodeMapView.swift +13 -2
- package/ios/map/modules/LocationManager.swift +17 -0
- package/ios/map/utils/PermissionManager.swift +11 -6
- package/ios/routes/drive/DriveTruckRouteCalculator.swift +9 -0
- package/ios/routes/walkride/WalkRideRouteCalculator.swift +30 -0
- package/ios/services/IndependentRouteService.swift +25 -0
- package/package.json +5 -2
|
@@ -2,7 +2,13 @@ package expo.modules.gaodemap.navigation
|
|
|
2
2
|
|
|
3
3
|
import android.annotation.SuppressLint
|
|
4
4
|
import android.content.Context
|
|
5
|
+
import android.graphics.Bitmap
|
|
6
|
+
import android.graphics.BitmapFactory
|
|
7
|
+
import android.graphics.Color
|
|
8
|
+
import android.net.Uri
|
|
5
9
|
import android.os.Bundle
|
|
10
|
+
import android.os.Handler
|
|
11
|
+
import android.os.Looper
|
|
6
12
|
import android.util.Log
|
|
7
13
|
import android.view.View
|
|
8
14
|
import android.view.ViewGroup
|
|
@@ -15,14 +21,42 @@ import com.amap.api.navi.enums.MapStyle
|
|
|
15
21
|
import com.amap.api.navi.enums.NaviType
|
|
16
22
|
import com.amap.api.navi.model.*
|
|
17
23
|
import expo.modules.gaodemap.map.modules.SDKInitializer
|
|
24
|
+
import expo.modules.gaodemap.navigation.managers.IndependentRouteManager
|
|
18
25
|
import expo.modules.kotlin.AppContext
|
|
19
26
|
import expo.modules.kotlin.viewevent.EventDispatcher
|
|
20
27
|
import expo.modules.kotlin.views.ExpoView
|
|
21
|
-
import java.
|
|
28
|
+
import java.io.ByteArrayOutputStream
|
|
29
|
+
import java.io.File
|
|
30
|
+
import java.io.FileOutputStream
|
|
31
|
+
import java.security.MessageDigest
|
|
32
|
+
import java.util.Collections
|
|
33
|
+
import java.util.WeakHashMap
|
|
34
|
+
import java.net.URL
|
|
22
35
|
|
|
23
36
|
@SuppressLint("ViewConstructor")
|
|
24
37
|
@Suppress("DEPRECATION", "OVERRIDE_DEPRECATION")
|
|
25
38
|
class ExpoGaodeMapNaviView(context: Context, appContext: AppContext) : ExpoView(context, appContext) {
|
|
39
|
+
companion object {
|
|
40
|
+
private val activeViews =
|
|
41
|
+
Collections.newSetFromMap(WeakHashMap<ExpoGaodeMapNaviView, Boolean>())
|
|
42
|
+
|
|
43
|
+
private fun snapshotActiveViews(): List<ExpoGaodeMapNaviView> =
|
|
44
|
+
synchronized(activeViews) { activeViews.toList() }
|
|
45
|
+
|
|
46
|
+
fun resumeActiveViews() {
|
|
47
|
+
snapshotActiveViews().forEach { it.onResume() }
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
fun pauseActiveViews() {
|
|
51
|
+
snapshotActiveViews().forEach { it.onPause() }
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
fun destroyActiveViews() {
|
|
55
|
+
snapshotActiveViews().forEach { it.onDestroy() }
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
private val independentRouteManager = IndependentRouteManager.shared
|
|
26
60
|
|
|
27
61
|
// 事件派发器
|
|
28
62
|
private val onNavigationReady by EventDispatcher()
|
|
@@ -38,6 +72,9 @@ class ExpoGaodeMapNaviView(context: Context, appContext: AppContext) : ExpoView(
|
|
|
38
72
|
private val onGpsStatusChanged by EventDispatcher()
|
|
39
73
|
private val onNavigationInfoUpdate by EventDispatcher()
|
|
40
74
|
private val onGpsSignalWeak by EventDispatcher()
|
|
75
|
+
private val onNavigationVisualStateUpdate by EventDispatcher()
|
|
76
|
+
private val onLaneInfoUpdate by EventDispatcher()
|
|
77
|
+
private val onTrafficStatusesUpdate by EventDispatcher()
|
|
41
78
|
|
|
42
79
|
// Props - 使用 internal 避免自动生成 setter
|
|
43
80
|
internal var showCamera: Boolean = true
|
|
@@ -50,16 +87,34 @@ class ExpoGaodeMapNaviView(context: Context, appContext: AppContext) : ExpoView(
|
|
|
50
87
|
internal var showUIElements: Boolean = true
|
|
51
88
|
internal var androidTrafficBarEnabled: Boolean = true
|
|
52
89
|
internal var isRouteListButtonShow: Boolean = true
|
|
53
|
-
internal var
|
|
90
|
+
internal var isTrafficButtonVisible: Boolean = true
|
|
54
91
|
internal var autoChangeZoom : Boolean = true
|
|
55
92
|
internal var autoLockCar: Boolean = true
|
|
56
|
-
internal var
|
|
93
|
+
internal var isTrafficLineEnabled: Boolean = true
|
|
57
94
|
internal var isRealCrossDisplayShow : Boolean = true
|
|
58
95
|
internal var isNaviArrowVisible : Boolean = true
|
|
96
|
+
internal var isLaneInfoVisible: Boolean = true
|
|
97
|
+
internal var isModeCrossDisplayVisible: Boolean = true
|
|
98
|
+
internal var isEyrieCrossDisplayVisible: Boolean = true
|
|
99
|
+
internal var isSecondActionVisible: Boolean = true
|
|
100
|
+
internal var isBackupOverlayVisible: Boolean = true
|
|
59
101
|
internal var isAfterRouteAutoGray: Boolean = false
|
|
60
102
|
internal var isVectorLineShow: Boolean = true
|
|
61
103
|
internal var isNaviTravelView : Boolean = false
|
|
62
104
|
internal var isCompassEnabled: Boolean = true
|
|
105
|
+
internal var isNaviStatusBarEnabled: Boolean = false
|
|
106
|
+
internal var lockZoomLevel: Int = 18
|
|
107
|
+
internal var lockTilt: Int = 35
|
|
108
|
+
internal var isEagleMapVisible: Boolean = false
|
|
109
|
+
internal var pointToCenterX: Double = 0.0
|
|
110
|
+
internal var pointToCenterY: Double = 0.0
|
|
111
|
+
internal var hideNativeTopInfoLayout: Boolean = false
|
|
112
|
+
internal var naviModeValue: Int = AMapNaviView.CAR_UP_MODE
|
|
113
|
+
internal var carImageUri: String? = null
|
|
114
|
+
internal var fourCornersImageUri: String? = null
|
|
115
|
+
internal var startPointImageUri: String? = null
|
|
116
|
+
internal var wayPointImageUri: String? = null
|
|
117
|
+
internal var endPointImageUri: String? = null
|
|
63
118
|
private val naviView: AMapNaviView by lazy(LazyThreadSafetyMode.NONE) {
|
|
64
119
|
AMapNaviView(context)
|
|
65
120
|
}
|
|
@@ -68,15 +123,550 @@ class ExpoGaodeMapNaviView(context: Context, appContext: AppContext) : ExpoView(
|
|
|
68
123
|
private var endCoordinate: NaviLatLng? = null
|
|
69
124
|
|
|
70
125
|
private var lastAppliedTopPaddingPx: Int? = null
|
|
126
|
+
private var isDestroyed = false
|
|
127
|
+
private var isCrossVisible = false
|
|
128
|
+
private var isModeCrossVisible = false
|
|
129
|
+
private var isLaneInfoCurrentlyVisible = false
|
|
130
|
+
private var currentRouteTotalLength: Int? = null
|
|
131
|
+
private var customCarBitmap: Bitmap? = null
|
|
132
|
+
private var customFourCornersBitmap: Bitmap? = null
|
|
133
|
+
private var customStartPointBitmap: Bitmap? = null
|
|
134
|
+
private var customWayPointBitmap: Bitmap? = null
|
|
135
|
+
private var customEndPointBitmap: Bitmap? = null
|
|
136
|
+
private var routeMarkerShowStartEndVia: Boolean = true
|
|
137
|
+
private var routeMarkerShowFootFerry: Boolean = true
|
|
138
|
+
private var routeMarkerShowForbidden: Boolean = true
|
|
139
|
+
private var routeMarkerShowRouteStartIcon: Boolean = true
|
|
140
|
+
private var routeMarkerShowRouteEndIcon: Boolean = true
|
|
141
|
+
private var cachedTurnIconImageUri: String? = null
|
|
142
|
+
private var cachedTurnIconContentHash: String? = null
|
|
143
|
+
private var hasLoggedMissingTurnIconBitmapApi = false
|
|
144
|
+
|
|
145
|
+
private fun registerActiveView() {
|
|
146
|
+
synchronized(activeViews) {
|
|
147
|
+
activeViews.add(this)
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
private fun unregisterActiveView() {
|
|
152
|
+
synchronized(activeViews) {
|
|
153
|
+
activeViews.remove(this)
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
private fun applyNaviStatusBarEnabledCompat(
|
|
158
|
+
options: AMapNaviViewOptions,
|
|
159
|
+
enabled: Boolean
|
|
160
|
+
) {
|
|
161
|
+
try {
|
|
162
|
+
val method = options.javaClass.getMethod(
|
|
163
|
+
"setNaviStatusBarEnabled",
|
|
164
|
+
java.lang.Boolean.TYPE
|
|
165
|
+
)
|
|
166
|
+
method.invoke(options, enabled)
|
|
167
|
+
} catch (_: NoSuchMethodException) {
|
|
168
|
+
Log.w(
|
|
169
|
+
"ExpoGaodeMapNaviView",
|
|
170
|
+
"AMapNaviViewOptions#setNaviStatusBarEnabled is unavailable in the current AMap SDK; skip applying naviStatusBarEnabled"
|
|
171
|
+
)
|
|
172
|
+
} catch (error: Throwable) {
|
|
173
|
+
Log.w(
|
|
174
|
+
"ExpoGaodeMapNaviView",
|
|
175
|
+
"Failed to apply naviStatusBarEnabled compatibly",
|
|
176
|
+
error
|
|
177
|
+
)
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
private fun applyNaviModeCompat(
|
|
182
|
+
options: AMapNaviViewOptions,
|
|
183
|
+
mode: Int
|
|
184
|
+
) {
|
|
185
|
+
try {
|
|
186
|
+
val method = options.javaClass.getMethod(
|
|
187
|
+
"setNaviMode",
|
|
188
|
+
Integer.TYPE
|
|
189
|
+
)
|
|
190
|
+
method.invoke(options, mode)
|
|
191
|
+
} catch (_: NoSuchMethodException) {
|
|
192
|
+
Log.w(
|
|
193
|
+
"ExpoGaodeMapNaviView",
|
|
194
|
+
"AMapNaviViewOptions#setNaviMode is unavailable in the current AMap SDK; skip applying naviMode on options"
|
|
195
|
+
)
|
|
196
|
+
} catch (error: Throwable) {
|
|
197
|
+
Log.w(
|
|
198
|
+
"ExpoGaodeMapNaviView",
|
|
199
|
+
"Failed to apply naviMode compatibly",
|
|
200
|
+
error
|
|
201
|
+
)
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
private fun createInitialViewOptions(): AMapNaviViewOptions {
|
|
206
|
+
return AMapNaviViewOptions().also { options ->
|
|
207
|
+
applyAllViewOptions(options)
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
private fun applyAllViewOptions(options: AMapNaviViewOptions) {
|
|
212
|
+
options.isLayoutVisible = showUIElements
|
|
213
|
+
options.isSettingMenuEnabled = true
|
|
214
|
+
options.isCompassEnabled = isCompassEnabled
|
|
215
|
+
options.isTrafficBarEnabled = androidTrafficBarEnabled
|
|
216
|
+
options.isRouteListButtonShow = isRouteListButtonShow
|
|
217
|
+
applyNaviStatusBarEnabledCompat(options, isNaviStatusBarEnabled)
|
|
218
|
+
|
|
219
|
+
options.isTrafficLayerEnabled = isTrafficButtonVisible
|
|
220
|
+
options.isTrafficLine = isTrafficLineEnabled
|
|
221
|
+
|
|
222
|
+
options.isRealCrossDisplayShow = isRealCrossDisplayShow
|
|
223
|
+
options.setModeCrossDisplayShow(isModeCrossDisplayVisible)
|
|
224
|
+
options.isLaneInfoShow = isLaneInfoVisible
|
|
225
|
+
options.isEyrieCrossDisplay = isEyrieCrossDisplayVisible
|
|
226
|
+
|
|
227
|
+
options.isCameraBubbleShow = showCamera
|
|
228
|
+
options.isShowCameraDistance = true
|
|
229
|
+
options.isWidgetOverSpeedPulseEffective = true
|
|
230
|
+
|
|
231
|
+
options.isAutoDrawRoute = true
|
|
232
|
+
options.isNaviArrowVisible = isNaviArrowVisible
|
|
233
|
+
options.isSecondActionVisible = isSecondActionVisible
|
|
234
|
+
options.isDrawBackUpOverlay = isBackupOverlayVisible
|
|
235
|
+
applyLeaderLineSetting(options, isVectorLineShow)
|
|
236
|
+
|
|
237
|
+
options.isAutoLockCar = autoLockCar
|
|
238
|
+
options.lockMapDelayed = 5000L
|
|
239
|
+
options.isAutoDisplayOverview = false
|
|
240
|
+
options.isAutoChangeZoom = autoChangeZoom
|
|
241
|
+
options.zoom = lockZoomLevel.coerceIn(14, 18)
|
|
242
|
+
options.tilt = lockTilt.coerceIn(0, 60)
|
|
243
|
+
applyNaviModeCompat(options, naviModeValue)
|
|
244
|
+
if (pointToCenterX > 0.0 && pointToCenterY > 0.0) {
|
|
245
|
+
options.setPointToCenter(pointToCenterX, pointToCenterY)
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
options.isAfterRouteAutoGray = isAfterRouteAutoGray
|
|
249
|
+
options.isSensorEnable = true
|
|
250
|
+
options.isAutoNaviViewNightMode = false
|
|
251
|
+
options.isEagleMapVisible = isEagleMapVisible
|
|
252
|
+
applyCustomAnnotationBitmaps(options)
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
private fun applyBitmapOptionCompat(
|
|
256
|
+
options: AMapNaviViewOptions,
|
|
257
|
+
methodName: String,
|
|
258
|
+
bitmap: Bitmap?
|
|
259
|
+
) {
|
|
260
|
+
try {
|
|
261
|
+
val method = options.javaClass.getMethod(methodName, Bitmap::class.java)
|
|
262
|
+
method.invoke(options, bitmap)
|
|
263
|
+
} catch (_: NoSuchMethodException) {
|
|
264
|
+
Log.w(
|
|
265
|
+
"ExpoGaodeMapNaviView",
|
|
266
|
+
"AMapNaviViewOptions#$methodName is unavailable in the current AMap SDK; skip applying custom bitmap"
|
|
267
|
+
)
|
|
268
|
+
} catch (error: Throwable) {
|
|
269
|
+
Log.w(
|
|
270
|
+
"ExpoGaodeMapNaviView",
|
|
271
|
+
"Failed to apply $methodName compatibly",
|
|
272
|
+
error
|
|
273
|
+
)
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
private fun applyCustomAnnotationBitmaps(options: AMapNaviViewOptions) {
|
|
278
|
+
applyBitmapOptionCompat(options, "setCarBitmap", customCarBitmap)
|
|
279
|
+
applyBitmapOptionCompat(options, "setFourCornersBitmap", customFourCornersBitmap)
|
|
280
|
+
applyBitmapOptionCompat(options, "setStartPointBitmap", customStartPointBitmap)
|
|
281
|
+
applyBitmapOptionCompat(options, "setWayPointBitmap", customWayPointBitmap)
|
|
282
|
+
applyBitmapOptionCompat(options, "setEndPointBitmap", customEndPointBitmap)
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
private fun refreshViewOptionsFromState(reason: String) {
|
|
286
|
+
if (isDestroyed) {
|
|
287
|
+
return
|
|
288
|
+
}
|
|
289
|
+
naviView.viewOptions = createInitialViewOptions()
|
|
290
|
+
refreshNaviUILayout(reason)
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
private fun loadBitmapFromSource(imagePath: String): Bitmap? {
|
|
294
|
+
return try {
|
|
295
|
+
when {
|
|
296
|
+
imagePath.startsWith("http://") || imagePath.startsWith("https://") -> {
|
|
297
|
+
URL(imagePath).openStream().use { BitmapFactory.decodeStream(it) }
|
|
298
|
+
}
|
|
299
|
+
imagePath.startsWith("file://") -> {
|
|
300
|
+
BitmapFactory.decodeFile(imagePath.substring(7))
|
|
301
|
+
}
|
|
302
|
+
else -> {
|
|
303
|
+
val fileName = imagePath.substringBeforeLast('.')
|
|
304
|
+
val resId = context.resources.getIdentifier(
|
|
305
|
+
fileName,
|
|
306
|
+
"drawable",
|
|
307
|
+
context.packageName
|
|
308
|
+
)
|
|
309
|
+
if (resId != 0) {
|
|
310
|
+
BitmapFactory.decodeResource(context.resources, resId)
|
|
311
|
+
} else {
|
|
312
|
+
BitmapFactory.decodeFile(imagePath)
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
} catch (_: Throwable) {
|
|
317
|
+
null
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
private fun updateCustomAnnotationBitmap(
|
|
322
|
+
uri: String?,
|
|
323
|
+
getCurrentUri: () -> String?,
|
|
324
|
+
setCurrentUri: (String?) -> Unit,
|
|
325
|
+
setBitmap: (Bitmap?) -> Unit,
|
|
326
|
+
reason: String
|
|
327
|
+
) {
|
|
328
|
+
val normalizedUri = uri?.takeIf { it.isNotBlank() }
|
|
329
|
+
setCurrentUri(normalizedUri)
|
|
330
|
+
|
|
331
|
+
if (normalizedUri == null) {
|
|
332
|
+
setBitmap(null)
|
|
333
|
+
refreshViewOptionsFromState("clear-$reason")
|
|
334
|
+
return
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
Thread {
|
|
338
|
+
val bitmap = loadBitmapFromSource(normalizedUri)
|
|
339
|
+
Handler(Looper.getMainLooper()).post {
|
|
340
|
+
if (isDestroyed || getCurrentUri() != normalizedUri) {
|
|
341
|
+
return@post
|
|
342
|
+
}
|
|
343
|
+
setBitmap(bitmap)
|
|
344
|
+
refreshViewOptionsFromState("apply-$reason")
|
|
345
|
+
}
|
|
346
|
+
}.start()
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
private fun applyRouteMarkerVisibleFromState() {
|
|
350
|
+
naviView.setRouteMarkerVisible(
|
|
351
|
+
routeMarkerShowStartEndVia,
|
|
352
|
+
routeMarkerShowFootFerry,
|
|
353
|
+
routeMarkerShowForbidden,
|
|
354
|
+
routeMarkerShowRouteStartIcon,
|
|
355
|
+
routeMarkerShowRouteEndIcon
|
|
356
|
+
)
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
private fun commitViewOptions(mutator: (AMapNaviViewOptions) -> Unit) {
|
|
360
|
+
val options = naviView.viewOptions ?: AMapNaviViewOptions()
|
|
361
|
+
mutator(options)
|
|
362
|
+
naviView.viewOptions = options
|
|
363
|
+
refreshNaviUILayout("commitViewOptions")
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
private fun refreshNaviUILayout(reason: String) {
|
|
367
|
+
if (isDestroyed) {
|
|
368
|
+
return
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
naviView.post {
|
|
372
|
+
if (isDestroyed) {
|
|
373
|
+
return@post
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
updateTopInsetPadding()
|
|
377
|
+
naviView.requestLayout()
|
|
378
|
+
naviView.forceLayout()
|
|
379
|
+
naviView.invalidate()
|
|
380
|
+
naviView.postInvalidateOnAnimation()
|
|
381
|
+
requestLayout()
|
|
382
|
+
invalidate()
|
|
383
|
+
postInvalidateOnAnimation()
|
|
384
|
+
updateNativeTopInfoLayoutVisibility()
|
|
385
|
+
Log.d("ExpoGaodeMapNaviView", "refreshNaviUILayout: $reason")
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
private fun shouldHideNativeTopInfoView(view: View): Boolean {
|
|
390
|
+
val className = view.javaClass.name
|
|
391
|
+
return className.contains("BaseNaviInfoLayout") ||
|
|
392
|
+
className.contains("NaviInfoLayout_")
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
private fun updateNativeTopInfoLayoutVisibility() {
|
|
396
|
+
if (isDestroyed) {
|
|
397
|
+
return
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
val queue = ArrayDeque<View>()
|
|
401
|
+
val targetVisibility = if (hideNativeTopInfoLayout) View.GONE else View.VISIBLE
|
|
402
|
+
queue.add(naviView)
|
|
403
|
+
|
|
404
|
+
while (queue.isNotEmpty()) {
|
|
405
|
+
val current = queue.removeFirst()
|
|
406
|
+
if (current is ViewGroup) {
|
|
407
|
+
for (index in 0 until current.childCount) {
|
|
408
|
+
queue.add(current.getChildAt(index))
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
if (!shouldHideNativeTopInfoView(current)) {
|
|
413
|
+
continue
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
if (current.visibility != targetVisibility) {
|
|
417
|
+
current.visibility = targetVisibility
|
|
418
|
+
current.requestLayout()
|
|
419
|
+
current.invalidate()
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
private fun suppressNativeTopInfoLayoutFlash() {
|
|
425
|
+
if (!hideNativeTopInfoLayout || isDestroyed) {
|
|
426
|
+
return
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
val delays = longArrayOf(0L, 16L, 48L, 96L, 180L)
|
|
430
|
+
delays.forEach { delayMs ->
|
|
431
|
+
naviView.postDelayed({
|
|
432
|
+
if (!isDestroyed) {
|
|
433
|
+
updateNativeTopInfoLayoutVisibility()
|
|
434
|
+
}
|
|
435
|
+
}, delayMs)
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
private fun emitVisualStateUpdate() {
|
|
440
|
+
onNavigationVisualStateUpdate(
|
|
441
|
+
mapOf(
|
|
442
|
+
"isCrossVisible" to isCrossVisible,
|
|
443
|
+
"isModeCrossVisible" to isModeCrossVisible,
|
|
444
|
+
"isLaneInfoVisible" to isLaneInfoCurrentlyVisible
|
|
445
|
+
)
|
|
446
|
+
)
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
private fun extractLaneValues(raw: Any?): List<Int> {
|
|
450
|
+
return when (raw) {
|
|
451
|
+
is IntArray -> raw.map { it.toInt() }
|
|
452
|
+
is ByteArray -> raw.map { it.toInt() and 0xFF }
|
|
453
|
+
is ShortArray -> raw.map { it.toInt() }
|
|
454
|
+
is Array<*> -> raw.mapNotNull { (it as? Number)?.toInt() }
|
|
455
|
+
else -> emptyList()
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
private fun getLaneArrayValue(laneInfo: AMapLaneInfo, fieldName: String): List<Int> {
|
|
460
|
+
val reflectedValue = runCatching {
|
|
461
|
+
laneInfo.javaClass.getField(fieldName).get(laneInfo)
|
|
462
|
+
}.getOrElse {
|
|
463
|
+
runCatching {
|
|
464
|
+
val getterName = "get" + fieldName.replaceFirstChar { char ->
|
|
465
|
+
if (char.isLowerCase()) {
|
|
466
|
+
char.titlecase()
|
|
467
|
+
} else {
|
|
468
|
+
char.toString()
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
laneInfo.javaClass.getMethod(getterName).invoke(laneInfo)
|
|
472
|
+
}.getOrNull()
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
return extractLaneValues(reflectedValue)
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
private fun resolveLaneCount(laneInfo: AMapLaneInfo): Int {
|
|
479
|
+
val reflectedCount = runCatching {
|
|
480
|
+
laneInfo.javaClass.getField("laneCount").get(laneInfo) as? Number
|
|
481
|
+
}.getOrElse {
|
|
482
|
+
runCatching {
|
|
483
|
+
laneInfo.javaClass.getMethod("getLaneCount").invoke(laneInfo) as? Number
|
|
484
|
+
}.getOrNull()
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
return reflectedCount?.toInt()?.coerceAtLeast(0) ?: 0
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
private fun serializeLaneInfo(laneInfo: AMapLaneInfo?): Map<String, Any>? {
|
|
491
|
+
if (laneInfo == null) {
|
|
492
|
+
return null
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
val backgroundLane = getLaneArrayValue(laneInfo, "backgroundLane")
|
|
496
|
+
val frontLane = getLaneArrayValue(laneInfo, "frontLane")
|
|
497
|
+
val declaredCount = resolveLaneCount(laneInfo)
|
|
498
|
+
val sentinelIndex = backgroundLane.indexOf(255).takeIf { it >= 0 }
|
|
499
|
+
|
|
500
|
+
val resolvedCount = listOfNotNull(
|
|
501
|
+
sentinelIndex,
|
|
502
|
+
declaredCount.takeIf { it > 0 },
|
|
503
|
+
backgroundLane.size.takeIf { it > 0 },
|
|
504
|
+
frontLane.size.takeIf { it > 0 }
|
|
505
|
+
).minOrNull() ?: 0
|
|
506
|
+
|
|
507
|
+
if (resolvedCount <= 0) {
|
|
508
|
+
return null
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
val normalizedBackground = (0 until resolvedCount).map { index ->
|
|
512
|
+
backgroundLane.getOrNull(index) ?: 255
|
|
513
|
+
}
|
|
514
|
+
val normalizedFront = (0 until resolvedCount).map { index ->
|
|
515
|
+
frontLane.getOrNull(index) ?: 255
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
return mapOf(
|
|
519
|
+
"laneCount" to resolvedCount,
|
|
520
|
+
"backgroundLane" to normalizedBackground,
|
|
521
|
+
"frontLane" to normalizedFront
|
|
522
|
+
)
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
private fun resolveNextTurnIconType(currentSegmentIndex: Int): Int? {
|
|
526
|
+
if (currentSegmentIndex < 0) {
|
|
527
|
+
return null
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
val steps = aMapNavi?.naviPath?.steps ?: return null
|
|
531
|
+
val nextSegmentIndex = currentSegmentIndex + 1
|
|
532
|
+
if (nextSegmentIndex !in steps.indices) {
|
|
533
|
+
return null
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
return try {
|
|
537
|
+
steps[nextSegmentIndex].iconType
|
|
538
|
+
} catch (_: Throwable) {
|
|
539
|
+
null
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
/**
|
|
544
|
+
* Android 导航 SDK 仅透出当前转向图 bitmap,且不同版本方法可见性不完全一致,
|
|
545
|
+
* 这里走反射兼容,避免因为 SDK 小版本差异导致编译直接中断。
|
|
546
|
+
*/
|
|
547
|
+
private fun extractTurnIconBitmap(naviInfo: NaviInfo): Bitmap? {
|
|
548
|
+
return try {
|
|
549
|
+
val method = naviInfo.javaClass.getMethod("getIconBitmap")
|
|
550
|
+
method.invoke(naviInfo) as? Bitmap
|
|
551
|
+
} catch (_: NoSuchMethodException) {
|
|
552
|
+
if (!hasLoggedMissingTurnIconBitmapApi) {
|
|
553
|
+
hasLoggedMissingTurnIconBitmapApi = true
|
|
554
|
+
Log.w(
|
|
555
|
+
"ExpoGaodeMapNaviView",
|
|
556
|
+
"NaviInfo#getIconBitmap is unavailable in the current AMap SDK; turnIconImage will be omitted on Android"
|
|
557
|
+
)
|
|
558
|
+
}
|
|
559
|
+
null
|
|
560
|
+
} catch (error: Throwable) {
|
|
561
|
+
Log.w("ExpoGaodeMapNaviView", "Failed to extract turn icon bitmap", error)
|
|
562
|
+
null
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
private fun bitmapToPngBytes(bitmap: Bitmap): ByteArray? {
|
|
567
|
+
return try {
|
|
568
|
+
val outputStream = ByteArrayOutputStream()
|
|
569
|
+
bitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream)
|
|
570
|
+
outputStream.toByteArray()
|
|
571
|
+
} catch (error: Throwable) {
|
|
572
|
+
Log.w("ExpoGaodeMapNaviView", "Failed to serialize turn icon bitmap", error)
|
|
573
|
+
null
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
private fun sha1Hex(bytes: ByteArray): String {
|
|
578
|
+
val digest = MessageDigest.getInstance("SHA-1").digest(bytes)
|
|
579
|
+
return digest.joinToString("") { "%02x".format(it) }
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
private fun cacheTurnIconBitmap(bytes: ByteArray, prefix: String, contentHash: String): String? {
|
|
583
|
+
return try {
|
|
584
|
+
val directory = File(context.cacheDir, "expo_gaode_map_navigation_icons")
|
|
585
|
+
if (!directory.exists()) {
|
|
586
|
+
directory.mkdirs()
|
|
587
|
+
}
|
|
588
|
+
val file = File(directory, "${prefix}_${contentHash}.png")
|
|
589
|
+
if (!file.exists()) {
|
|
590
|
+
FileOutputStream(file).use { stream ->
|
|
591
|
+
stream.write(bytes)
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
Uri.fromFile(file).toString()
|
|
595
|
+
} catch (error: Throwable) {
|
|
596
|
+
Log.w("ExpoGaodeMapNaviView", "Failed to cache turn icon bitmap", error)
|
|
597
|
+
null
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
private fun deleteCachedIconFile(uriString: String?) {
|
|
602
|
+
if (uriString.isNullOrBlank()) {
|
|
603
|
+
return
|
|
604
|
+
}
|
|
605
|
+
runCatching {
|
|
606
|
+
val path = Uri.parse(uriString).path ?: return
|
|
607
|
+
File(path).delete()
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
private fun updateCachedTurnIconImage(naviInfo: NaviInfo): String? {
|
|
612
|
+
val bitmap = extractTurnIconBitmap(naviInfo)
|
|
613
|
+
if (bitmap == null) {
|
|
614
|
+
deleteCachedIconFile(cachedTurnIconImageUri)
|
|
615
|
+
cachedTurnIconImageUri = null
|
|
616
|
+
cachedTurnIconContentHash = null
|
|
617
|
+
return null
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
val bytes = bitmapToPngBytes(bitmap) ?: return cachedTurnIconImageUri
|
|
621
|
+
val contentHash = sha1Hex(bytes)
|
|
622
|
+
if (contentHash == cachedTurnIconContentHash && !cachedTurnIconImageUri.isNullOrBlank()) {
|
|
623
|
+
return cachedTurnIconImageUri
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
val nextUri = cacheTurnIconBitmap(bytes, "turn_icon", contentHash) ?: return cachedTurnIconImageUri
|
|
627
|
+
val previousUri = cachedTurnIconImageUri
|
|
628
|
+
cachedTurnIconImageUri = nextUri
|
|
629
|
+
cachedTurnIconContentHash = contentHash
|
|
630
|
+
if (previousUri != nextUri) {
|
|
631
|
+
deleteCachedIconFile(previousUri)
|
|
632
|
+
}
|
|
633
|
+
return nextUri
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
private fun emitTrafficStatusesUpdate(retainDistance: Int? = null) {
|
|
637
|
+
val trafficStatuses = try {
|
|
638
|
+
aMapNavi?.getTrafficStatuses(0, 0)
|
|
639
|
+
} catch (_: Throwable) {
|
|
640
|
+
null
|
|
641
|
+
} ?: emptyList()
|
|
642
|
+
|
|
643
|
+
val totalLength = try {
|
|
644
|
+
aMapNavi?.naviPath?.allLength
|
|
645
|
+
} catch (_: Throwable) {
|
|
646
|
+
null
|
|
647
|
+
} ?: currentRouteTotalLength
|
|
648
|
+
|
|
649
|
+
currentRouteTotalLength = totalLength ?: currentRouteTotalLength
|
|
650
|
+
|
|
651
|
+
val payload = mutableMapOf<String, Any>(
|
|
652
|
+
"items" to trafficStatuses.map { status ->
|
|
653
|
+
mapOf(
|
|
654
|
+
"status" to status.status,
|
|
655
|
+
"length" to status.length
|
|
656
|
+
)
|
|
657
|
+
}
|
|
658
|
+
)
|
|
659
|
+
|
|
660
|
+
if ((totalLength ?: 0) > 0) {
|
|
661
|
+
payload["totalLength"] = totalLength as Int
|
|
662
|
+
}
|
|
71
663
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
664
|
+
if (retainDistance != null) {
|
|
665
|
+
payload["retainDistance"] = retainDistance
|
|
666
|
+
}
|
|
75
667
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
val paddingTop: Int
|
|
79
|
-
)
|
|
668
|
+
onTrafficStatusesUpdate(payload)
|
|
669
|
+
}
|
|
80
670
|
|
|
81
671
|
// 导航监听器
|
|
82
672
|
@Suppress("DEPRECATION", "OVERRIDE_DEPRECATION")
|
|
@@ -101,7 +691,7 @@ class ExpoGaodeMapNaviView(context: Context, appContext: AppContext) : ExpoView(
|
|
|
101
691
|
}
|
|
102
692
|
|
|
103
693
|
override fun onTrafficStatusUpdate() {
|
|
104
|
-
|
|
694
|
+
emitTrafficStatusesUpdate()
|
|
105
695
|
}
|
|
106
696
|
|
|
107
697
|
override fun onLocationChange(location: AMapNaviLocation?) {
|
|
@@ -156,6 +746,13 @@ class ExpoGaodeMapNaviView(context: Context, appContext: AppContext) : ExpoView(
|
|
|
156
746
|
// GPS 导航
|
|
157
747
|
aMapNavi?.startNavi(NaviType.GPS)
|
|
158
748
|
}
|
|
749
|
+
Handler(Looper.getMainLooper()).post {
|
|
750
|
+
try {
|
|
751
|
+
applyRouteMarkerVisibleFromState()
|
|
752
|
+
} catch (e: Exception) {
|
|
753
|
+
Log.e("ExpoGaodeMapNaviView", "Failed to reapply route marker visibility after route success", e)
|
|
754
|
+
}
|
|
755
|
+
}
|
|
159
756
|
}
|
|
160
757
|
|
|
161
758
|
override fun onCalculateRouteSuccess(result: AMapCalcRouteResult?) {
|
|
@@ -172,6 +769,13 @@ class ExpoGaodeMapNaviView(context: Context, appContext: AppContext) : ExpoView(
|
|
|
172
769
|
// GPS 导航
|
|
173
770
|
aMapNavi?.startNavi(NaviType.GPS)
|
|
174
771
|
}
|
|
772
|
+
Handler(Looper.getMainLooper()).post {
|
|
773
|
+
try {
|
|
774
|
+
applyRouteMarkerVisibleFromState()
|
|
775
|
+
} catch (e: Exception) {
|
|
776
|
+
Log.e("ExpoGaodeMapNaviView", "Failed to reapply route marker visibility after route success", e)
|
|
777
|
+
}
|
|
778
|
+
}
|
|
175
779
|
}
|
|
176
780
|
|
|
177
781
|
override fun onCalculateRouteFailure(errorCode: Int) {
|
|
@@ -214,14 +818,40 @@ class ExpoGaodeMapNaviView(context: Context, appContext: AppContext) : ExpoView(
|
|
|
214
818
|
|
|
215
819
|
override fun onNaviInfoUpdate(naviInfo: NaviInfo?) {
|
|
216
820
|
naviInfo?.let {
|
|
217
|
-
|
|
821
|
+
currentRouteTotalLength = try {
|
|
822
|
+
aMapNavi?.naviPath?.allLength
|
|
823
|
+
} catch (_: Throwable) {
|
|
824
|
+
null
|
|
825
|
+
} ?: currentRouteTotalLength
|
|
826
|
+
val nextIconType = resolveNextTurnIconType(it.curStep)
|
|
827
|
+
val turnIconImage = updateCachedTurnIconImage(it)
|
|
828
|
+
val payload = mutableMapOf<String, Any>(
|
|
829
|
+
"naviMode" to it.naviType,
|
|
218
830
|
"currentRoadName" to (it.currentRoadName ?: ""),
|
|
219
831
|
"nextRoadName" to (it.nextRoadName ?: ""),
|
|
220
832
|
"pathRetainDistance" to it.pathRetainDistance,
|
|
221
833
|
"pathRetainTime" to it.pathRetainTime,
|
|
222
834
|
"curStepRetainDistance" to it.curStepRetainDistance,
|
|
223
|
-
"curStepRetainTime" to it.curStepRetainTime
|
|
224
|
-
|
|
835
|
+
"curStepRetainTime" to it.curStepRetainTime,
|
|
836
|
+
"currentSpeed" to it.currentSpeed,
|
|
837
|
+
"iconType" to it.iconType,
|
|
838
|
+
"iconDirection" to it.iconType,
|
|
839
|
+
"currentSegmentIndex" to it.curStep,
|
|
840
|
+
"currentLinkIndex" to it.curLink,
|
|
841
|
+
"currentPointIndex" to it.curPoint,
|
|
842
|
+
"routeRemainTrafficLightCount" to it.routeRemainLightCount,
|
|
843
|
+
"driveDistance" to 0,
|
|
844
|
+
"driveTime" to 0
|
|
845
|
+
)
|
|
846
|
+
if (nextIconType != null) {
|
|
847
|
+
payload["nextIconType"] = nextIconType
|
|
848
|
+
}
|
|
849
|
+
if (!turnIconImage.isNullOrBlank()) {
|
|
850
|
+
payload["turnIconImage"] = turnIconImage
|
|
851
|
+
}
|
|
852
|
+
onNavigationInfoUpdate(payload)
|
|
853
|
+
emitTrafficStatusesUpdate(it.pathRetainDistance)
|
|
854
|
+
refreshNaviUILayout("onNaviInfoUpdate")
|
|
225
855
|
}
|
|
226
856
|
}
|
|
227
857
|
|
|
@@ -239,30 +869,57 @@ class ExpoGaodeMapNaviView(context: Context, appContext: AppContext) : ExpoView(
|
|
|
239
869
|
|
|
240
870
|
override fun showCross(crossImg: AMapNaviCross?) {
|
|
241
871
|
// 显示路口放大图
|
|
872
|
+
isCrossVisible = true
|
|
873
|
+
emitVisualStateUpdate()
|
|
874
|
+
suppressNativeTopInfoLayoutFlash()
|
|
875
|
+
refreshNaviUILayout("showCross")
|
|
242
876
|
}
|
|
243
877
|
|
|
244
878
|
override fun hideCross() {
|
|
245
879
|
// 隐藏路口放大图
|
|
880
|
+
isCrossVisible = false
|
|
881
|
+
emitVisualStateUpdate()
|
|
882
|
+
suppressNativeTopInfoLayoutFlash()
|
|
883
|
+
refreshNaviUILayout("hideCross")
|
|
246
884
|
}
|
|
247
885
|
|
|
248
886
|
override fun showModeCross(modelCross: AMapModelCross?) {
|
|
249
887
|
// 显示路口3D模型
|
|
888
|
+
isModeCrossVisible = true
|
|
889
|
+
emitVisualStateUpdate()
|
|
890
|
+
suppressNativeTopInfoLayoutFlash()
|
|
891
|
+
refreshNaviUILayout("showModeCross")
|
|
250
892
|
}
|
|
251
893
|
|
|
252
894
|
override fun hideModeCross() {
|
|
253
895
|
// 隐藏路口3D模型
|
|
896
|
+
isModeCrossVisible = false
|
|
897
|
+
emitVisualStateUpdate()
|
|
898
|
+
suppressNativeTopInfoLayoutFlash()
|
|
899
|
+
refreshNaviUILayout("hideModeCross")
|
|
254
900
|
}
|
|
255
901
|
|
|
256
902
|
override fun showLaneInfo(laneInfo: AMapLaneInfo?) {
|
|
257
903
|
// 显示车道信息
|
|
904
|
+
isLaneInfoCurrentlyVisible = true
|
|
905
|
+
emitVisualStateUpdate()
|
|
906
|
+
serializeLaneInfo(laneInfo)?.let { onLaneInfoUpdate(it) }
|
|
907
|
+
refreshNaviUILayout("showLaneInfo")
|
|
258
908
|
}
|
|
259
909
|
|
|
260
910
|
override fun showLaneInfo(laneInfos: Array<out AMapLaneInfo>?, laneBackgroundInfo: ByteArray?, laneRecommendedInfo: ByteArray?) {
|
|
261
911
|
// 显示车道信息(重载方法)
|
|
912
|
+
isLaneInfoCurrentlyVisible = true
|
|
913
|
+
emitVisualStateUpdate()
|
|
914
|
+
serializeLaneInfo(laneInfos?.firstOrNull())?.let { onLaneInfoUpdate(it) }
|
|
915
|
+
refreshNaviUILayout("showLaneInfoArray")
|
|
262
916
|
}
|
|
263
917
|
|
|
264
918
|
override fun hideLaneInfo() {
|
|
265
919
|
// 隐藏车道信息
|
|
920
|
+
isLaneInfoCurrentlyVisible = false
|
|
921
|
+
emitVisualStateUpdate()
|
|
922
|
+
refreshNaviUILayout("hideLaneInfo")
|
|
266
923
|
}
|
|
267
924
|
|
|
268
925
|
override fun notifyParallelRoad(parallelRoadType: Int) {
|
|
@@ -312,6 +969,7 @@ class ExpoGaodeMapNaviView(context: Context, appContext: AppContext) : ExpoView(
|
|
|
312
969
|
|
|
313
970
|
// 初始化导航视图
|
|
314
971
|
naviView.onCreate(Bundle())
|
|
972
|
+
naviView.viewOptions = createInitialViewOptions()
|
|
315
973
|
naviView.layoutParams = android.widget.FrameLayout.LayoutParams(
|
|
316
974
|
android.widget.FrameLayout.LayoutParams.MATCH_PARENT,
|
|
317
975
|
android.widget.FrameLayout.LayoutParams.MATCH_PARENT
|
|
@@ -323,8 +981,6 @@ class ExpoGaodeMapNaviView(context: Context, appContext: AppContext) : ExpoView(
|
|
|
323
981
|
naviView.clipChildren = false
|
|
324
982
|
naviView.clipToPadding = false
|
|
325
983
|
|
|
326
|
-
ensureOverlayInsetHook()
|
|
327
|
-
|
|
328
984
|
// 使用单例获取导航实例
|
|
329
985
|
aMapNavi = AMapNavi.getInstance(appCtx)
|
|
330
986
|
aMapNavi?.addAMapNaviListener(naviListener)
|
|
@@ -333,65 +989,8 @@ class ExpoGaodeMapNaviView(context: Context, appContext: AppContext) : ExpoView(
|
|
|
333
989
|
aMapNavi?.setUseInnerVoice(true, true) // 启用内置语音,并回调文字
|
|
334
990
|
//设置是否为骑步行视图
|
|
335
991
|
aMapNavi?.isNaviTravelView = isNaviTravelView
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
// === 基础界面控制 ===
|
|
340
|
-
// 注意:isLayoutVisible 控制整个导航UI布局的显示
|
|
341
|
-
// 设置为 true 将显示导航信息面板(包括距离、时间等)
|
|
342
|
-
options.isLayoutVisible = showUIElements
|
|
343
|
-
options.isSettingMenuEnabled = true // 显示设置菜单按钮
|
|
344
|
-
options.isCompassEnabled = isCompassEnabled // 显示指南针
|
|
345
|
-
options.isTrafficBarEnabled = androidTrafficBarEnabled // 显示路况条
|
|
346
|
-
options.isRouteListButtonShow = isRouteListButtonShow // 显示路线全览按钮
|
|
347
|
-
|
|
348
|
-
Log.d("ExpoGaodeMapNaviView", "导航UI配置: isLayoutVisible=true, 所有UI元素已启用")
|
|
349
|
-
|
|
350
|
-
// === 地图图层 ===
|
|
351
|
-
options.isTrafficLayerEnabled = isTrafficLayerEnabled // 显示交通路况图层
|
|
352
|
-
options.isTrafficLine = isTrafficLine // 显示交通路况线
|
|
353
|
-
|
|
354
|
-
// === 路口放大图和车道信息 ===
|
|
355
|
-
options.isRealCrossDisplayShow = isRealCrossDisplayShow // 显示实景路口放大图
|
|
356
|
-
options.setModeCrossDisplayShow(true) // 显示路口3D模型(使用方法而非属性)
|
|
357
|
-
options.isLaneInfoShow = true // 显示车道信息
|
|
358
|
-
options.isEyrieCrossDisplay = true // 显示鹰眼路口图
|
|
359
|
-
|
|
360
|
-
// === 摄像头和电子眼 ===
|
|
361
|
-
options.isCameraBubbleShow = showCamera // 显示摄像头气泡(已废弃但仍可用)
|
|
362
|
-
options.isShowCameraDistance = true // 显示与摄像头的距离
|
|
363
|
-
options.isWidgetOverSpeedPulseEffective = true // 超速脉冲效果
|
|
364
|
-
|
|
365
|
-
// === 路线和导航箭头 ===
|
|
366
|
-
options.isAutoDrawRoute = true // 自动绘制路线
|
|
367
|
-
options.isNaviArrowVisible = isNaviArrowVisible // 显示导航箭头
|
|
368
|
-
options.isSecondActionVisible = true // 显示辅助操作(如下个路口提示)
|
|
369
|
-
options.isDrawBackUpOverlay = true // 绘制备用路线覆盖物
|
|
370
|
-
if(isVectorLineShow)
|
|
371
|
-
options.isLeaderLineEnabled
|
|
372
|
-
|
|
373
|
-
// === 地图锁车和视角控制 ===
|
|
374
|
-
options.isAutoLockCar = autoLockCar // 自动锁车
|
|
375
|
-
options.lockMapDelayed = 5000L // 5秒后自动锁车(毫秒)
|
|
376
|
-
options.isAutoDisplayOverview = false // 不自动显示全览
|
|
377
|
-
options.isAutoChangeZoom = autoChangeZoom // 根据导航自动调整缩放级别
|
|
378
|
-
options.zoom = 18 // 锁车时的缩放级别 (14-18)
|
|
379
|
-
options.tilt = 35 // 锁车时的倾斜角度 (0-60)
|
|
380
|
-
|
|
381
|
-
// === 已走路线处理 ===
|
|
382
|
-
options.isAfterRouteAutoGray = isAfterRouteAutoGray // 走过的路线自动变灰
|
|
383
|
-
|
|
384
|
-
// === 传感器和定位 ===
|
|
385
|
-
options.isSensorEnable = true // 使用设备传感器
|
|
386
|
-
|
|
387
|
-
// === 夜间模式(已废弃但保留兼容) ===
|
|
388
|
-
// 建议使用 setMapStyle 方法设置地图样式
|
|
389
|
-
options.isAutoNaviViewNightMode = false // 不自动切换夜间模式
|
|
390
|
-
|
|
391
|
-
// === 鹰眼地图 ===
|
|
392
|
-
options.isEagleMapVisible = false // 不显示鹰眼地图(小地图)
|
|
393
|
-
|
|
394
|
-
naviView.viewOptions = options
|
|
992
|
+
Log.d("ExpoGaodeMapNaviView", "导航UI配置初始化完成")
|
|
993
|
+
registerActiveView()
|
|
395
994
|
|
|
396
995
|
naviView.post { updateTopInsetPadding() }
|
|
397
996
|
|
|
@@ -413,7 +1012,10 @@ class ExpoGaodeMapNaviView(context: Context, appContext: AppContext) : ExpoView(
|
|
|
413
1012
|
override fun onNextRoadClick() {}
|
|
414
1013
|
override fun onScanViewButtonClick() {}
|
|
415
1014
|
override fun onLockMap(isLock: Boolean) {}
|
|
416
|
-
override fun onNaviViewLoaded() {
|
|
1015
|
+
override fun onNaviViewLoaded() {
|
|
1016
|
+
updateNativeTopInfoLayoutVisibility()
|
|
1017
|
+
refreshNaviUILayout("onNaviViewLoaded")
|
|
1018
|
+
}
|
|
417
1019
|
override fun onMapTypeChanged(mapType: Int) {}
|
|
418
1020
|
})
|
|
419
1021
|
|
|
@@ -422,271 +1024,34 @@ class ExpoGaodeMapNaviView(context: Context, appContext: AppContext) : ExpoView(
|
|
|
422
1024
|
}
|
|
423
1025
|
}
|
|
424
1026
|
|
|
425
|
-
private fun getStatusBarHeightPx(): Int {
|
|
426
|
-
return try {
|
|
427
|
-
val resourceId = context.resources.getIdentifier("status_bar_height", "dimen", "android")
|
|
428
|
-
if (resourceId > 0) context.resources.getDimensionPixelSize(resourceId) else 0
|
|
429
|
-
} catch (_: Exception) {
|
|
430
|
-
0
|
|
431
|
-
}
|
|
432
|
-
}
|
|
433
|
-
|
|
434
1027
|
private fun dpToPx(dp: Double): Int {
|
|
435
1028
|
val density = context.resources.displayMetrics.density
|
|
436
1029
|
return (dp * density + 0.5).toInt()
|
|
437
1030
|
}
|
|
438
1031
|
|
|
439
1032
|
private fun updateTopInsetPadding() {
|
|
440
|
-
val
|
|
441
|
-
val paddingTopPx = if (shouldApplyPadding) {
|
|
442
|
-
androidStatusBarPaddingTopDp?.let { dpToPx(it) } ?: getStatusBarHeightPx()
|
|
443
|
-
} else {
|
|
444
|
-
//默认返回状态栏高度
|
|
445
|
-
getStatusBarHeightPx()
|
|
446
|
-
}
|
|
1033
|
+
val paddingTopPx = androidStatusBarPaddingTopDp?.let { dpToPx(it) } ?: 0
|
|
447
1034
|
|
|
448
1035
|
if (lastAppliedTopPaddingPx == paddingTopPx) {
|
|
449
1036
|
return
|
|
450
1037
|
}
|
|
451
1038
|
|
|
452
1039
|
lastAppliedTopPaddingPx = paddingTopPx
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
applyTopInsetToOverlays(paddingTopPx)
|
|
459
|
-
}
|
|
460
|
-
|
|
461
|
-
private fun ensureOverlayInsetHook() {
|
|
462
|
-
if (overlayHooked) {
|
|
463
|
-
return
|
|
464
|
-
}
|
|
465
|
-
|
|
466
|
-
overlayHooked = true
|
|
467
|
-
naviView.addOnLayoutChangeListener { _, _, _, _, _, _, _, _, _ ->
|
|
468
|
-
applyTopInsetToOverlays(topInsetPx)
|
|
469
|
-
}
|
|
470
|
-
}
|
|
471
|
-
|
|
472
|
-
private fun applyTopInsetToOverlays(paddingTopPx: Int) {
|
|
473
|
-
if (paddingTopPx <= 0) {
|
|
474
|
-
if (overlayStates.isNotEmpty()) {
|
|
475
|
-
val iterator = overlayStates.entries.iterator()
|
|
476
|
-
while (iterator.hasNext()) {
|
|
477
|
-
val entry = iterator.next()
|
|
478
|
-
val view = entry.key
|
|
479
|
-
val state = entry.value
|
|
480
|
-
view.translationY = state.translationY
|
|
481
|
-
view.setPadding(view.paddingLeft, state.paddingTop, view.paddingRight, view.paddingBottom)
|
|
482
|
-
iterator.remove()
|
|
483
|
-
}
|
|
484
|
-
}
|
|
485
|
-
return
|
|
486
|
-
}
|
|
487
|
-
|
|
488
|
-
val rawTargets = findTopOverlayTargets(naviView)
|
|
489
|
-
val targets = filterTopLevelTargets(naviView, rawTargets)
|
|
490
|
-
if (targets.isEmpty()) {
|
|
491
|
-
val applied = applyTopPaddingToNaviUiLayer(paddingTopPx)
|
|
492
|
-
if (!applied) {
|
|
493
|
-
naviView.post { applyTopPaddingToNaviUiLayer(paddingTopPx) }
|
|
494
|
-
}
|
|
495
|
-
return
|
|
496
|
-
}
|
|
497
|
-
|
|
498
|
-
val targetSet = targets.toHashSet()
|
|
499
|
-
|
|
500
|
-
val iterator = overlayStates.entries.iterator()
|
|
501
|
-
while (iterator.hasNext()) {
|
|
502
|
-
val entry = iterator.next()
|
|
503
|
-
val view = entry.key
|
|
504
|
-
if (!targetSet.contains(view)) {
|
|
505
|
-
val state = entry.value
|
|
506
|
-
view.translationY = state.translationY
|
|
507
|
-
view.setPadding(view.paddingLeft, state.paddingTop, view.paddingRight, view.paddingBottom)
|
|
508
|
-
iterator.remove()
|
|
509
|
-
}
|
|
510
|
-
}
|
|
511
|
-
|
|
512
|
-
for (target in targets) {
|
|
513
|
-
if (!overlayStates.containsKey(target)) {
|
|
514
|
-
overlayStates[target] = OverlayState(
|
|
515
|
-
translationY = target.translationY,
|
|
516
|
-
paddingTop = target.paddingTop
|
|
517
|
-
)
|
|
518
|
-
}
|
|
519
|
-
ensureNoClipChain(target)
|
|
520
|
-
target.translationY = paddingTopPx.toFloat()
|
|
521
|
-
}
|
|
522
|
-
}
|
|
523
|
-
|
|
524
|
-
private fun ensureNoClipChain(view: View) {
|
|
525
|
-
var currentParent = view.parent
|
|
526
|
-
while (currentParent is ViewGroup) {
|
|
527
|
-
currentParent.clipChildren = false
|
|
528
|
-
currentParent.clipToPadding = false
|
|
529
|
-
if (currentParent === naviView) {
|
|
530
|
-
break
|
|
531
|
-
}
|
|
532
|
-
currentParent = currentParent.parent
|
|
533
|
-
}
|
|
534
|
-
}
|
|
535
|
-
|
|
536
|
-
private fun filterTopLevelTargets(root: ViewGroup, targets: List<View>): List<View> {
|
|
537
|
-
if (targets.size <= 1) {
|
|
538
|
-
return targets
|
|
539
|
-
}
|
|
540
|
-
|
|
541
|
-
val set = targets.toHashSet()
|
|
542
|
-
val result = ArrayList<View>(targets.size)
|
|
543
|
-
for (view in targets) {
|
|
544
|
-
var parent = view.parent
|
|
545
|
-
var hasAncestorInTargets = false
|
|
546
|
-
while (parent is View) {
|
|
547
|
-
if (parent === root) {
|
|
548
|
-
break
|
|
549
|
-
}
|
|
550
|
-
if (set.contains(parent)) {
|
|
551
|
-
hasAncestorInTargets = true
|
|
552
|
-
break
|
|
553
|
-
}
|
|
554
|
-
parent = parent.parent
|
|
555
|
-
}
|
|
556
|
-
if (!hasAncestorInTargets) {
|
|
557
|
-
result.add(view)
|
|
558
|
-
}
|
|
559
|
-
}
|
|
560
|
-
|
|
561
|
-
return result
|
|
562
|
-
}
|
|
563
|
-
|
|
564
|
-
private fun findTopOverlayTargets(root: ViewGroup): List<View> {
|
|
565
|
-
val result = ArrayList<View>()
|
|
566
|
-
val parentHeight = root.height
|
|
567
|
-
val parentWidth = root.width
|
|
568
|
-
if (parentHeight <= 0 || parentWidth <= 0) {
|
|
569
|
-
return result
|
|
570
|
-
}
|
|
571
|
-
|
|
572
|
-
val queue = ArrayDeque<View>()
|
|
573
|
-
for (i in 0 until root.childCount) {
|
|
574
|
-
queue.add(root.getChildAt(i))
|
|
575
|
-
}
|
|
576
|
-
|
|
577
|
-
while (queue.isNotEmpty()) {
|
|
578
|
-
val view = queue.removeFirst()
|
|
579
|
-
val group = view as? ViewGroup
|
|
580
|
-
if (group != null) {
|
|
581
|
-
for (i in 0 until group.childCount) {
|
|
582
|
-
queue.add(group.getChildAt(i))
|
|
583
|
-
}
|
|
584
|
-
}
|
|
585
|
-
|
|
586
|
-
if (!view.isShown) {
|
|
587
|
-
continue
|
|
588
|
-
}
|
|
589
|
-
|
|
590
|
-
val name = view.javaClass.name
|
|
591
|
-
if (name.contains("MapView", ignoreCase = true) ||
|
|
592
|
-
name.contains("Texture", ignoreCase = true) ||
|
|
593
|
-
name.contains("Surface", ignoreCase = true) ||
|
|
594
|
-
name.contains("GLSurface", ignoreCase = true)
|
|
595
|
-
) {
|
|
596
|
-
continue
|
|
597
|
-
}
|
|
598
|
-
|
|
599
|
-
if (view.height <= 0 || view.width <= 0) {
|
|
600
|
-
continue
|
|
601
|
-
}
|
|
602
|
-
|
|
603
|
-
if (view.top > 1) {
|
|
604
|
-
continue
|
|
605
|
-
}
|
|
606
|
-
|
|
607
|
-
if (view.height >= (parentHeight * 0.6f).toInt()) {
|
|
608
|
-
continue
|
|
609
|
-
}
|
|
610
|
-
|
|
611
|
-
val wideEnough = view.width >= (parentWidth * 0.5f).toInt()
|
|
612
|
-
val likelyUi = wideEnough && (view.isClickable || (view as? ViewGroup)?.childCount ?: 0 > 0)
|
|
613
|
-
if (!likelyUi) {
|
|
614
|
-
continue
|
|
615
|
-
}
|
|
616
|
-
|
|
617
|
-
result.add(view)
|
|
618
|
-
}
|
|
619
|
-
|
|
620
|
-
return result
|
|
621
|
-
}
|
|
622
|
-
|
|
623
|
-
private fun applyTopPaddingToNaviUiLayer(paddingTopPx: Int): Boolean {
|
|
624
|
-
val uiRoot = findNaviUiRoot(naviView) ?: return false
|
|
625
|
-
|
|
626
|
-
uiRoot.setPadding(uiRoot.paddingLeft, paddingTopPx, uiRoot.paddingRight, uiRoot.paddingBottom)
|
|
627
|
-
uiRoot.clipToPadding = false
|
|
628
|
-
return true
|
|
629
|
-
}
|
|
630
|
-
|
|
631
|
-
private fun findNaviUiRoot(root: ViewGroup): ViewGroup? {
|
|
632
|
-
var best: ViewGroup? = null
|
|
633
|
-
var bestScore = Int.MIN_VALUE
|
|
634
|
-
|
|
635
|
-
val queue = ArrayDeque<View>()
|
|
636
|
-
for (i in 0 until root.childCount) {
|
|
637
|
-
queue.add(root.getChildAt(i))
|
|
638
|
-
}
|
|
639
|
-
|
|
640
|
-
while (queue.isNotEmpty()) {
|
|
641
|
-
val view = queue.removeFirst()
|
|
642
|
-
val group = view as? ViewGroup
|
|
643
|
-
if (group != null) {
|
|
644
|
-
val score = scoreAsUiRootCandidate(group)
|
|
645
|
-
if (score > bestScore) {
|
|
646
|
-
bestScore = score
|
|
647
|
-
best = group
|
|
648
|
-
}
|
|
649
|
-
for (i in 0 until group.childCount) {
|
|
650
|
-
queue.add(group.getChildAt(i))
|
|
651
|
-
}
|
|
652
|
-
}
|
|
1040
|
+
if (paddingTopPx > 0) {
|
|
1041
|
+
naviView.setPadding(0, paddingTopPx, 0, 0)
|
|
1042
|
+
} else {
|
|
1043
|
+
naviView.setPadding(0, 0, 0, 0)
|
|
653
1044
|
}
|
|
654
|
-
|
|
655
|
-
return if (bestScore > 0) best else null
|
|
1045
|
+
naviView.requestLayout()
|
|
656
1046
|
}
|
|
657
1047
|
|
|
658
|
-
private fun
|
|
659
|
-
val
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
name.contains("GLSurface", ignoreCase = true)
|
|
664
|
-
) {
|
|
665
|
-
return Int.MIN_VALUE
|
|
666
|
-
}
|
|
667
|
-
|
|
668
|
-
var score = 0
|
|
669
|
-
|
|
670
|
-
val lp = group.layoutParams
|
|
671
|
-
if (lp != null) {
|
|
672
|
-
if (lp.width == ViewGroup.LayoutParams.MATCH_PARENT && lp.height == ViewGroup.LayoutParams.MATCH_PARENT) {
|
|
673
|
-
score += 4
|
|
674
|
-
} else if (lp.width == ViewGroup.LayoutParams.MATCH_PARENT) {
|
|
675
|
-
score += 2
|
|
676
|
-
}
|
|
677
|
-
}
|
|
678
|
-
|
|
679
|
-
if (group.childCount >= 3) {
|
|
680
|
-
score += 2
|
|
681
|
-
} else if (group.childCount >= 1) {
|
|
682
|
-
score += 1
|
|
683
|
-
}
|
|
684
|
-
|
|
685
|
-
if (name.contains("RelativeLayout", ignoreCase = true) || name.contains("FrameLayout", ignoreCase = true)) {
|
|
686
|
-
score += 1
|
|
1048
|
+
private fun applyLeaderLineSetting(options: AMapNaviViewOptions, enabled: Boolean) {
|
|
1049
|
+
val color = if (enabled) {
|
|
1050
|
+
Color.argb(160, 48, 122, 246)
|
|
1051
|
+
} else {
|
|
1052
|
+
-1
|
|
687
1053
|
}
|
|
688
|
-
|
|
689
|
-
return score
|
|
1054
|
+
options.setLeaderLineEnabled(color)
|
|
690
1055
|
}
|
|
691
1056
|
|
|
692
1057
|
|
|
@@ -698,45 +1063,44 @@ class ExpoGaodeMapNaviView(context: Context, appContext: AppContext) : ExpoView(
|
|
|
698
1063
|
|
|
699
1064
|
fun applyShowUIElements(visible: Boolean) {
|
|
700
1065
|
showUIElements = visible
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
1066
|
+
commitViewOptions { options ->
|
|
1067
|
+
options.isLayoutVisible = visible
|
|
1068
|
+
}
|
|
704
1069
|
}
|
|
705
1070
|
|
|
706
1071
|
fun applyAndroidTrafficBarEnabled(enabled: Boolean) {
|
|
707
1072
|
androidTrafficBarEnabled = enabled
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
1073
|
+
commitViewOptions { options ->
|
|
1074
|
+
options.isTrafficBarEnabled = enabled
|
|
1075
|
+
}
|
|
711
1076
|
}
|
|
712
1077
|
|
|
713
1078
|
fun applyShowTrafficButton(enabled: Boolean) {
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
1079
|
+
isTrafficButtonVisible = enabled
|
|
1080
|
+
commitViewOptions { options ->
|
|
1081
|
+
options.isTrafficLayerEnabled = enabled
|
|
1082
|
+
}
|
|
718
1083
|
}
|
|
719
1084
|
|
|
720
1085
|
fun applyShowBrowseRouteButton(enabled: Boolean) {
|
|
721
1086
|
isRouteListButtonShow = enabled
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
1087
|
+
commitViewOptions { options ->
|
|
1088
|
+
options.isRouteListButtonShow = enabled
|
|
1089
|
+
}
|
|
725
1090
|
}
|
|
726
1091
|
|
|
727
1092
|
fun applyShowGreyAfterPass(enabled: Boolean){
|
|
728
1093
|
isAfterRouteAutoGray = enabled
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
1094
|
+
commitViewOptions { options ->
|
|
1095
|
+
options.isAfterRouteAutoGray = enabled
|
|
1096
|
+
}
|
|
732
1097
|
}
|
|
733
1098
|
|
|
734
1099
|
fun applyShowVectorline(enabled: Boolean){
|
|
735
1100
|
isVectorLineShow = enabled
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
naviView.viewOptions = options
|
|
1101
|
+
commitViewOptions { options ->
|
|
1102
|
+
applyLeaderLineSetting(options, enabled)
|
|
1103
|
+
}
|
|
740
1104
|
}
|
|
741
1105
|
|
|
742
1106
|
fun startNavigation(startLat: Double, startLng: Double, endLat: Double, endLng: Double, promise: expo.modules.kotlin.Promise) {
|
|
@@ -778,6 +1142,37 @@ class ExpoGaodeMapNaviView(context: Context, appContext: AppContext) : ExpoView(
|
|
|
778
1142
|
}
|
|
779
1143
|
}
|
|
780
1144
|
|
|
1145
|
+
fun startNavigationWithIndependentPath(
|
|
1146
|
+
token: Int,
|
|
1147
|
+
routeId: Int?,
|
|
1148
|
+
routeIndex: Int?,
|
|
1149
|
+
requestedNaviType: Int?,
|
|
1150
|
+
promise: expo.modules.kotlin.Promise
|
|
1151
|
+
) {
|
|
1152
|
+
try {
|
|
1153
|
+
val finalNaviType = requestedNaviType ?: naviType
|
|
1154
|
+
val result = independentRouteManager.start(context, token, finalNaviType, routeId, routeIndex)
|
|
1155
|
+
if (result.success) {
|
|
1156
|
+
promise.resolve(
|
|
1157
|
+
mapOf(
|
|
1158
|
+
"success" to true,
|
|
1159
|
+
"message" to result.message,
|
|
1160
|
+
"token" to token,
|
|
1161
|
+
"naviType" to finalNaviType,
|
|
1162
|
+
"sdkNaviType" to result.sdkNaviType,
|
|
1163
|
+
"routeId" to result.resolvedRouteId,
|
|
1164
|
+
"pathCount" to result.pathCount,
|
|
1165
|
+
"mainPathIndex" to result.mainPathIndex
|
|
1166
|
+
)
|
|
1167
|
+
)
|
|
1168
|
+
} else {
|
|
1169
|
+
promise.reject("START_INDEPENDENT_NAVI_FAILED", result.message, null)
|
|
1170
|
+
}
|
|
1171
|
+
} catch (e: Exception) {
|
|
1172
|
+
promise.reject("START_INDEPENDENT_NAVI_ERROR", e.message, e)
|
|
1173
|
+
}
|
|
1174
|
+
}
|
|
1175
|
+
|
|
781
1176
|
fun stopNavigation(promise: expo.modules.kotlin.Promise) {
|
|
782
1177
|
try {
|
|
783
1178
|
aMapNavi?.stopNavi()
|
|
@@ -793,10 +1188,9 @@ class ExpoGaodeMapNaviView(context: Context, appContext: AppContext) : ExpoView(
|
|
|
793
1188
|
// Prop setters - 使用不同的方法名避免与 var 属性的自动 setter 冲突
|
|
794
1189
|
fun applyShowCamera(show: Boolean) {
|
|
795
1190
|
showCamera = show
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
naviView.viewOptions = options
|
|
1191
|
+
commitViewOptions { options ->
|
|
1192
|
+
options.isCameraBubbleShow = show
|
|
1193
|
+
}
|
|
800
1194
|
}
|
|
801
1195
|
|
|
802
1196
|
fun applyNaviType(type: Int) {
|
|
@@ -830,42 +1224,125 @@ class ExpoGaodeMapNaviView(context: Context, appContext: AppContext) : ExpoView(
|
|
|
830
1224
|
|
|
831
1225
|
fun applyAutoLockCar(enabled: Boolean) {
|
|
832
1226
|
autoLockCar = enabled
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
1227
|
+
commitViewOptions { options ->
|
|
1228
|
+
options.isAutoLockCar = enabled
|
|
1229
|
+
}
|
|
836
1230
|
}
|
|
837
1231
|
|
|
838
1232
|
fun applyAutoChangeZoom(enabled: Boolean) {
|
|
839
1233
|
autoChangeZoom = enabled
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
1234
|
+
commitViewOptions { options ->
|
|
1235
|
+
options.isAutoChangeZoom = enabled
|
|
1236
|
+
}
|
|
843
1237
|
}
|
|
844
1238
|
|
|
845
1239
|
fun applyTrafficLayerEnabled(enabled: Boolean) {
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
1240
|
+
isTrafficLineEnabled = enabled
|
|
1241
|
+
commitViewOptions { options ->
|
|
1242
|
+
options.isTrafficLine = enabled
|
|
1243
|
+
}
|
|
850
1244
|
}
|
|
851
1245
|
|
|
852
1246
|
fun applyRealCrossDisplay(enabled: Boolean) {
|
|
853
1247
|
isRealCrossDisplayShow = enabled
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
1248
|
+
commitViewOptions { options ->
|
|
1249
|
+
options.isRealCrossDisplayShow = enabled
|
|
1250
|
+
}
|
|
1251
|
+
}
|
|
1252
|
+
|
|
1253
|
+
fun applyLaneInfoVisible(enabled: Boolean) {
|
|
1254
|
+
isLaneInfoVisible = enabled
|
|
1255
|
+
commitViewOptions { options ->
|
|
1256
|
+
options.isLaneInfoShow = enabled
|
|
1257
|
+
}
|
|
1258
|
+
}
|
|
1259
|
+
|
|
1260
|
+
fun applyModeCrossDisplay(enabled: Boolean) {
|
|
1261
|
+
isModeCrossDisplayVisible = enabled
|
|
1262
|
+
commitViewOptions { options ->
|
|
1263
|
+
options.setModeCrossDisplayShow(enabled)
|
|
1264
|
+
}
|
|
1265
|
+
}
|
|
1266
|
+
|
|
1267
|
+
fun applyEyrieCrossDisplay(enabled: Boolean) {
|
|
1268
|
+
isEyrieCrossDisplayVisible = enabled
|
|
1269
|
+
commitViewOptions { options ->
|
|
1270
|
+
options.isEyrieCrossDisplay = enabled
|
|
1271
|
+
}
|
|
1272
|
+
}
|
|
1273
|
+
|
|
1274
|
+
fun applySecondActionVisible(enabled: Boolean) {
|
|
1275
|
+
isSecondActionVisible = enabled
|
|
1276
|
+
commitViewOptions { options ->
|
|
1277
|
+
options.isSecondActionVisible = enabled
|
|
1278
|
+
}
|
|
1279
|
+
}
|
|
1280
|
+
|
|
1281
|
+
fun applyBackupOverlayVisible(enabled: Boolean) {
|
|
1282
|
+
isBackupOverlayVisible = enabled
|
|
1283
|
+
commitViewOptions { options ->
|
|
1284
|
+
options.isDrawBackUpOverlay = enabled
|
|
1285
|
+
}
|
|
857
1286
|
}
|
|
858
1287
|
|
|
859
1288
|
fun applyShowCompassEnabled(enabled: Boolean){
|
|
860
1289
|
isCompassEnabled = enabled
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
1290
|
+
commitViewOptions { options ->
|
|
1291
|
+
options.isCompassEnabled = enabled
|
|
1292
|
+
}
|
|
1293
|
+
}
|
|
1294
|
+
|
|
1295
|
+
fun applyNaviStatusBarEnabled(enabled: Boolean) {
|
|
1296
|
+
isNaviStatusBarEnabled = enabled
|
|
1297
|
+
commitViewOptions { options ->
|
|
1298
|
+
applyNaviStatusBarEnabledCompat(options, enabled)
|
|
1299
|
+
}
|
|
1300
|
+
}
|
|
1301
|
+
|
|
1302
|
+
fun applyLockZoom(level: Int) {
|
|
1303
|
+
lockZoomLevel = level.coerceIn(14, 18)
|
|
1304
|
+
commitViewOptions { options ->
|
|
1305
|
+
options.zoom = lockZoomLevel
|
|
1306
|
+
}
|
|
1307
|
+
}
|
|
1308
|
+
|
|
1309
|
+
fun applyLockTilt(tilt: Int) {
|
|
1310
|
+
lockTilt = tilt.coerceIn(0, 60)
|
|
1311
|
+
commitViewOptions { options ->
|
|
1312
|
+
options.tilt = lockTilt
|
|
1313
|
+
}
|
|
1314
|
+
}
|
|
1315
|
+
|
|
1316
|
+
fun applyEagleMapVisible(enabled: Boolean) {
|
|
1317
|
+
isEagleMapVisible = enabled
|
|
1318
|
+
commitViewOptions { options ->
|
|
1319
|
+
options.isEagleMapVisible = enabled
|
|
1320
|
+
}
|
|
1321
|
+
}
|
|
1322
|
+
|
|
1323
|
+
fun applyPointToCenter(x: Double, y: Double) {
|
|
1324
|
+
pointToCenterX = x
|
|
1325
|
+
pointToCenterY = y
|
|
1326
|
+
commitViewOptions { options ->
|
|
1327
|
+
if (x > 0.0 && y > 0.0) {
|
|
1328
|
+
options.setPointToCenter(x, y)
|
|
1329
|
+
}
|
|
1330
|
+
}
|
|
1331
|
+
}
|
|
1332
|
+
|
|
1333
|
+
fun applyHideNativeTopInfoLayout(hidden: Boolean) {
|
|
1334
|
+
hideNativeTopInfoLayout = hidden
|
|
1335
|
+
updateNativeTopInfoLayoutVisibility()
|
|
1336
|
+
refreshNaviUILayout("applyHideNativeTopInfoLayout")
|
|
864
1337
|
}
|
|
865
1338
|
|
|
866
1339
|
|
|
867
1340
|
fun applyNaviMode(mode: Int) {
|
|
868
|
-
|
|
1341
|
+
naviModeValue = mode
|
|
1342
|
+
commitViewOptions { options ->
|
|
1343
|
+
applyNaviModeCompat(options, mode)
|
|
1344
|
+
}
|
|
1345
|
+
// 兼容旧版接口,保持与 options 一致
|
|
869
1346
|
naviView.naviMode = mode
|
|
870
1347
|
}
|
|
871
1348
|
|
|
@@ -877,15 +1354,13 @@ class ExpoGaodeMapNaviView(context: Context, appContext: AppContext) : ExpoView(
|
|
|
877
1354
|
fun applyNightMode(enabled: Boolean) {
|
|
878
1355
|
// 夜间模式设置 - isNightMode 属性可能不存在
|
|
879
1356
|
try {
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
1357
|
+
commitViewOptions { options ->
|
|
1358
|
+
if(enabled){
|
|
1359
|
+
options.setMapStyle(MapStyle.NIGHT, null)
|
|
1360
|
+
}else{
|
|
1361
|
+
options.setMapStyle(MapStyle.DAY, null)
|
|
1362
|
+
}
|
|
885
1363
|
}
|
|
886
|
-
// options.isNightMode = enabled // 该属性可能不存在
|
|
887
|
-
// 可以通过其他方式设置夜间模式
|
|
888
|
-
naviView.viewOptions = options
|
|
889
1364
|
} catch (e: Exception) {
|
|
890
1365
|
Log.e("ExpoGaodeMapNaviView", "Failed to set night mode", e)
|
|
891
1366
|
}
|
|
@@ -905,6 +1380,56 @@ class ExpoGaodeMapNaviView(context: Context, appContext: AppContext) : ExpoView(
|
|
|
905
1380
|
}
|
|
906
1381
|
}
|
|
907
1382
|
|
|
1383
|
+
fun applyCarImage(uri: String?) {
|
|
1384
|
+
updateCustomAnnotationBitmap(
|
|
1385
|
+
uri = uri,
|
|
1386
|
+
getCurrentUri = { carImageUri },
|
|
1387
|
+
setCurrentUri = { carImageUri = it },
|
|
1388
|
+
setBitmap = { customCarBitmap = it },
|
|
1389
|
+
reason = "carBitmap"
|
|
1390
|
+
)
|
|
1391
|
+
}
|
|
1392
|
+
|
|
1393
|
+
fun applyFourCornersImage(uri: String?) {
|
|
1394
|
+
updateCustomAnnotationBitmap(
|
|
1395
|
+
uri = uri,
|
|
1396
|
+
getCurrentUri = { fourCornersImageUri },
|
|
1397
|
+
setCurrentUri = { fourCornersImageUri = it },
|
|
1398
|
+
setBitmap = { customFourCornersBitmap = it },
|
|
1399
|
+
reason = "fourCornersBitmap"
|
|
1400
|
+
)
|
|
1401
|
+
}
|
|
1402
|
+
|
|
1403
|
+
fun applyStartPointImage(uri: String?) {
|
|
1404
|
+
updateCustomAnnotationBitmap(
|
|
1405
|
+
uri = uri,
|
|
1406
|
+
getCurrentUri = { startPointImageUri },
|
|
1407
|
+
setCurrentUri = { startPointImageUri = it },
|
|
1408
|
+
setBitmap = { customStartPointBitmap = it },
|
|
1409
|
+
reason = "startPointBitmap"
|
|
1410
|
+
)
|
|
1411
|
+
}
|
|
1412
|
+
|
|
1413
|
+
fun applyWayPointImage(uri: String?) {
|
|
1414
|
+
updateCustomAnnotationBitmap(
|
|
1415
|
+
uri = uri,
|
|
1416
|
+
getCurrentUri = { wayPointImageUri },
|
|
1417
|
+
setCurrentUri = { wayPointImageUri = it },
|
|
1418
|
+
setBitmap = { customWayPointBitmap = it },
|
|
1419
|
+
reason = "wayPointBitmap"
|
|
1420
|
+
)
|
|
1421
|
+
}
|
|
1422
|
+
|
|
1423
|
+
fun applyEndPointImage(uri: String?) {
|
|
1424
|
+
updateCustomAnnotationBitmap(
|
|
1425
|
+
uri = uri,
|
|
1426
|
+
getCurrentUri = { endPointImageUri },
|
|
1427
|
+
setCurrentUri = { endPointImageUri = it },
|
|
1428
|
+
setBitmap = { customEndPointBitmap = it },
|
|
1429
|
+
reason = "endPointBitmap"
|
|
1430
|
+
)
|
|
1431
|
+
}
|
|
1432
|
+
|
|
908
1433
|
|
|
909
1434
|
/**
|
|
910
1435
|
* 设置是否显示交通信号灯
|
|
@@ -936,8 +1461,13 @@ class ExpoGaodeMapNaviView(context: Context, appContext: AppContext) : ExpoView(
|
|
|
936
1461
|
showRouteStartIcon: Boolean,
|
|
937
1462
|
showRouteEndIcon: Boolean
|
|
938
1463
|
) {
|
|
1464
|
+
routeMarkerShowStartEndVia = showStartEndVia
|
|
1465
|
+
routeMarkerShowFootFerry = showFootFerry
|
|
1466
|
+
routeMarkerShowForbidden = showForbidden
|
|
1467
|
+
routeMarkerShowRouteStartIcon = showRouteStartIcon
|
|
1468
|
+
routeMarkerShowRouteEndIcon = showRouteEndIcon
|
|
939
1469
|
try {
|
|
940
|
-
|
|
1470
|
+
applyRouteMarkerVisibleFromState()
|
|
941
1471
|
Log.d("ExpoGaodeMapNaviView", "Route marker visibility set - startEnd:$showStartEndVia, ferry:$showFootFerry, forbidden:$showForbidden, routeStart:$showRouteStartIcon, routeEnd:$showRouteEndIcon")
|
|
942
1472
|
} catch (e: Exception) {
|
|
943
1473
|
Log.e("ExpoGaodeMapNaviView", "Failed to set route marker visibility", e)
|
|
@@ -985,9 +1515,9 @@ class ExpoGaodeMapNaviView(context: Context, appContext: AppContext) : ExpoView(
|
|
|
985
1515
|
fun applyNaviArrowVisible(visible: Boolean) {
|
|
986
1516
|
try {
|
|
987
1517
|
isNaviArrowVisible = visible
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
1518
|
+
commitViewOptions { options ->
|
|
1519
|
+
options.isNaviArrowVisible = visible
|
|
1520
|
+
}
|
|
991
1521
|
Log.d("ExpoGaodeMapNaviView", "Navi arrow visibility set to: $visible")
|
|
992
1522
|
} catch (e: Exception) {
|
|
993
1523
|
Log.e("ExpoGaodeMapNaviView", "Failed to set navi arrow visibility", e)
|
|
@@ -996,9 +1526,9 @@ class ExpoGaodeMapNaviView(context: Context, appContext: AppContext) : ExpoView(
|
|
|
996
1526
|
|
|
997
1527
|
override fun onAttachedToWindow() {
|
|
998
1528
|
super.onAttachedToWindow()
|
|
1529
|
+
registerActiveView()
|
|
999
1530
|
try {
|
|
1000
|
-
|
|
1001
|
-
Log.d("ExpoGaodeMapNaviView", "NaviView resumed")
|
|
1531
|
+
onResume()
|
|
1002
1532
|
} catch (e: Exception) {
|
|
1003
1533
|
Log.e("ExpoGaodeMapNaviView", "Error resuming navi view", e)
|
|
1004
1534
|
}
|
|
@@ -1007,42 +1537,52 @@ class ExpoGaodeMapNaviView(context: Context, appContext: AppContext) : ExpoView(
|
|
|
1007
1537
|
override fun onDetachedFromWindow() {
|
|
1008
1538
|
super.onDetachedFromWindow()
|
|
1009
1539
|
try {
|
|
1010
|
-
|
|
1011
|
-
naviView.onDestroy()
|
|
1012
|
-
|
|
1013
|
-
// 停止语音播报
|
|
1014
|
-
aMapNavi?.stopSpeak()
|
|
1015
|
-
|
|
1016
|
-
// 移除监听器但保留 AMapNavi 实例(因为是单例)
|
|
1017
|
-
aMapNavi?.removeAMapNaviListener(naviListener)
|
|
1018
|
-
|
|
1019
|
-
Log.d("ExpoGaodeMapNaviView", "NaviView paused and destroyed")
|
|
1540
|
+
onPause()
|
|
1020
1541
|
} catch (e: Exception) {
|
|
1021
|
-
Log.e("ExpoGaodeMapNaviView", "Error
|
|
1542
|
+
Log.e("ExpoGaodeMapNaviView", "Error pausing navi view", e)
|
|
1022
1543
|
}
|
|
1023
1544
|
}
|
|
1024
1545
|
|
|
1025
1546
|
// 生命周期方法(供外部调用)
|
|
1026
1547
|
fun onResume() {
|
|
1548
|
+
if (isDestroyed) {
|
|
1549
|
+
return
|
|
1550
|
+
}
|
|
1027
1551
|
try {
|
|
1028
1552
|
naviView.onResume()
|
|
1553
|
+
refreshNaviUILayout("onResume")
|
|
1554
|
+
Log.d("ExpoGaodeMapNaviView", "NaviView resumed")
|
|
1029
1555
|
} catch (e: Exception) {
|
|
1030
1556
|
Log.e("ExpoGaodeMapNaviView", "Error resuming navi view", e)
|
|
1031
1557
|
}
|
|
1032
1558
|
}
|
|
1033
1559
|
|
|
1034
1560
|
fun onPause() {
|
|
1561
|
+
if (isDestroyed) {
|
|
1562
|
+
return
|
|
1563
|
+
}
|
|
1035
1564
|
try {
|
|
1036
1565
|
naviView.onPause()
|
|
1566
|
+
Log.d("ExpoGaodeMapNaviView", "NaviView paused")
|
|
1037
1567
|
} catch (e: Exception) {
|
|
1038
1568
|
Log.e("ExpoGaodeMapNaviView", "Error pausing navi view", e)
|
|
1039
1569
|
}
|
|
1040
1570
|
}
|
|
1041
1571
|
|
|
1042
1572
|
fun onDestroy() {
|
|
1573
|
+
if (isDestroyed) {
|
|
1574
|
+
return
|
|
1575
|
+
}
|
|
1576
|
+
isDestroyed = true
|
|
1577
|
+
unregisterActiveView()
|
|
1043
1578
|
try {
|
|
1579
|
+
naviView.onPause()
|
|
1044
1580
|
naviView.onDestroy()
|
|
1581
|
+
aMapNavi?.stopSpeak()
|
|
1045
1582
|
aMapNavi?.removeAMapNaviListener(naviListener)
|
|
1583
|
+
deleteCachedIconFile(cachedTurnIconImageUri)
|
|
1584
|
+
cachedTurnIconImageUri = null
|
|
1585
|
+
cachedTurnIconContentHash = null
|
|
1046
1586
|
// AMapNavi 是单例,不需要手动 destroy
|
|
1047
1587
|
} catch (e: Exception) {
|
|
1048
1588
|
Log.e("ExpoGaodeMapNaviView", "Error destroying navi view", e)
|