This commit is contained in:
2025-05-12 20:00:31 +08:00
parent d43b571af0
commit d2be63ea08
7 changed files with 355 additions and 35 deletions

View File

@@ -20,3 +20,6 @@
# hide the original source file name. # hide the original source file name.
#-renamesourcefileattribute SourceFile #-renamesourcefileattribute SourceFile
-keep class com.amap.api.navi.**{*;}
-keep class com.alibaba.idst.nui.* {*;}
-keep class com.google.**{*;}

View File

@@ -24,6 +24,8 @@
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" /> <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" /> <uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />
<uses-feature <uses-feature
android:name="android.hardware.bluetooth_le" android:name="android.hardware.bluetooth_le"
android:required="true" /> android:required="true" />
@@ -48,6 +50,10 @@
<activity <activity
android:name=".RouteActivity" android:name=".RouteActivity"
android:exported="false" /> android:exported="false" />
<activity
android:name="com.amap.api.navi.AmapRouteActivity"
android:theme="@android:style/Theme.NoTitleBar"
android:configChanges="orientation|keyboardHidden|screenSize|navigation" />
<activity <activity
android:name=".MainActivity" android:name=".MainActivity"
android:exported="true" android:exported="true"
@@ -63,6 +69,12 @@
<meta-data <meta-data
android:name="com.amap.api.v2.apikey" android:name="com.amap.api.v2.apikey"
android:value="14f8203a16e09d7000bd8b31c9bf1ef7" /> android:value="14f8203a16e09d7000bd8b31c9bf1ef7" />
<meta-data
android:name="IFLYTEK_APPKEY"
android:value="1342cc62" />
<meta-data
android:name="IFLYTEK_CHANNEL"
android:value="Android_Demo" />
</application> </application>
</manifest> </manifest>

View File

@@ -1,29 +1,37 @@
package com.example.mangowalking; package com.example.mangowalking;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.content.pm.PackageManager; import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.util.Log; import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.ContextCompat;
import com.amap.api.location.AMapLocationClient; import com.amap.api.location.AMapLocationClient;
import com.amap.api.location.AMapLocationClientOption; import com.amap.api.location.AMapLocationClientOption;
import com.amap.api.location.AMapLocationListener; import com.amap.api.location.AMapLocationListener;
import com.amap.api.maps.AMapException; import com.amap.api.maps.AMapException;
import com.amap.api.maps.model.LatLng;
import com.amap.api.maps.model.Poi;
import com.amap.api.navi.AMapNavi; import com.amap.api.navi.AMapNavi;
import com.amap.api.navi.AMapNaviListener; import com.amap.api.navi.AMapNaviListener;
import com.amap.api.navi.AMapNaviView; import com.amap.api.navi.AMapNaviView;
import com.amap.api.navi.AMapNaviViewListener; import com.amap.api.navi.AMapNaviViewListener;
import com.amap.api.navi.AmapNaviPage;
import com.amap.api.navi.AmapNaviParams;
import com.amap.api.navi.AmapNaviType;
import com.amap.api.navi.AmapPageType;
import com.amap.api.navi.ParallelRoadListener; import com.amap.api.navi.ParallelRoadListener;
import com.amap.api.navi.enums.AMapNaviParallelRoadStatus; import com.amap.api.navi.enums.AMapNaviParallelRoadStatus;
import com.amap.api.navi.enums.NaviType; import com.amap.api.navi.enums.NaviType;
import com.amap.api.navi.enums.TransportType; import com.amap.api.navi.enums.TransportType;
import com.amap.api.navi.enums.TravelStrategy;
import com.amap.api.navi.model.*; import com.amap.api.navi.model.*;
import com.example.mangowalking.utils.TTSController; import com.example.mangowalking.utils.TTSController;
import com.google.android.filament.View;
import java.util.ArrayList; import java.util.ArrayList;
@@ -32,38 +40,109 @@ import java.util.List;
public class GuideMap extends AppCompatActivity implements AMapNaviListener, AMapNaviViewListener, ParallelRoadListener { public class GuideMap extends AppCompatActivity implements AMapNaviListener, AMapNaviViewListener, ParallelRoadListener {
private static final String TAG = "GuideMap"; private static final String TAG = "GuideMap";
private AMapNaviView mNaviView; // 对应DEMO mAMapNaviView; private AMapNaviView mNaviView; // 对应DEMO mAMapNaviView;
private AMapNavi mNavi; // mAMapNavi; private AMapNavi mAMapNavi; // mAMapNavi;
protected TTSController mTtsManager; protected TTSController mTtsManager;
private NaviLatLng mStartPoint; // 起点
private NaviLatLng mEndPoint; // 终点 //终点坐标
private double endLat,endLon; //终点坐标
private List<NaviLatLng> mWayPoints = new ArrayList<>(); // 途经点 private List<NaviLatLng> mWayPoints = new ArrayList<>(); // 途经点
protected final List<NaviLatLng> sList = new ArrayList<NaviLatLng>();
protected final List<NaviLatLng> eList = new ArrayList<NaviLatLng>();
protected List<NaviLatLng> mWayPointList = new ArrayList<NaviLatLng>();
//与定位相关 //与定位相关
private AMapLocationClient mapLocationClient; private AMapLocationClient mapLocationClient;
private AMapLocationClientOption mLocationOption; private AMapLocationClientOption mLocationOption;
private boolean isAutoStartLocation = false;
private AmapNaviType currentNaviType = AmapNaviType.WALK;
private NaviLatLng end;
private TextView tvRouteInfo;
private Button btnStartNavi;
private Button btnSwitchMode;
@SuppressLint("MissingInflatedId") @SuppressLint("MissingInflatedId")
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
// mNavi.setIsNaviTravelView(true);
setContentView(R.layout.activity_guide_map); // 获取传入的终点经纬度
// 1. 初始化导航组件 Intent intent = getIntent();
mNaviView = findViewById(R.id.naviView); endLat = intent.getDoubleExtra("end_lat", 0);
mNaviView.onCreate(savedInstanceState); endLon = intent.getDoubleExtra("end_lon", 0);
Log.d("GuideMap", "收到终点坐标: lat=" + endLat + ", lon=" + endLon);
Log.d("GuideMap", "接收到坐标:" + endLat + "," + endLon);
if (endLat < 1 || endLon < 1) {
Toast.makeText(this, "终点坐标可能异常", Toast.LENGTH_LONG).show();
}
end = new NaviLatLng(endLat,endLon);
startNaviToDestination(currentNaviType);
//
// mNaviView = findViewById(R.id.naviView);
// mNaviView.onCreate(savedInstanceState);
//
// mTtsManager = TTSController.getInstance(getApplicationContext());
// mTtsManager.init();
// mTtsManager.setTTSType(TTSController.TTSType.SYSTEMTTS);
// try {
// AMapNavi.getInstance(this).calculateWalkRoute(null,end);
// } catch (AMapException e) {
// throw new RuntimeException(e);
// }
try { try {
mNavi = AMapNavi.getInstance(getApplicationContext()); AMapNavi.getInstance(this).calculateWalkRoute(end);
mAMapNavi = AMapNavi.getInstance(getApplicationContext());
mAMapNavi.setUseInnerVoice(true,false);
AMapNavi.setTtsPlaying(true);
} catch (AMapException e) { } catch (AMapException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
mAMapNavi.addAMapNaviListener(mTtsManager);
mAMapNavi.playTTS("主人你好呀", false);
// mAMapNavi.startNavi(NaviType.EMULATOR);
//以上为新添加的 不知道怎么处理
// try {
// mAMapNavi = AMapNavi.getInstance(getApplicationContext());
// } catch (AMapException e) {
// throw new RuntimeException(e);
// }
// mAMapNavi.addAMapNaviListener(this);
// mAMapNavi.addAMapNaviListener(mTtsManager);
//
// // 🚩 设置为骑/步行视图(重要)
// mAMapNavi.setIsNaviTravelView(true);
//
// // 🚶 步行路线规划(起点为空)——无起点规划
// NaviLatLng end = new NaviLatLng(endLat, endLon);
// mAMapNavi.calculateWalkRoute(end); // 或 mAMapNavi.calculateRideRoute(end);
//
// // 初始化界面控件
// tvRouteInfo = findViewById(R.id.tvRouteInfo);
// btnStartNavi = findViewById(R.id.btnStartNavi);
// btnSwitchMode = findViewById(R.id.btnSwitchMode);
// // 切换模式按钮
// btnSwitchMode.setOnClickListener(new View.OnClickListener() {
// @Override
// public void onClick(View view) {
// if (currentNaviType == AmapNaviType.WALK) {
// currentNaviType = AmapNaviType.DRIVER;
// } else {
// currentNaviType = AmapNaviType.WALK;
// }
// updateRouteInfoText();
// }
// });
//
// // 开始导航按钮
// btnStartNavi.setOnClickListener(new View.OnClickListener() {
// @Override
// public void onClick(View view) {
// startNaviToDestination(currentNaviType);
// }
// });
// 2. 设置导航监听器
mNavi.addAMapNaviListener(this);
mNaviView.setAMapNaviViewListener(new AMapNaviViewListener() { mNaviView.setAMapNaviViewListener(new AMapNaviViewListener() {
@Override @Override
public void onNaviSetting() { public void onNaviSetting() {
@@ -122,12 +201,12 @@ public class GuideMap extends AppCompatActivity implements AMapNaviListener, AMa
} }
// 处理导航视图事件... // 处理导航视图事件...
}); });
mNaviView.setNaviMode(mNaviView.NORTH_UP_MODE);
initLocation();
// 3. 添加途经点(可选) // 3. 添加途经点(可选)
// mWayPoints.add(new NaviLatLng(39.993706, 116.400865)); // mWayPoints.add(new NaviLatLng(39.993706, 116.400865));
//初始化定位 //初始化定位
// initLocation(); // initLocation();
// mNaviView.setNaviMode(mNaviView.NORTH_UP_MODE);
} }
@Override @Override
public void onNaviSetting() { public void onNaviSetting() {
@@ -223,6 +302,22 @@ public class GuideMap extends AppCompatActivity implements AMapNaviListener, AMa
} }
private void updateRouteInfoText() {
String modeText = currentNaviType == AmapNaviType.WALK ? "步行模式" : "公交模式";
tvRouteInfo.setText("当前导航模式:" + modeText);
}
private void startNaviToDestination(AmapNaviType naviType) {
Poi end = new Poi("目的地", new LatLng(endLat, endLon), null);
AmapNaviParams params = new AmapNaviParams(null, null, end, naviType, AmapPageType.ROUTE);
params.setUseInnerVoice(true);
AmapNaviPage.getInstance().showRouteActivity(getApplicationContext(), params, null);
}
@Override @Override
protected void onResume() { protected void onResume() {
@@ -238,14 +333,25 @@ public class GuideMap extends AppCompatActivity implements AMapNaviListener, AMa
@Override @Override
protected void onDestroy() { protected void onDestroy() {
// super.onDestroy();
// mNaviView.onDestroy();
// //since 1.6.0 不再在naviview destroy的时候自动执行AMapNavi.stopNavi();请自行执行
// if (mAMapNavi!=null){
// mAMapNavi.stopNavi();
// mAMapNavi.destroy();
// }
super.onDestroy(); super.onDestroy();
mNaviView.onDestroy(); // if(mTtsManager != null)
//since 1.6.0 不再在naviview destroy的时候自动执行AMapNavi.stopNavi();请自行执行 // {
if (mNavi!=null){ // mTtsManager.stopSpeaking();
mNavi.stopNavi(); // mTtsManager.destroy();
mNavi.destroy(); // }
if(mAMapNavi != null)
{
// mAMapNavi.removeAMapNaviListener(mTtsManager);
mAMapNavi.stopNavi();
} }
mNaviView.onDestroy();
} }
@@ -257,8 +363,8 @@ public class GuideMap extends AppCompatActivity implements AMapNaviListener, AMa
@Override @Override
public void onInitNaviSuccess() { public void onInitNaviSuccess() {
//这里无需super 因为我是直接在父类上直接写 //这里无需super 因为我是直接在父类上直接写
mNavi.setTravelInfo(new AMapTravelInfo(TransportType.Walk)); mAMapNavi.setTravelInfo(new AMapTravelInfo(TransportType.Walk));
mNavi.calculateWalkRoute(new NaviLatLng(39.925846, 116.435765), new NaviLatLng(39.925846, 116.532765)); mAMapNavi.calculateWalkRoute(null, end);
} }
@Override @Override
@@ -273,7 +379,7 @@ public class GuideMap extends AppCompatActivity implements AMapNaviListener, AMa
@Override @Override
public void onLocationChange(AMapNaviLocation aMapNaviLocation) { public void onLocationChange(AMapNaviLocation aMapNaviLocation) {
aMapNaviLocation.getCoord();
} }
@Override @Override
@@ -413,7 +519,12 @@ public class GuideMap extends AppCompatActivity implements AMapNaviListener, AMa
@Override @Override
public void onCalculateRouteSuccess(AMapCalcRouteResult aMapCalcRouteResult) { public void onCalculateRouteSuccess(AMapCalcRouteResult aMapCalcRouteResult) {
mNavi.startNavi(NaviType.GPS); try {
AMapNavi.getInstance(this).startNavi(NaviType.GPS);
AMapNavi.getInstance(this.getApplicationContext()).setIsNaviTravelView(true);
} catch (AMapException e) {
throw new RuntimeException(e);
}
} }
@Override @Override

View File

@@ -201,7 +201,22 @@ public class RouteActivity extends AppCompatActivity implements
//初始化出行方式 //初始化出行方式
initTravelMode(); initTravelMode();
binding.buttonmy.setOnClickListener(v->startActivity(new Intent(this,GuideMap.class))); // 源码 --->
//binding.buttonmy.setOnClickListener(v->startActivity(new Intent(this,GuideMap.class)));
binding.buttonmy.setOnClickListener(v -> {
// 检查终点坐标是否存在
if (mEndPoint != null) {
Intent intent = new Intent(this, GuideMap.class);
// 将终点坐标放入Intent
intent.putExtra("end_lat", mEndPoint.getLatitude());
intent.putExtra("end_lon", mEndPoint.getLongitude());
Log.d("RouteActivity", "准备跳转 GuideMap终点" + mEndPoint.getLatitude() + "," + mEndPoint.getLongitude());
startActivity(intent);
} else {
Toast.makeText(this, "请先选择目的地", Toast.LENGTH_SHORT).show();
}
});
// 新加入的 // 新加入的
scanner = bluetoothAdapter.getBluetoothLeScanner(); scanner = bluetoothAdapter.getBluetoothLeScanner();
//不进行权限验证 //不进行权限验证

View File

@@ -0,0 +1,170 @@
package com.example.mangowalking.utils;
import static com.iflytek.cloud.SpeechSynthesizer.createSynthesizer;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.widget.Toast;
import com.amap.api.navi.AMapNavi;
import com.iflytek.cloud.ErrorCode;
import com.iflytek.cloud.InitListener;
import com.iflytek.cloud.SpeechConstant;
import com.iflytek.cloud.SpeechError;
import com.iflytek.cloud.SpeechSynthesizer;
import com.iflytek.cloud.SpeechUtility;
import com.iflytek.cloud.SynthesizerListener;
import java.util.LinkedList;
/**
* 当前DEMO的播报方式是队列模式。其原理就是依次将需要播报的语音放入链表中播报过程是从头开始依次往后播报。
* <p>
* 导航SDK原则上是不提供语音播报模块的如果您觉得此种播报方式不能满足你的需求请自行优化或改进。
*/
public class AmapTTSController {
private final String appId = "1342cc62";
public static AmapTTSController ttsManager;
private Context mContext;
private SpeechSynthesizer mTts;
private boolean isPlaying = false;
private LinkedList<String> wordList = new LinkedList();
private final int TTS_PLAY = 1;
private final int CHECK_TTS_PLAY = 2;
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case TTS_PLAY:
synchronized (mTts) {
if (!isPlaying && mTts != null && wordList.size() > 0) {
isPlaying = true;
String playtts = wordList.removeFirst();
if (mTts == null) {
createSynthesizer();
}
mTts.startSpeaking(playtts, new SynthesizerListener() {
@Override
public void onCompleted(SpeechError arg0) {
AMapNavi.setTtsPlaying(isPlaying = false);
handler.obtainMessage(1).sendToTarget();
}
@Override
public void onEvent(int arg0, int arg1, int arg2, Bundle arg3) {
}
@Override
public void onBufferProgress(int arg0, int arg1, int arg2, String arg3) {
// 合成进度
isPlaying = true;
}
@Override
public void onSpeakBegin() {
//开始播放
AMapNavi.setTtsPlaying(isPlaying = true);
}
@Override
public void onSpeakPaused() {
}
@Override
public void onSpeakProgress(int arg0, int arg1, int arg2) {
//播放进度
isPlaying = true;
}
@Override
public void onSpeakResumed() {
//继续播放
isPlaying = true;
}
});
}
}
break;
case CHECK_TTS_PLAY:
if (!isPlaying) {
handler.obtainMessage(1).sendToTarget();
}
break;
default:
}
}
};
private AmapTTSController(Context context) {
mContext = context.getApplicationContext();
SpeechUtility.createUtility(mContext, SpeechConstant.APPID + "=" + appId);
if (mTts == null) {
createSynthesizer();
}
}
private void createSynthesizer() {
mTts = SpeechSynthesizer.createSynthesizer(mContext,
new InitListener() {
@Override
public void onInit(int errorcode) {
if (ErrorCode.SUCCESS == errorcode) {
} else {
Toast.makeText(mContext, "语音合成初始化失败!", Toast.LENGTH_SHORT);
}
}
});
}
public void init() {
//设置发音人
mTts.setParameter(SpeechConstant.VOICE_NAME, "xiaoyan");
//设置语速,值范围:[0, 100],默认值50
mTts.setParameter(SpeechConstant.SPEED, "55");
//设置音量
mTts.setParameter(SpeechConstant.VOLUME, "tts_volume");
//设置语调
mTts.setParameter(SpeechConstant.PITCH, "tts_pitch");
}
public static AmapTTSController getInstance(Context context) {
if (ttsManager == null) {
ttsManager = new AmapTTSController(context);
}
return ttsManager;
}
public void stopSpeaking() {
if (wordList != null) {
wordList.clear();
}
if (mTts != null) {
mTts.stopSpeaking();
}
isPlaying = false;
}
public void destroy() {
if (wordList != null) {
wordList.clear();
}
if (mTts != null) {
mTts.destroy();
}
}
public void onGetNavigationText(String arg1) {
if (wordList != null){
wordList.addLast(arg1);
}
handler.obtainMessage(CHECK_TTS_PLAY).sendToTarget();
}
};

View File

@@ -0,0 +1,6 @@
package com.example.mangowalking.utils;
public interface IBuilder<T> {
T build();
}

View File

@@ -11,12 +11,14 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" /> android:layout_height="match_parent" />
<!-- 顶部状态信息栏 -->
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="horizontal" android:orientation="horizontal"
android:background="#80000000" android:background="#80000000"
android:padding="8dp"> android:padding="8dp"
android:layout_gravity="top">
<TextView <TextView
android:id="@+id/tvRouteInfo" android:id="@+id/tvRouteInfo"
android:layout_width="0dp" android:layout_width="0dp"
@@ -24,11 +26,12 @@
android:layout_weight="1" android:layout_weight="1"
android:textColor="#FFFFFF" android:textColor="#FFFFFF"
android:textSize="16sp" android:textSize="16sp"
android:gravity="center"/> android:gravity="center" />
</LinearLayout> </LinearLayout>
<!-- 底部控制栏 --> <!-- 底部控制栏 -->
<LinearLayout <LinearLayout
android:id="@+id/bottomBar"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="bottom" android:layout_gravity="bottom"
@@ -42,7 +45,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_weight="1" android:layout_weight="1"
android:text="开始导航" android:text="开始导航"
android:textAllCaps="false"/> android:textAllCaps="false" />
<Button <Button
android:id="@+id/btnSwitchMode" android:id="@+id/btnSwitchMode"
@@ -50,7 +53,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_weight="1" android:layout_weight="1"
android:text="切换模式" android:text="切换模式"
android:textAllCaps="false"/> android:textAllCaps="false" />
</LinearLayout> </LinearLayout>