package com.shoyoo.react.anavi.navi import android.graphics.Color import com.amap.api.navi.AMapNavi import com.amap.api.navi.AMapNaviListener import com.amap.api.navi.AimlessModeListener import com.amap.api.navi.ParallelRoadListener import com.amap.api.navi.enums.AMapNaviParallelRoadStatus import com.amap.api.navi.enums.NaviType import com.amap.api.navi.enums.TravelStrategy import com.amap.api.navi.model.* import com.facebook.react.bridge.Arguments import com.facebook.react.bridge.ReadableArray import com.facebook.react.bridge.ReadableMap import com.facebook.react.bridge.ReadableType import com.facebook.react.common.MapBuilder import com.facebook.react.uimanager.ThemedReactContext import com.facebook.react.uimanager.ViewGroupManager import com.facebook.react.uimanager.annotations.ReactProp import com.shoyoo.react.anavi.toBitmap import com.shoyoo.react.anavi.toNaviLatLng import com.shoyoo.react.anavi.toNaviPoi import com.shoyoo.react.anavi.toWritableMap @Suppress("unused") abstract class ANaviViewManager : ViewGroupManager(), AimlessModeListener, AMapNaviListener, ParallelRoadListener { private var view: ANaviView? = null private lateinit var navi: AMapNavi override fun createViewInstance(reactContext: ThemedReactContext): ANaviView { navi = AMapNavi.getInstance(reactContext.currentActivity) navi.setUseInnerVoice(true) navi.addAimlessModeListener(this) navi.addAMapNaviListener(this) navi.addParallelRoadListener(this) view = ANaviView(reactContext.currentActivity!!, reactContext).apply { onCreate(null) } return view!! } override fun onDropViewInstance(view: ANaviView) { navi.stopNavi() navi.destroy() super.onDropViewInstance(view) } override fun getCommandsMap(): Map { return mapOf( "startNavi" to START_NAVI, "stopNavi" to STOP_NAVI, "pauseNavi" to PAUSE_NAVI, "resumeNavi" to RESUME_NAVI, "startGPS" to START_GPS, "stopGPS" to STOP_GPS) } override fun receiveCommand(view: ANaviView, commandId: Int, args: ReadableArray?) { when (commandId) { START_NAVI -> startNavi(args?.getInt(0) ?: NaviType.GPS, args?.getInt(0)) STOP_NAVI -> stopNavi() PAUSE_NAVI -> pauseNavi() RESUME_NAVI -> resumeNavi() START_GPS -> startGPS(args?.getInt(0)?.toLong(), args?.getInt(1)) STOP_GPS -> stopGPS() } } override fun getExportedCustomDirectEventTypeConstants(): Map { return mapOf( "onInitNaviFailure" to MapBuilder.of("registrationName", "onInitNaviFailure"), "onInitNaviSuccess" to MapBuilder.of("registrationName", "onInitNaviSuccess"), "onStartNavi" to MapBuilder.of("registrationName", "onStartNavi"), "onLocationChange" to MapBuilder.of("registrationName", "onLocationChange"), "onGetNavigationText" to MapBuilder.of("registrationName", "onGetNavigationText"), "onEndEmulatorNavi" to MapBuilder.of("registrationName", "onEndEmulatorNavi"), "onCalculateRouteFailure" to MapBuilder.of("registrationName", "onCalculateRouteFailure"), "onGpsStatusChanged" to MapBuilder.of("registrationName", "onGpsStatusChanged"), "onCalculateRouteSuccess" to MapBuilder.of("registrationName", "onCalculateRouteSuccess"), "onPlayRing" to MapBuilder.of("registrationName", "onPlayRing"), "onNaviSettingChanged" to MapBuilder.of("registrationName", "onNaviSettingChanged"), "onNaviCancel" to MapBuilder.of("registrationName", "onNaviCancel"), "onNaviComplete" to MapBuilder.of("registrationName", "onNaviComplete"), "onNaviBackClick" to MapBuilder.of("registrationName", "onNaviBackClick"), "onNaviMapModeChanged" to MapBuilder.of("registrationName", "onNaviMapModeChanged"), "onNaviMapViewTrackingModeChanged" to MapBuilder.of("registrationName", "onNaviMapViewTrackingModeChanged"), "onLockMap" to MapBuilder.of("registrationName", "onLockMap"), "onNaviViewLoaded" to MapBuilder.of("registrationName", "onNaviViewLoaded"), "onNaviMapViewModeChanged" to MapBuilder.of("registrationName", "onNaviMapViewModeChanged") ) } protected fun calculateDriveRoute(from: NaviLatLng?, to: NaviLatLng, wayPoints: List?, strategy: Int) { if (from == null) { navi.calculateDriveRoute(listOf(to), wayPoints, strategy) } else { navi.calculateDriveRoute(listOf(from), listOf(to), wayPoints, strategy) } } protected fun calculateDriveRoute(from: NaviPoi, to: NaviPoi, wayPoints: List?, strategy: Int) { navi.calculateDriveRoute(from, to, wayPoints, strategy) } protected fun calculateDriveRoute(fromPoiId: String?, toPoiId: String, wayPoints: List?, strategy: Int) { if (fromPoiId == null) { navi.calculateDriveRoute(toPoiId, wayPoints, strategy) } else { navi.calculateDriveRoute(fromPoiId, toPoiId, wayPoints, strategy) } } protected fun calculateRideRoute(from: NaviLatLng?, to: NaviLatLng) { if (from == null) { navi.calculateRideRoute(to) } else { navi.calculateRideRoute(from, to) } } protected fun calculateRideRoute(from: NaviPoi, to: NaviPoi, strategy: TravelStrategy) { navi.calculateRideRoute(from, to, strategy) } protected fun calculateWalkRoute(from: NaviLatLng?, to: NaviLatLng) { if (from == null) { navi.calculateWalkRoute(to) } else { navi.calculateWalkRoute(from, to) } } protected fun calculateWalkRoute(from: NaviPoi, to: NaviPoi, strategy: TravelStrategy) { navi.calculateWalkRoute(from, to, strategy) } protected abstract fun calculateRoute(from: Any?, to: Any, wayPoints: List?, strategy: Int) private fun startNavi(type: Int, speed: Int?) { if (type == NaviType.EMULATOR) { startEmulateNavi(speed) } else { navi.startNavi(type) } } private fun startEmulateNavi(speed: Int?) { if (speed != null) { navi.setEmulatorNaviSpeed(speed) } navi.startNavi(NaviType.EMULATOR) } private fun stopNavi() { navi.stopNavi() } private fun pauseNavi() { navi.pauseNavi() } private fun resumeNavi() { navi.resumeNavi() } private fun startGPS(time: Long?, dis: Int?) { when { time == null -> { navi.startGPS() } dis != null -> { navi.startGPS(time, dis) } else -> { navi.startGPS() } } } private fun stopGPS() { navi.stopGPS() } /* * 1.String * 2.LatLng * 3.NaviPoi * 4.List * 5.List */ private data class NaviArgs(val type: Int, val data: Any?) private fun parseArgument(args: ReadableMap?): NaviArgs? { return if (args == null) { null } else if (args.hasKey("name") && args.hasKey("coordinate") && args.hasKey("poiId")) { NaviArgs(3, args.toNaviPoi()) } else if (args.hasKey("latitude") && args.hasKey("longitude")) { NaviArgs(2, args.toNaviLatLng()) } else { null } } private fun parseArgument(key: String, args: ReadableMap): NaviArgs? { if (!args.hasKey(key)) { return null } return when (args.getType(key)) { ReadableType.String -> { NaviArgs(1, args.getString(key)) } ReadableType.Map -> { parseArgument(args.getMap(key)) } ReadableType.Array -> { val arr = args.getArray(key) when { arr?.size() == 0 -> { null } arr?.getType(0) == ReadableType.String -> { NaviArgs(4, (0 until arr.size()).map { arr.getString(it) }.toList()) } arr?.getType(0) == ReadableType.Map -> { NaviArgs(5, (0 until arr.size()).map { parseArgument(arr.getMap(it)) }.toList()) } else -> { null } } } else -> { null } } } @ReactProp(name = "navi") fun setNaviArgument(view: ANaviView, arguments: ReadableMap) { val from = parseArgument("from", arguments) val to = parseArgument("to", arguments) ?: throw IllegalArgumentException("The to parameter can't be null") val strategy = if (arguments.hasKey("strategy")) arguments.getInt("strategy") else null val wayPoints = parseArgument("wayPoints", arguments) if (from != null && from.type != to.type) { throw IllegalArgumentException("The type of from must be same as to's type") } calculateRoute(from?.data, to.data!!, wayPoints?.data as List?, strategy ?: 10) } @ReactProp(name = "layoutVisible") fun setLayoutVisible(view: ANaviView, visible: Boolean) { view.viewOptions.apply { isLayoutVisible = visible view.viewOptions = this } } @ReactProp(name = "compassVisible") fun setCompassEnabled(view: ANaviView, enabled: Boolean) { view.viewOptions.apply { isCompassEnabled = enabled view.viewOptions = this } } @ReactProp(name = "leaderLineColor") fun setLeaderLineEnabled(view: ANaviView, color: String) { view.viewOptions.apply { setLeaderLineEnabled(Color.parseColor(color)) view.viewOptions = this } } @ReactProp(name = "turnArrowVisible") fun setNaviArrowVisible(view: ANaviView, visible: Boolean) { view.viewOptions.apply { isNaviArrowVisible = visible view.viewOptions = this } } @ReactProp(name = "screenAlwaysBright") fun setScreenAlwaysBright(view: ANaviView, alwaysBright: Boolean) { view.viewOptions.apply { isScreenAlwaysBright = alwaysBright view.viewOptions = this } } @ReactProp(name = "browseButtonVisible") fun setRouteListButtonShow(view: ANaviView, visible: Boolean) { view.viewOptions.apply { isRouteListButtonShow = visible view.viewOptions = this } } @ReactProp(name = "moreButtonVisible") fun setSettingMenuEnabled(view: ANaviView, enabled: Boolean) { view.viewOptions.apply { isSettingMenuEnabled = enabled view.viewOptions = this } } @ReactProp(name = "tilt") fun setTilt(view: ANaviView, tilt: Int) { view.viewOptions.apply { this.tilt = tilt view.viewOptions = this } } @ReactProp(name = "carMarkerIcon") fun setCarBitmap(view: ANaviView, icon: String) { view.viewOptions.apply { carBitmap = icon.toBitmap() view.viewOptions = this } } @ReactProp(name = "startMarkerIcon") fun setStartPointBitmap(view: ANaviView, icon: String) { view.viewOptions.apply { setStartPointBitmap(icon.toBitmap()) view.viewOptions = this } } @ReactProp(name = "endMarkerIcon") fun setEndPointBitmap(view: ANaviView, icon: String) { view.viewOptions.apply { setEndPointBitmap(icon.toBitmap()) view.viewOptions = this } } @ReactProp(name = "fourCornersIcon") fun setFourCornersBitmap(view: ANaviView, icon: String) { view.viewOptions.apply { fourCornersBitmap = icon.toBitmap() view.viewOptions = this } } @ReactProp(name = "showMode") fun showMode(view: ANaviView, mode: Int) { view.setShowMode(mode) } // region Implement AimlessModeListener override fun onUpdateTrafficFacility(p0: Array?) { } override fun onUpdateAimlessModeElecCameraInfo(p0: Array?) { } override fun updateAimlessModeCongestionInfo(p0: AimLessModeCongestionInfo?) { } override fun updateAimlessModeStatistics(p0: AimLessModeStat?) { } // endregion // region Implement AMapNaviListener override fun onInitNaviFailure() { view?.emit("onInitNaviFailure") } override fun onInitNaviSuccess() { view?.emit("onInitNaviSuccess") } override fun onStartNavi(type: Int) { view?.emit("onStartNavi", Arguments.createMap().apply { putInt("type", type) }) } override fun onTrafficStatusUpdate() { } override fun onLocationChange(location: AMapNaviLocation?) { location?.let { view?.emit("onLocationChange", it.toWritableMap()) } } override fun onGetNavigationText(type: Int, text: String?) { } override fun onGetNavigationText(text: String?) { view?.emit("onGetNavigationText", Arguments.createMap().apply { putString("text", text) }) } override fun onEndEmulatorNavi() { view?.emit("onEndEmulatorNavi") } override fun onArriveDestination() { view?.emit("onNaviComplete") } override fun onCalculateRouteFailure(errorCode: Int) { } override fun onCalculateRouteFailure(result: AMapCalcRouteResult?) { view?.emit("onCalculateRouteFailure", Arguments.createMap().apply { putInt("errorCode", result?.errorCode ?: 0) putString("errorDetail", result?.errorDetail) putString("errorDescription", result?.errorDescription) }) } override fun onReCalculateRouteForYaw() { } override fun onReCalculateRouteForTrafficJam() { } override fun onArrivedWayPoint(wayId: Int) { } override fun onGpsOpenStatus(enabled: Boolean) { } override fun onNaviInfoUpdate(naviInfo: NaviInfo?) { } override fun updateCameraInfo(cameraInfos: Array?) { } override fun updateIntervalCameraInfo(startCameraInfo: AMapNaviCameraInfo?, endCameraInfo: AMapNaviCameraInfo?, status: Int) { } override fun onServiceAreaUpdate(serviceAreaInfos: Array?) { } override fun showCross(cross: AMapNaviCross?) { } override fun hideCross() { } override fun showModeCross(modelCross: AMapModelCross?) { } override fun hideModeCross() { } override fun showLaneInfo(laneInfos: Array?, laneBackgroundInfo: ByteArray?, laneRecommendedInfo: ByteArray?) { } override fun showLaneInfo(laneInfo: AMapLaneInfo?) { } override fun hideLaneInfo() { } override fun onCalculateRouteSuccess(routeIds: IntArray?) { } override fun onCalculateRouteSuccess(result: AMapCalcRouteResult?) { view?.emit("onCalculateRouteSuccess", Arguments.createMap().apply { putInt("errorCode", result?.errorCode!!) putString("errorDetail", result.errorDetail) putString("errorDescription", result.errorDescription) putArray("routeId", Arguments.createArray().apply { result.routeid.forEach { pushInt(it) } }) }) } override fun notifyParallelRoad(parallelRoadType: Int) { } override fun OnUpdateTrafficFacility(infos: Array?) { } override fun OnUpdateTrafficFacility(var1: AMapNaviTrafficFacilityInfo?) { } override fun onPlayRing(type: Int) { view?.emit("onPlayRing", Arguments.createMap().apply { putInt("type", type) }) } override fun onNaviRouteNotify(notifyData: AMapNaviRouteNotifyData?) { } override fun onGpsSignalWeak(weak: Boolean) { view?.emit("onGpsStatusChanged", Arguments.createMap().apply { putInt("status", if (weak) 2 else 1) }) } // endregion // region Implement ParallelRoadListener override fun notifyParallelRoad(roadStatus: AMapNaviParallelRoadStatus?) { } // endregion companion object { const val START_NAVI = 1 const val STOP_NAVI = 2 const val PAUSE_NAVI = 3 const val RESUME_NAVI = 4 const val START_GPS = 5 const val STOP_GPS = 6 } }