diff --git a/lib/modules/agent/controllers/agent_controller.dart b/lib/modules/agent/controllers/agent_controller.dart index 5c9a5c683..2852e4f69 100644 --- a/lib/modules/agent/controllers/agent_controller.dart +++ b/lib/modules/agent/controllers/agent_controller.dart @@ -810,6 +810,7 @@ class AgentController extends GetxController with WidgetsBindingObserver { if (maps_route_navigation is Map) { final card_navigation = maps_route_navigation["card_navigation"]; + final isinternal = metaResult["isinternal"] ?? false; if (card_navigation is Map) { //导航 final start = card_navigation["start"] as String; @@ -826,9 +827,15 @@ class AgentController extends GetxController with WidgetsBindingObserver { Future.delayed(Duration(seconds: 2), () { // Logger.i(TAG, 'liwei-------- 打开导航页面: $start $end '); // 2秒后执行的代码 - - openNavigation(false, start, destination, end_latitude, - end_longitude, ""); + final navigationMode = + AppConfig.env('APP_NAVIGATION_MODE') ?? + 'external_auto'; + if (navigationMode == 'internal_gaode' || isinternal) { + _navigationManager.open( + start, "$end_longitude,$end_latitude", "driving"); + } + // openNavigation(false, start, destination, end_latitude, + // end_longitude, ""); }); } } diff --git a/local_plugins/agent_service/android/src/main/kotlin/com/yunqiinnovation/agent_service/AgentService.kt b/local_plugins/agent_service/android/src/main/kotlin/com/yunqiinnovation/agent_service/AgentService.kt index c4cab4819..702ee4098 100644 --- a/local_plugins/agent_service/android/src/main/kotlin/com/yunqiinnovation/agent_service/AgentService.kt +++ b/local_plugins/agent_service/android/src/main/kotlin/com/yunqiinnovation/agent_service/AgentService.kt @@ -1884,7 +1884,7 @@ object AgentService : CoroutineScope { metadata[toolname] = meta // 现在可以赋值 metadata["notreply"] = notreply // 现在可以赋值 - val metaStr = JSONObject(metadata as Map<*, *>).toString() + // Log.d(TAG, "mcp调用结果: $metaStr") if (meta.has("card_music")) { //音乐卡片 val cardMusic = meta.getJSONObject("card_music") @@ -1967,13 +1967,24 @@ object AgentService : CoroutineScope { }else if (meta.has("card_navigation")) { //导航服务 val cardNavigation = meta.getJSONObject("card_navigation") val start = cardNavigation.optString("start", "") - val end = cardNavigation.optString("end", "") - processNavigation(start, end); + val destination = cardNavigation.optString("destination", "") + val end_longitude = cardNavigation.optString("end_longitude", "") + val end_latitude = cardNavigation.optString("end_latitude", "") + // final start = card_navigation["start"] as String; + // final destination = + // card_navigation["destination"] as String; + // final end_longitude = + // card_navigation["end_longitude"] as String; + // final end_latitude = + // card_navigation["end_latitude"] as String; + var isinternal = processNavigation(start, destination,end_latitude,end_longitude,"driving"); + metadata["isinternal"] = isinternal // 是否是内部导航 }else if (toolname == "map_weather") { //导航服务 iscard = true }else if (toolname == "maps_weather") { //导航服务 iscard = true } + val metaStr = JSONObject(metadata as Map<*, *>).toString() return mapOf("meta" to metaStr, "broadcast" to broadcast, "notreply" to notreply,"iscard" to iscard); } } catch (e: Exception) { @@ -2055,25 +2066,254 @@ object AgentService : CoroutineScope { } /** * 处理导航 - * 将ai返回的音乐连接 在后台启动播放 - * @param musicUrl 图片文件路径 - * @param name 歌曲名称,默认为空 - * @param singer 歌手,默认为false + * 启动导航服务到指定目的地 + * @param start 起点地址 + * @param destination 目的地地址 + * @param endlatitude 目的地纬度 + * @param endlongitude 目的地经度 + * @param mode 导航模式:driving(驾车)、transit(公交)、walking(步行)、cycling(骑行) * @return 是否成功开始处理 */ - fun processNavigation(start: String, end: String) { - if (navigationMode == "internal_gaode"){ - // 如果 playlist 中有有效的歌曲,开始播放 - if (!start.isNullOrEmpty() && !end.isNullOrEmpty()) { - NavigationServiceHelper.startNavigation( - context, - "start", - startpos = start, - endpos = end - ) + fun processNavigation(start: String, destination: String, + endlatitude: String, endlongitude: String, mode: String):Boolean { + Log.d(TAG, "processNavigation: $start -> $destination ($endlongitude,$endlatitude,), mode: $mode") + + if (destination.isEmpty()) { + Log.i(TAG, "启动导航服务失败:目的地为空") + return false + } + + // 获取导航模式配置,默认为自动选择 + val configNavigationMode = navigationMode.ifEmpty { "external_auto" } + Log.d(TAG, "导航模式配置: $configNavigationMode") + + when (configNavigationMode) { + "internal_gaode" -> { + // 使用内置高德导航 + navigateWithInternalGaode(start, destination, endlatitude, endlongitude, mode) + return true + } + "external_baidu" -> { + // 使用外部百度地图 + navigateWithBaiduMap(destination, endlatitude, endlongitude, mode) + return false + } + "external_gaode" -> { + // 使用外部高德地图 + navigateWithGaodeMap(destination, endlatitude, endlongitude, mode) + return false + } + "external_google" -> { + // 使用外部谷歌地图 + navigateWithGoogleMap(destination, mode) + return false + } + else -> { + // 自动选择导航应用,优先级:百度 > 高德 > 谷歌 > 内置高德 + return autoSelectNavigation(start, destination, endlatitude, endlongitude, mode) + } + } + } + + /** + * 使用内置高德导航 + */ + private fun navigateWithInternalGaode(start: String, destination: String, + endlatitude: String, endlongitude: String, mode: String) { + try { + val endpos = if (endlatitude.isNotEmpty() && endlongitude.isNotEmpty()) { + "$endlongitude,$endlatitude" } else { - Log.i(TAG, "启动导航服务失败") + destination } + + NavigationServiceHelper.startNavigation( + context, + "start", + startpos = start, + endpos = "$endlongitude,$endlatitude" + ) + Log.i(TAG, "启动内置高德导航服务成功") + } catch (e: Exception) { + Log.e(TAG, "启动内置高德导航失败: ${e.message}", e) + } + } + + /** + * 使用百度地图导航 + */ + private fun navigateWithBaiduMap(destination: String, endlatitude: String, + endlongitude: String, mode: String) { + try { + val packageInfo = context.packageManager.getPackageInfo(context.packageName, 0) + val src = packageInfo.packageName + + // 百度地图导航模式映射 + val baiduMode = when (mode) { + "transit" -> "transit" + "walking" -> "walking" + "cycling" -> "riding" + else -> "driving" + } + + // 构建目的地参数 + val destinationParam = if (endlatitude.isNotEmpty() && endlongitude.isNotEmpty()) { + "name:$destination|latlng:$endlatitude,$endlongitude" + } else { + destination + } + + val uri = android.net.Uri.parse("baidumap://map/direction?" + + "destination=$destinationParam&" + + "coord_type=gcj02&" + + "mode=$baiduMode&" + + "src=$src") + + val intent = Intent(Intent.ACTION_VIEW, uri).apply { + flags = Intent.FLAG_ACTIVITY_NEW_TASK + } + + if (isAppInstalled("com.baidu.BaiduMap")) { + context.startActivity(intent) + Log.i(TAG, "已启动百度地图导航") + } else { + Log.w(TAG, "百度地图未安装") + throw Exception("百度地图未安装") + } + } catch (e: Exception) { + Log.e(TAG, "启动百度地图失败: ${e.message}", e) + // 回退到其他导航方式 + navigateWithGaodeMap(destination, endlatitude, endlongitude, mode) + } + } + + /** + * 使用高德地图导航 + */ + private fun navigateWithGaodeMap(destination: String, endlatitude: String, + endlongitude: String, mode: String) { + try { + val packageInfo = context.packageManager.getPackageInfo(context.packageName, 0) + val src = packageInfo.packageName + + // 高德地图导航模式映射 + val gaodeMode = when (mode) { + "transit" -> "1" + "walking" -> "2" + "cycling" -> "3" + else -> "0" + } + + val uriBuilder = StringBuilder("androidamap://route/plan?") + if (endlatitude.isNotEmpty() && endlongitude.isNotEmpty()) { + uriBuilder.append("dlat=$endlatitude&") + uriBuilder.append("dlon=$endlongitude&") + } + uriBuilder.append("dname=$destination&") + uriBuilder.append("dev=0&") + uriBuilder.append("t=$gaodeMode&") + uriBuilder.append("sourceApplication=$src") + + val uri = android.net.Uri.parse(uriBuilder.toString()) + val intent = Intent(Intent.ACTION_VIEW, uri).apply { + flags = Intent.FLAG_ACTIVITY_NEW_TASK + } + + if (isAppInstalled("com.autonavi.minimap")) { + context.startActivity(intent) + Log.i(TAG, "已启动高德地图导航") + } else { + Log.w(TAG, "高德地图未安装") + throw Exception("高德地图未安装") + } + } catch (e: Exception) { + Log.e(TAG, "启动高德地图失败: ${e.message}", e) + // 回退到其他导航方式 + navigateWithGoogleMap(destination, mode) + } + } + + /** + * 使用谷歌地图导航 + */ + private fun navigateWithGoogleMap(destination: String, mode: String) { + try { + // 谷歌地图导航模式映射 + val googleMode = when (mode) { + "transit" -> "transit" + "walking" -> "walking" + "cycling" -> "bicycling" + else -> "driving" + } + + // 尝试使用Google Maps应用 + val appUri = android.net.Uri.parse("comgooglemaps://?saddr=Current+Location&daddr=$destination&directionsmode=$googleMode") + val appIntent = Intent(Intent.ACTION_VIEW, appUri).apply { + flags = Intent.FLAG_ACTIVITY_NEW_TASK + } + + if (isAppInstalled("com.google.android.apps.maps")) { + context.startActivity(appIntent) + Log.i(TAG, "已启动谷歌地图导航") + } else { + // 回退到网页版 + val webUri = android.net.Uri.parse("https://www.google.com/maps/dir/?api=1&origin=Current+Location&destination=$destination&travelmode=$googleMode") + val webIntent = Intent(Intent.ACTION_VIEW, webUri).apply { + flags = Intent.FLAG_ACTIVITY_NEW_TASK + } + context.startActivity(webIntent) + Log.i(TAG, "已启动谷歌地图网页版导航") + } + } catch (e: Exception) { + Log.e(TAG, "启动谷歌地图失败: ${e.message}", e) + // 最后回退到内置导航 + navigateWithInternalGaode("", destination, "", "", mode) + } + } + + /** + * 自动选择导航应用 + */ + private fun autoSelectNavigation(start: String, destination: String, + endlatitude: String, endlongitude: String, mode: String):Boolean { + Log.d(TAG, "自动选择导航应用") + + // 1. 优先尝试百度地图 + if (isAppInstalled("com.baidu.BaiduMap")) { + Log.d(TAG, "自动选择:使用百度地图") + navigateWithBaiduMap(destination, endlatitude, endlongitude, mode) + return false + } + + // 2. 其次尝试高德地图 + if (isAppInstalled("com.autonavi.minimap")) { + Log.d(TAG, "自动选择:使用高德地图") + navigateWithGaodeMap(destination, endlatitude, endlongitude, mode) + return false + } + + // 3. 然后尝试谷歌地图 + if (isAppInstalled("com.google.android.apps.maps")) { + Log.d(TAG, "自动选择:使用谷歌地图") + navigateWithGoogleMap(destination, mode) + return false + } + + // 4. 最后使用内置高德导航 + Log.d(TAG, "自动选择:使用内置高德导航") + navigateWithInternalGaode(start, destination, endlatitude, endlongitude, mode) + return true + } + + /** + * 检查应用是否已安装 + */ + private fun isAppInstalled(packageName: String): Boolean { + return try { + context.packageManager.getPackageInfo(packageName, 0) + true + } catch (e: Exception) { + false } }