29 changed files with 1244 additions and 379 deletions
@ -1,96 +0,0 @@ |
|||
import 'package:flutter/material.dart'; |
|||
|
|||
/// A widget that displays a navigation card with different modes of transportation. |
|||
Widget navigationCard( |
|||
BuildContext context, { |
|||
required List<Map<String, dynamic>> modes, |
|||
double height = 260, |
|||
}) { |
|||
int currentIndex = 0; |
|||
|
|||
return Container( |
|||
height: height, |
|||
decoration: BoxDecoration( |
|||
borderRadius: BorderRadius.circular(16), |
|||
color: Colors.white, |
|||
boxShadow: const [ |
|||
BoxShadow( |
|||
blurRadius: 8, |
|||
color: Colors.black12, |
|||
offset: Offset(0, 4), |
|||
), |
|||
], |
|||
), |
|||
child: StatefulBuilder( |
|||
builder: (context, setInnerState) { |
|||
return Column( |
|||
children: [ |
|||
// 路线图片 |
|||
ClipRRect( |
|||
borderRadius: |
|||
const BorderRadius.vertical(top: Radius.circular(16)), |
|||
child: AnimatedSwitcher( |
|||
duration: const Duration(milliseconds: 300), |
|||
child: Image.network( |
|||
modes[currentIndex]["image"] as String, |
|||
key: ValueKey<String>(modes[currentIndex]["ntype"] as String), |
|||
height: 160, |
|||
width: double.infinity, |
|||
fit: BoxFit.cover, |
|||
), |
|||
), |
|||
), |
|||
|
|||
// 导航方式切换按钮 |
|||
Padding( |
|||
padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 4), |
|||
child: Row( |
|||
mainAxisAlignment: MainAxisAlignment.spaceEvenly, |
|||
children: List.generate(modes.length, (index) { |
|||
final isSelected = index == currentIndex; |
|||
return GestureDetector( |
|||
onTap: () { |
|||
setInnerState(() => currentIndex = index); |
|||
}, |
|||
child: SizedBox( |
|||
width: 50, |
|||
child: Text( |
|||
modes[index]["ntype"] as String, |
|||
style: TextStyle( |
|||
color: isSelected ? Colors.blue : Colors.black87, |
|||
fontSize: 12, |
|||
fontWeight: FontWeight.w500, |
|||
), |
|||
), |
|||
), |
|||
); |
|||
}), |
|||
), |
|||
), |
|||
|
|||
// 距离和耗时 |
|||
Padding( |
|||
padding: const EdgeInsets.all(8), |
|||
child: Row( |
|||
mainAxisAlignment: MainAxisAlignment.spaceBetween, |
|||
children: [ |
|||
Text('距离:${modes[currentIndex]["distance"]}', |
|||
style: const TextStyle(fontSize: 12, color: Colors.blue)), |
|||
Container( |
|||
decoration: BoxDecoration( |
|||
shape: BoxShape.circle, // 👈 圆形背景 |
|||
color: Colors.blue, |
|||
), |
|||
child: Icon(Icons.turn_left, |
|||
color: Colors.white, // 👈 圆形图标 |
|||
size: 20), |
|||
) |
|||
], |
|||
), |
|||
), |
|||
], |
|||
); |
|||
}, |
|||
), |
|||
); |
|||
} |
|||
@ -0,0 +1,157 @@ |
|||
import 'package:flutter/material.dart'; |
|||
import 'package:get/get.dart'; |
|||
import '../controllers/agent_controller.dart'; |
|||
|
|||
String formatDistance(String distanceStr) { |
|||
final distance = double.tryParse(distanceStr); |
|||
if (distance == null) return distanceStr; // 如果无法解析,则返回原始字符串 |
|||
|
|||
if (distance >= 1000) { |
|||
final km = distance / 1000; |
|||
return '${km.toStringAsFixed(1)} 公里'; |
|||
} else { |
|||
return '${distance.toStringAsFixed(0)} 米'; |
|||
} |
|||
} |
|||
|
|||
String formatDuration(String secondsStr) { |
|||
int totalSeconds = int.tryParse(secondsStr) ?? 0; |
|||
Duration duration = Duration(seconds: totalSeconds); |
|||
|
|||
int hours = duration.inHours; |
|||
int minutes = duration.inMinutes.remainder(60); |
|||
int seconds = duration.inSeconds.remainder(60); |
|||
|
|||
List<String> parts = []; |
|||
if (hours > 0) parts.add('$hours小时'); |
|||
if (minutes > 0) parts.add('$minutes分钟'); |
|||
if (seconds > 0 || parts.isEmpty) parts.add('$seconds秒'); |
|||
|
|||
return parts.join(''); |
|||
} |
|||
|
|||
//导航卡片 |
|||
Widget navigationCard( |
|||
BuildContext context, { |
|||
required String start, |
|||
required String end, |
|||
required String destination, |
|||
required List<Map<String, dynamic>> modes, |
|||
Map<String, dynamic>? navigation, |
|||
double height = 300, |
|||
}) { |
|||
int currentIndex = 0; |
|||
final controller = Get.find<AgentController>(); // 获取控制器 |
|||
return Container( |
|||
height: height, |
|||
decoration: BoxDecoration( |
|||
borderRadius: BorderRadius.circular(16), |
|||
color: Colors.white, |
|||
boxShadow: const [ |
|||
BoxShadow( |
|||
blurRadius: 8, |
|||
color: Colors.black12, |
|||
offset: Offset(0, 4), |
|||
), |
|||
], |
|||
), |
|||
child: StatefulBuilder( |
|||
builder: (context, setInnerState) { |
|||
return Column( |
|||
crossAxisAlignment: CrossAxisAlignment.start, |
|||
children: [ |
|||
// 路线图片 |
|||
ClipRRect( |
|||
borderRadius: |
|||
const BorderRadius.vertical(top: Radius.circular(16)), |
|||
child: AnimatedSwitcher( |
|||
duration: const Duration(milliseconds: 300), |
|||
child: Image.network( |
|||
modes[currentIndex]["image"] as String, |
|||
key: ValueKey<String>(modes[currentIndex]["ntype"] as String), |
|||
height: 160, |
|||
width: double.infinity, |
|||
fit: BoxFit.cover, |
|||
), |
|||
), |
|||
), |
|||
|
|||
// 导航方式切换按钮 |
|||
Padding( |
|||
padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 4), |
|||
child: Row( |
|||
mainAxisAlignment: MainAxisAlignment.spaceEvenly, |
|||
children: List.generate(modes.length, (index) { |
|||
final isSelected = index == currentIndex; |
|||
return GestureDetector( |
|||
onTap: modes[index]['enable'] as bool |
|||
? () { |
|||
setInnerState(() => currentIndex = index); |
|||
} |
|||
: null, |
|||
child: SizedBox( |
|||
width: 50, |
|||
child: Text( |
|||
(modes[index]["ntype"] as String).tr, |
|||
textAlign: TextAlign.center, |
|||
style: TextStyle( |
|||
color: modes[index]['enable'] |
|||
? isSelected |
|||
? Colors.blue |
|||
: Colors.black87 |
|||
: Colors.grey, |
|||
fontSize: 12, |
|||
fontWeight: FontWeight.w500, |
|||
), |
|||
), |
|||
), |
|||
); |
|||
}), |
|||
), |
|||
), |
|||
|
|||
// 距离和耗时 |
|||
Padding( |
|||
padding: const EdgeInsets.symmetric(horizontal: 8), |
|||
child: Row( |
|||
mainAxisAlignment: MainAxisAlignment.spaceBetween, |
|||
children: [ |
|||
Column( |
|||
crossAxisAlignment: CrossAxisAlignment.start, |
|||
children: [ |
|||
Text('$destination', |
|||
style: const TextStyle( |
|||
fontSize: 12, color: Colors.black)), |
|||
Text( |
|||
'${formatDistance(modes[currentIndex]["distance"])}-约${formatDuration(modes[currentIndex]["duration"])}', |
|||
style: const TextStyle( |
|||
fontSize: 15, color: Colors.blue)), |
|||
if (navigation != null) |
|||
Text( |
|||
"导航中... ${navigation["distanceText"]}进入${navigation["nextRoad"]}", |
|||
style: TextStyle( |
|||
fontSize: 12, |
|||
color: |
|||
const Color.fromARGB(255, 164, 164, 164))) |
|||
], |
|||
), |
|||
CircleAvatar( |
|||
backgroundColor: Colors.blue, |
|||
radius: 18, |
|||
child: IconButton( |
|||
icon: const Icon(Icons.turn_left, |
|||
color: Colors.white, size: 20), |
|||
onPressed: () { |
|||
controller.openNavigation(start, end, ""); |
|||
}, |
|||
), |
|||
) |
|||
], |
|||
), |
|||
), |
|||
], |
|||
); |
|||
}, |
|||
), |
|||
); |
|||
} |
|||
@ -0,0 +1,9 @@ |
|||
import 'package:get/get.dart'; |
|||
import '../controllers/navigation_controller.dart'; |
|||
|
|||
class NavigationBinding extends Bindings { |
|||
@override |
|||
void dependencies() { |
|||
Get.lazyPut<NavigationController>(() => NavigationController()); |
|||
} |
|||
} |
|||
@ -0,0 +1,5 @@ |
|||
import 'package:get/get.dart'; |
|||
|
|||
class NavigationController extends GetxController { |
|||
static NavigationController get to => Get.find(); //单例访问模式 |
|||
} |
|||
@ -0,0 +1,17 @@ |
|||
import 'package:deep_voice/modules/navigation/controllers/navigation_controller.dart'; |
|||
import 'package:flutter/material.dart'; |
|||
import 'package:get/get.dart'; |
|||
|
|||
class NavigationView extends GetView<NavigationController> { |
|||
const NavigationView({Key? key}) : super(key: key); |
|||
|
|||
@override |
|||
Widget build(BuildContext context) { |
|||
return Scaffold( |
|||
appBar: AppBar(title: const Text('地图展示')), |
|||
body: Stack( |
|||
children: [], |
|||
), |
|||
); |
|||
} |
|||
} |
|||
@ -0,0 +1,293 @@ |
|||
package com.yunqiinnovation.amap_service |
|||
|
|||
import android.content.Context |
|||
import android.os.Bundle |
|||
import android.util.Log |
|||
import androidx.appcompat.app.AppCompatActivity |
|||
import com.amap.api.navi.AMapNavi |
|||
import com.amap.api.navi.AMapNaviListener |
|||
import com.amap.api.navi.AMapNaviView |
|||
import com.amap.api.navi.AMapNaviViewListener |
|||
import com.amap.api.navi.enums.PathPlanningStrategy |
|||
import com.amap.api.navi.model.AMapCalcRouteResult |
|||
import com.amap.api.navi.model.AMapLaneInfo |
|||
import com.amap.api.navi.model.AMapModelCross |
|||
import com.amap.api.navi.model.AMapNaviCameraInfo |
|||
import com.amap.api.navi.model.AMapNaviCross |
|||
import com.amap.api.navi.model.AMapNaviLocation |
|||
import com.amap.api.navi.model.AMapNaviRouteNotifyData |
|||
import com.amap.api.navi.model.AMapNaviTrafficFacilityInfo |
|||
import com.amap.api.navi.model.AMapServiceAreaInfo |
|||
import com.amap.api.navi.model.AimLessModeCongestionInfo |
|||
import com.amap.api.navi.model.AimLessModeStat |
|||
import com.amap.api.navi.model.NaviInfo |
|||
import com.amap.api.navi.model.NaviLatLng |
|||
import com.yunqiinnovation.amap_service.NavigationService.Companion.sharedNavi |
|||
|
|||
class NavigationActivity : AppCompatActivity(), AMapNaviListener, AMapNaviViewListener { |
|||
private lateinit var naviView: AMapNaviView |
|||
private var navi: AMapNavi? = null |
|||
private lateinit var context: Context |
|||
private var startpos:String = ""; |
|||
private var endpos:String = ""; |
|||
private var ntype:String = ""; |
|||
override fun onCreate(savedInstanceState: Bundle?) { |
|||
super.onCreate(savedInstanceState) |
|||
setContentView(R.layout.activity_navigation) |
|||
context = this |
|||
// 初始化导航视图 |
|||
naviView = findViewById(R.id.navi_view) |
|||
naviView.onCreate(savedInstanceState) |
|||
naviView.setAMapNaviViewListener(this) |
|||
|
|||
startpos = intent.getStringExtra("startpos").toString() |
|||
endpos = intent.getStringExtra("endpos").toString() |
|||
ntype = intent.getStringExtra("ntype").toString() |
|||
Log.i("NavigationActivity", "onCreate $startpos $endpos $ntype") |
|||
navi = NavigationService.sharedNavi |
|||
if (navi == null) { |
|||
navi = AMapNavi.getInstance(context).apply { |
|||
setUseInnerVoice(true) |
|||
setBroadcastMode(1) |
|||
} |
|||
} |
|||
navi?.addAMapNaviListener(this); |
|||
|
|||
// 绑定当前 activity 到导航状态 |
|||
} |
|||
|
|||
override fun onResume() { |
|||
super.onResume() |
|||
naviView.onResume() |
|||
} |
|||
|
|||
override fun onPause() { |
|||
super.onPause() |
|||
naviView.onPause() |
|||
} |
|||
|
|||
override fun onDestroy() { |
|||
navi?.stopNavi() |
|||
navi?.removeAMapNaviListener(this); |
|||
AMapNavi.destroy() |
|||
NavigationServiceHelper.startNavigation(context,"stop") |
|||
naviView.onDestroy() |
|||
super.onDestroy() |
|||
Log.i("NavigationActivity", "liwei------------------- onDestroy!") |
|||
} |
|||
|
|||
override fun onInitNaviFailure() { |
|||
// TODO("Not yet implemented") |
|||
} |
|||
|
|||
override fun onInitNaviSuccess() { |
|||
Log.i("NavigationActivity", "onInitNaviSuccess!") |
|||
// 起点 |
|||
val startParts: List<String> = startpos.split(",") |
|||
val startLng = startParts[0].toDouble() |
|||
val startLat = startParts[1].toDouble() |
|||
|
|||
// 终点 |
|||
val endParts: List<String> = endpos.split(",") |
|||
val endLng = endParts[0].toDouble() |
|||
val endLat = endParts[1].toDouble() |
|||
|
|||
val startList: MutableList<NaviLatLng> = ArrayList() |
|||
val endList: MutableList<NaviLatLng> = ArrayList() |
|||
startList.add(NaviLatLng(startLat, startLng)) |
|||
endList.add(NaviLatLng(endLat, endLng)) |
|||
val success = navi?.calculateDriveRoute(startList, endList, null, PathPlanningStrategy.DRIVING_MULTIPLE_ROUTES_DEFAULT); |
|||
if (!success!!) { |
|||
Log.e("NavigationActivity", "路径规划请求失败") |
|||
} |
|||
// TODO("Not yet implemented") |
|||
} |
|||
|
|||
override fun onStartNavi(p0: Int) { |
|||
// TODO("Not yet implemented") |
|||
} |
|||
|
|||
override fun onTrafficStatusUpdate() { |
|||
// TODO("Not yet implemented") |
|||
} |
|||
|
|||
override fun onLocationChange(p0: AMapNaviLocation?) { |
|||
// TODO("Not yet implemented") |
|||
} |
|||
|
|||
override fun onGetNavigationText(p0: Int, p1: String?) { |
|||
// TODO("Not yet implemented") |
|||
} |
|||
|
|||
override fun onGetNavigationText(p0: String?) { |
|||
// TODO("Not yet implemented") |
|||
} |
|||
|
|||
override fun onEndEmulatorNavi() { |
|||
// TODO("Not yet implemented") |
|||
} |
|||
|
|||
override fun onArriveDestination() { |
|||
// TODO("Not yet implemented") |
|||
} |
|||
|
|||
override fun onCalculateRouteFailure(p0: Int) { |
|||
// TODO("Not yet implemented") |
|||
} |
|||
|
|||
override fun onCalculateRouteFailure(p0: AMapCalcRouteResult?) { |
|||
// TODO("Not yet implemented") |
|||
} |
|||
|
|||
override fun onReCalculateRouteForYaw() { |
|||
// TODO("Not yet implemented") |
|||
} |
|||
|
|||
override fun onReCalculateRouteForTrafficJam() { |
|||
// TODO("Not yet implemented") |
|||
} |
|||
|
|||
override fun onArrivedWayPoint(p0: Int) { |
|||
// TODO("Not yet implemented") |
|||
} |
|||
|
|||
override fun onGpsOpenStatus(p0: Boolean) { |
|||
// TODO("Not yet implemented") |
|||
} |
|||
|
|||
override fun onNaviInfoUpdate(p0: NaviInfo?) { |
|||
// TODO("Not yet implemented") |
|||
} |
|||
|
|||
override fun updateCameraInfo(p0: Array<out AMapNaviCameraInfo>?) { |
|||
// TODO("Not yet implemented") |
|||
} |
|||
|
|||
override fun updateIntervalCameraInfo( |
|||
p0: AMapNaviCameraInfo?, |
|||
p1: AMapNaviCameraInfo?, |
|||
p2: Int |
|||
) { |
|||
// TODO("Not yet implemented") |
|||
} |
|||
|
|||
override fun onServiceAreaUpdate(p0: Array<out AMapServiceAreaInfo>?) { |
|||
// TODO("Not yet implemented") |
|||
} |
|||
|
|||
override fun showCross(p0: AMapNaviCross?) { |
|||
// TODO("Not yet implemented") |
|||
} |
|||
|
|||
override fun hideCross() { |
|||
// TODO("Not yet implemented") |
|||
} |
|||
|
|||
override fun showModeCross(p0: AMapModelCross?) { |
|||
// TODO("Not yet implemented") |
|||
} |
|||
|
|||
override fun hideModeCross() { |
|||
// TODO("Not yet implemented") |
|||
} |
|||
|
|||
override fun showLaneInfo(p0: Array<out AMapLaneInfo>?, p1: ByteArray?, p2: ByteArray?) { |
|||
// TODO("Not yet implemented") |
|||
} |
|||
|
|||
override fun showLaneInfo(p0: AMapLaneInfo?) { |
|||
// TODO("Not yet implemented") |
|||
} |
|||
|
|||
override fun hideLaneInfo() { |
|||
// TODO("Not yet implemented") |
|||
} |
|||
|
|||
override fun onCalculateRouteSuccess(p0: IntArray?) { |
|||
navi?.startNavi(1); |
|||
// TODO("Not yet implemented") |
|||
} |
|||
|
|||
override fun onCalculateRouteSuccess(p0: AMapCalcRouteResult?) { |
|||
// TODO("Not yet implemented") |
|||
} |
|||
|
|||
override fun notifyParallelRoad(p0: Int) { |
|||
// TODO("Not yet implemented") |
|||
} |
|||
|
|||
override fun OnUpdateTrafficFacility(p0: Array<out AMapNaviTrafficFacilityInfo>?) { |
|||
// TODO("Not yet implemented") |
|||
} |
|||
|
|||
override fun OnUpdateTrafficFacility(p0: AMapNaviTrafficFacilityInfo?) { |
|||
// TODO("Not yet implemented") |
|||
} |
|||
|
|||
override fun updateAimlessModeStatistics(p0: AimLessModeStat?) { |
|||
// TODO("Not yet implemented") |
|||
} |
|||
|
|||
override fun updateAimlessModeCongestionInfo(p0: AimLessModeCongestionInfo?) { |
|||
// TODO("Not yet implemented") |
|||
} |
|||
|
|||
override fun onPlayRing(p0: Int) { |
|||
// TODO("Not yet implemented") |
|||
} |
|||
|
|||
override fun onNaviRouteNotify(p0: AMapNaviRouteNotifyData?) { |
|||
// TODO("Not yet implemented") |
|||
} |
|||
|
|||
override fun onGpsSignalWeak(p0: Boolean) { |
|||
// TODO("Not yet implemented") |
|||
} |
|||
|
|||
//UI事件---------------------------------------------------------------------------------------------- |
|||
override fun onNaviSetting() { |
|||
// TODO("Not yet implemented") |
|||
} |
|||
|
|||
override fun onNaviCancel() { |
|||
finishAndRemoveTask() |
|||
// TODO("Not yet implemented") |
|||
} |
|||
|
|||
override fun onNaviBackClick(): Boolean { |
|||
// TODO("Not yet implemented") |
|||
return false |
|||
} |
|||
|
|||
override fun onNaviMapMode(p0: Int) { |
|||
// TODO("Not yet implemented") |
|||
} |
|||
|
|||
override fun onNaviTurnClick() { |
|||
// TODO("Not yet implemented") |
|||
} |
|||
|
|||
override fun onNextRoadClick() { |
|||
// TODO("Not yet implemented") |
|||
} |
|||
|
|||
override fun onScanViewButtonClick() { |
|||
// TODO("Not yet implemented") |
|||
} |
|||
|
|||
override fun onLockMap(p0: Boolean) { |
|||
// TODO("Not yet implemented") |
|||
} |
|||
|
|||
override fun onNaviViewLoaded() { |
|||
// TODO("Not yet implemented") |
|||
} |
|||
|
|||
override fun onMapTypeChanged(p0: Int) { |
|||
// TODO("Not yet implemented") |
|||
} |
|||
|
|||
override fun onNaviViewShowMode(p0: Int) { |
|||
// TODO("Not yet implemented") |
|||
} |
|||
} |
|||
@ -0,0 +1,108 @@ |
|||
package com.yunqiinnovation.amap_service |
|||
|
|||
import android.content.Context |
|||
import android.content.Intent |
|||
import android.os.Handler |
|||
import android.os.Looper |
|||
import android.util.Log |
|||
import androidx.core.content.ContextCompat |
|||
import java.util.Collections |
|||
|
|||
/** |
|||
* 代理服务事件监听接口 |
|||
*/ |
|||
interface NavigationListener { |
|||
/** |
|||
* 当有事件发生时调用此方法 |
|||
* |
|||
* @param eventName 事件名称 |
|||
* @param data 事件数据 |
|||
*/ |
|||
fun onEvent(eventName: String, data: Map<String, Any>) |
|||
} |
|||
|
|||
object NavigationServiceHelper { |
|||
private val TAG = "NavigationServiceStarter" |
|||
private lateinit var context: Context |
|||
private val listeners = Collections.synchronizedSet(mutableSetOf<NavigationListener>()) |
|||
fun init(appContext: Context) { |
|||
context = appContext |
|||
} |
|||
//启动导航 |
|||
fun startNavigation(context: Context,command:String, startpos: String? = null, endpos: String? = null, ntype: String? = null) { |
|||
Log.i(TAG, "liwei------------------- startNavigation: $command $startpos $endpos $ntype") |
|||
val intent = Intent(context, NavigationService::class.java).apply { |
|||
putExtra("command", command) |
|||
startpos?.let { putExtra("startpos", it) } |
|||
endpos?.let { putExtra("endpos", it) } |
|||
ntype?.let { putExtra("ntype", it) } |
|||
} |
|||
ContextCompat.startForegroundService(context, intent) |
|||
// context.startForegroundService(intent) |
|||
} |
|||
|
|||
//打开导航页面 |
|||
fun openNavigationUI(startpos: String? = null, endpos: String? = null, ntype: String? = null) { |
|||
Log.i(TAG, "liwei------------------- openNavigationUI: $startpos $endpos $ntype") |
|||
val intent = Intent(context, NavigationActivity::class.java).apply { |
|||
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) |
|||
putExtra("startpos", startpos) |
|||
putExtra("endpos", endpos) |
|||
putExtra("ntype", ntype) |
|||
} |
|||
context.startActivity(intent) |
|||
} |
|||
|
|||
/** |
|||
* 添加事件监听器 |
|||
* @param listener 要添加的监听器 |
|||
*/ |
|||
fun addListener(listener: NavigationListener) { |
|||
listeners.add(listener) |
|||
} |
|||
|
|||
/** |
|||
* 移除事件监听器 |
|||
* @param listener 要移除的监听器 |
|||
*/ |
|||
fun removeListener(listener: NavigationListener) { |
|||
listeners.remove(listener) |
|||
} |
|||
|
|||
/** |
|||
* 移除所有事件监听器 |
|||
*/ |
|||
fun clearListeners() { |
|||
listeners.clear() |
|||
} |
|||
|
|||
/** |
|||
* 发送事件 |
|||
*/ |
|||
fun sendEvent(eventName: String, data: Map<String, Any>) { |
|||
// 检查当前是否在主线程 |
|||
if (Looper.myLooper() == Looper.getMainLooper()) { |
|||
// 已在主线程,直接发送 |
|||
listeners.forEach { listener -> |
|||
try { |
|||
listener.onEvent(eventName, data) |
|||
} catch (e: Exception) { |
|||
// FileLogger.e(NavigationService.TAG, "向监听器发送事件失败", e) |
|||
} |
|||
} |
|||
|
|||
} else { |
|||
// 不在主线程,切换到主线程 |
|||
Handler(Looper.getMainLooper()).post { |
|||
listeners.forEach { listener -> |
|||
try { |
|||
listener.onEvent(eventName, data) |
|||
} catch (e: Exception) { |
|||
// FileLogger.e(NavigationService.TAG, "向监听器发送事件失败", e) |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
} |
|||
@ -1,34 +0,0 @@ |
|||
package com.yunqiinnovation.amap_service |
|||
|
|||
import android.content.Context |
|||
import android.content.Intent |
|||
import android.util.Log |
|||
import androidx.core.content.ContextCompat |
|||
|
|||
object NavigationServiceStarter { |
|||
private val TAG = "NavigationServiceStarter" |
|||
//播放单曲 |
|||
fun startServiceWithCommand(context: Context, command: String, startpos: String? = null, endpos: String? = null, ntype: String? = null) { |
|||
Log.i(TAG, "liwei------------------- startServiceWithCommand: $command $startpos $endpos $ntype") |
|||
val intent = Intent(context, NavigationService::class.java).apply { |
|||
putExtra("command", command) |
|||
startpos?.let { |
|||
putExtra("startpos",it) // 只有非 null 时才 putExtra |
|||
} |
|||
endpos?.let { |
|||
putExtra("endpos", it) // 只有非 null 时才 putExtra |
|||
} |
|||
ntype?.let { |
|||
putExtra("ntype",it) // 只有非 null 时才 putExtra |
|||
} |
|||
} |
|||
val success = try { |
|||
ContextCompat.startForegroundService(context, intent) |
|||
true |
|||
} catch (e: Exception) { |
|||
Log.e(TAG, "liwei------------------- Failed to start service", e) |
|||
false |
|||
} |
|||
Log.d(TAG, "liwei------------------- Service start success: $success") |
|||
} |
|||
} |
|||
@ -1,9 +1,9 @@ |
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android" |
|||
android:width="24dp" |
|||
android:height="24dp" |
|||
android:viewportWidth="24" |
|||
android:viewportHeight="24"> |
|||
android:viewportWidth="24.0" |
|||
android:viewportHeight="24.0"> |
|||
<path |
|||
android:fillColor="#FFFFFF" |
|||
android:pathData="M12,2L3,21h9v-6h6v6h3L12,2z" /> |
|||
android:fillColor="#000000" |
|||
android:pathData="M12,2C8.13,2 5,5.13 5,9C5,11.74 7.19,14.74 9.93,16.07L12,21L14.07,16.07C16.81,14.74 19,11.74 19,9C19,5.13 15.87,2 12,2ZM12,12C10.34,12 9,10.66 9,9C9,7.34 10.34,6 12,6C13.66,6 15,7.34 15,9C15,10.66 13.66,12 12,12Z"/> |
|||
</vector> |
|||
|
|||
@ -0,0 +1,10 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" |
|||
android:layout_width="match_parent" |
|||
android:layout_height="match_parent"> |
|||
|
|||
<com.amap.api.navi.AMapNaviView |
|||
android:id="@+id/navi_view" |
|||
android:layout_width="match_parent" |
|||
android:layout_height="match_parent"/> |
|||
</FrameLayout> |
|||
@ -0,0 +1,20 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<resources> |
|||
<!-- 主色调 --> |
|||
<color name="purple_500">#6200EE</color> |
|||
<color name="purple_700">#3700B3</color> |
|||
<color name="teal_200">#03DAC5</color> |
|||
<color name="teal_700">#018786</color> |
|||
<color name="black">#000000</color> |
|||
<color name="white">#FFFFFF</color> |
|||
|
|||
<!-- 额外颜色 --> |
|||
<color name="red_500">#F44336</color> |
|||
<color name="green_500">#4CAF50</color> |
|||
<color name="blue_500">#2196F3</color> |
|||
|
|||
<color name="colorPrimary">#6200EE</color> |
|||
<color name="colorPrimaryDark">#3700B3</color> |
|||
<color name="colorAccent">#03DAC5</color> |
|||
|
|||
</resources> |
|||
@ -0,0 +1,9 @@ |
|||
<resources> |
|||
<!-- 基础应用主题 --> |
|||
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar"> |
|||
<!-- 自定义主题属性 --> |
|||
<item name="colorPrimary">@color/colorPrimary</item> |
|||
<item name="colorPrimaryDark">@color/colorPrimaryDark</item> |
|||
<item name="colorAccent">@color/colorAccent</item> |
|||
</style> |
|||
</resources> |
|||
@ -1,2 +1,2 @@ |
|||
#Sun May 18 21:39:38 IST 2025 |
|||
gradle.version=8.10 |
|||
#Wed May 21 01:03:35 CST 2025 |
|||
gradle.version=8.9 |
|||
|
|||
Loading…
Reference in new issue