This commit is contained in:
parent
1fb64b7770
commit
e943361349
|
|
@ -17,7 +17,7 @@ android {
|
|||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||
|
||||
ndk {
|
||||
abiFilters.addAll(listOf("armeabi-v7a","x86"))
|
||||
abiFilters.addAll(listOf("armeabi-v7a"))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@
|
|||
' setInterval(function() {',
|
||||
' var code = prompt("bridge:_poll", "");',
|
||||
' if (code) { try { eval(code); } catch(e) {} }',
|
||||
' }, 500);',
|
||||
' }, 1000);',
|
||||
'})();'
|
||||
].join('\n');
|
||||
|
||||
|
|
|
|||
|
|
@ -4,12 +4,15 @@ import android.media.AudioFormat;
|
|||
import android.media.AudioRecord;
|
||||
import android.media.MediaRecorder;
|
||||
import android.util.Log;
|
||||
|
||||
import com.stand.standapp.MyApplication;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
@SuppressWarnings("ResultOfMethodCallIgnored")
|
||||
public class AudioRecordManager {
|
||||
private final String TAG = "AudioRecordManager";
|
||||
private static final int FREQUENCY = 8000;
|
||||
private static final int FREQUENCY = 8000; //16K采集率
|
||||
private AudioRecord mRecorder;
|
||||
private Thread recordThread;
|
||||
private boolean isStart = false;
|
||||
|
|
@ -22,6 +25,7 @@ public class AudioRecordManager {
|
|||
}
|
||||
|
||||
public void initAudio() {
|
||||
//一、实例化一个AudioRecord类
|
||||
int audioSource = MediaRecorder.AudioSource.MIC;
|
||||
mRecorder = new AudioRecord(audioSource,
|
||||
FREQUENCY,
|
||||
|
|
@ -119,6 +123,7 @@ public class AudioRecordManager {
|
|||
return;
|
||||
}
|
||||
mRecorder.startRecording();
|
||||
int count = 0;
|
||||
while (isStart) {
|
||||
if (null != mRecorder) {
|
||||
bytesRecord = mRecorder.read(tempBuffer, 0, bufferSize);
|
||||
|
|
@ -147,6 +152,7 @@ public class AudioRecordManager {
|
|||
public void startRecord() {
|
||||
try {
|
||||
stopRecord();
|
||||
|
||||
startThread();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
|
|
@ -158,7 +164,6 @@ public class AudioRecordManager {
|
|||
*/
|
||||
public void stopRecord() {
|
||||
try {
|
||||
isStart = false;
|
||||
destroyThread();
|
||||
if (mRecorder != null) {
|
||||
try {
|
||||
|
|
@ -171,6 +176,7 @@ public class AudioRecordManager {
|
|||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,14 @@
|
|||
package com.example.kingway.ptt;
|
||||
|
||||
import timber.log.Timber;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**解析接收到的AT指令*/
|
||||
public class CallBackResolution {
|
||||
|
|
@ -41,16 +47,16 @@ public class CallBackResolution {
|
|||
|
||||
String ngx = "\\u";
|
||||
try {
|
||||
Timber.tag(TAG).i("lisHex-->" + lisHex.toString());
|
||||
Log.i(TAG, "lisHex-->" + lisHex.toString());
|
||||
String firstHex = lisHex.get(0);
|
||||
String errorNum = lisHex.get(1);
|
||||
Timber.tag(TAG).d("at_OEM_AT_cb firstHex: " + firstHex + ", errorNum: " + errorNum);
|
||||
Log.d(TAG, "at_OEM_AT_cb firstHex: " + firstHex + ", errorNum: " + errorNum);
|
||||
switch (firstHex){
|
||||
case "82"://登录状态通知指令
|
||||
String loginId = lisHex.get(2) + "" + lisHex.get(3) + "" + lisHex.get(4) + "" + lisHex.get(5);
|
||||
pttLoginStatus = errorNum;
|
||||
pttLoginId = loginId;
|
||||
Timber.tag(TAG).i("PTT login status: %s, id: %s", pttLoginStatus, pttLoginId);
|
||||
Log.d(TAG,"PTT login status: "+pttLoginStatus+", id: "+pttLoginId);
|
||||
// 实时推送状态到前端
|
||||
com.stand.standapp.MainActivity.executeJs("updatePttLoginStatus('" + pttLoginStatus + "','" + pttLoginId + "')");
|
||||
CallBackUtil.callBackLoinState(errorNum, loginId);
|
||||
|
|
@ -64,7 +70,6 @@ public class CallBackResolution {
|
|||
}
|
||||
break;
|
||||
|
||||
|
||||
case "a2"://账号有视频功能
|
||||
CallBackUtil.callBackHaveVideo();
|
||||
break;
|
||||
|
|
@ -81,17 +86,17 @@ public class CallBackResolution {
|
|||
break;
|
||||
|
||||
case "0b"://发起讲话返回状态
|
||||
Timber.tag(TAG).d("at_OEM_AT_cb ptt speak...");
|
||||
Log.d(TAG, "at_OEM_AT_cb ptt speak...");
|
||||
CallBackUtil.callBackSpeakPlaySuccess(errorNum.equals("00")? true : false);
|
||||
break;
|
||||
|
||||
case "0c"://结束讲话返回状态
|
||||
Timber.tag(TAG).d("at_OEM_AT_cb speak end...");
|
||||
Log.d(TAG, "at_OEM_AT_cb speak end...");
|
||||
CallBackUtil.callBackSpeakReleaseSuccess(errorNum.equals("00")? true : false);
|
||||
break;
|
||||
|
||||
case "80"://返回群组信息
|
||||
Timber.tag(TAG).d("at_OEM_AT_cb get group info: " + lisHex);
|
||||
Log.d(TAG, "at_OEM_AT_cb get group info: " + lisHex);
|
||||
String strGroup = "";
|
||||
String groupId = lisHex.get(6) + "" + lisHex.get(7) + "" + lisHex.get(8) + "" + lisHex.get(9);
|
||||
int groupNo = Integer.valueOf((lisHex.get(4) + "" + lisHex.get(5)), 16);
|
||||
|
|
@ -114,9 +119,9 @@ public class CallBackResolution {
|
|||
} finally {
|
||||
String tempTxt = "";
|
||||
tempTxt = unicodeToString(strGroup);
|
||||
Timber.tag(TAG).i(" 组名称 " + tempTxt);
|
||||
Log.i(TAG, " 组名称 " + tempTxt);
|
||||
CallBackUtil.callBackGroupInfo(groupId, tempTxt, groupNo, groupCount);
|
||||
Timber.tag(TAG).d("at_OEM_AT_cb group info groupId: " + groupId + ", groupNo: " + groupNo+", groupCount: " +groupCount);
|
||||
Log.d(TAG, "at_OEM_AT_cb group info groupId: " + groupId + ", groupNo: " + groupNo+", groupCount: " +groupCount);
|
||||
if (1 == groupNo) groupInfos.clear();
|
||||
GroupInfoDto groupInfo = new GroupInfoDto(groupId, tempTxt, groupNo, groupCount);
|
||||
groupInfos.add(groupInfo);
|
||||
|
|
@ -149,8 +154,6 @@ public class CallBackResolution {
|
|||
GroupMemberInfoDto infoDto = new GroupMemberInfoDto(memberId, tempTxt, status, memberNo, haveVideo);
|
||||
if (memberNo == 1) memberInfoDtos.clear();
|
||||
memberInfoDtos.add(infoDto);
|
||||
//输出群成员信息memberInfoDtos
|
||||
Timber.tag(TAG).d("at_OEM_AT_cb group member info: " + infoDto);
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
@ -226,7 +229,7 @@ public class CallBackResolution {
|
|||
for (int i = 0; i < stringsTalk.size(); i++) {
|
||||
tempTxt += unicode(stringsTalk.get(i));
|
||||
}
|
||||
Timber.tag(TAG).i(" 临时讲话 信息通知的指令 " + tempTxt);
|
||||
Log.i(TAG, " 临时讲话 信息通知的指令 " + tempTxt);
|
||||
CallBackUtil.callBackTempCallNotify(tempTxt);
|
||||
}
|
||||
break;
|
||||
|
|
@ -259,7 +262,7 @@ public class CallBackResolution {
|
|||
for (int i = 0; i < stringsJumpGroup.size(); i++) {
|
||||
userGroupName += unicode(stringsJumpGroup.get(i));
|
||||
}
|
||||
Timber.tag(TAG).i("进入群组 " + userGroupName);
|
||||
Log.i(TAG,"进入群组 " + userGroupName);
|
||||
indexGroupId = userGroupId;
|
||||
indexGroupName = userGroupName;
|
||||
CallBackUtil.callBackNotifyUpdateGroup(userGroupId, userGroupName);
|
||||
|
|
@ -286,7 +289,7 @@ public class CallBackResolution {
|
|||
String time = strLis[2];
|
||||
CallBackUtil.callBackNotifyLocationStatus(0, locationMemberId, latitude, longitude, time);
|
||||
} catch (Exception e) {
|
||||
Timber.tag(TAG).e(e, "获取定位Exception");
|
||||
Log.e(TAG, "获取定位Exception-->" + e.getMessage());
|
||||
}
|
||||
} else {
|
||||
CallBackUtil.callBackNotifyLocationStatus(1, "", 0.0, 0.0, "");
|
||||
|
|
@ -340,14 +343,14 @@ public class CallBackResolution {
|
|||
List<String> strName = new ArrayList<>();
|
||||
double latitude = 0.0, longitude = 0.0;
|
||||
try {
|
||||
String string = "";
|
||||
for (int i = 4; i < lisHex.size(); i++) {
|
||||
string += lisHex.get(i).toString();
|
||||
}
|
||||
String address = hexString2String(string);
|
||||
Timber.tag(TAG).i("address-->" + address);
|
||||
String string = "";
|
||||
for (int i = 4; i < lisHex.size(); i++) {
|
||||
string += lisHex.get(i).toString();
|
||||
}
|
||||
String address = hexString2String(string);
|
||||
Log.i(TAG, "address-->" + address);
|
||||
|
||||
String[] strLis = address.split(",");
|
||||
String[] strLis = address.split(",");
|
||||
latitude = Double.parseDouble(strLis[0]);
|
||||
longitude = Double.parseDouble(strLis[1]);
|
||||
int size = lisHex.size() - (8 + strLis[0].length() + strLis[1].length());
|
||||
|
|
@ -387,24 +390,41 @@ public class CallBackResolution {
|
|||
break;
|
||||
}
|
||||
}catch (Exception e){
|
||||
Timber.tag(TAG).e(e, "at_OEM_AT_cb Exception");
|
||||
Log.e(TAG,"at_OEM_AT_cb Exception " + e.getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断登录状态冲突, 1min内超过5次状态切换则视为登录冲突
|
||||
* state
|
||||
* 0 : 离线
|
||||
* 1 : 登陆中
|
||||
* 2 : 登陆成功
|
||||
* 3 : 注销中
|
||||
* 说明:第一次登录 通知状态 先01再02,
|
||||
* 离线再上线 通知状态 先00再01
|
||||
* tip:1min内会出现40次左右0-1切换
|
||||
*/
|
||||
public static boolean isLoginConflict(String state) {
|
||||
Log.d(TAG, " isLoginConflict state: " + state + ",oldLoginSate: " + oldLoginSate + ", logNum: " + logNum);
|
||||
if (oldLoginSate.equals("00") && state.equals("01")) {
|
||||
Log.d(TAG, "isLoginConflict first login...");
|
||||
logNum++;
|
||||
oldLoginSate = state;
|
||||
} else if (oldLoginSate.equals("01") && state.equals("00")) {
|
||||
Log.d(TAG, "isLoginConflict login state changed...");
|
||||
logNum++;
|
||||
oldLoginSate = state;
|
||||
}
|
||||
if (1 == logNum) {
|
||||
offlineTime = System.currentTimeMillis();
|
||||
}
|
||||
Log.d(TAG, "isLoginConflict logNum: " + logNum + ", offlineTime: " + offlineTime);
|
||||
if (logNum > 4) {
|
||||
Log.d(TAG, "isLoginConflict current time: " + System.currentTimeMillis() + ", diffTime: " + (System.currentTimeMillis() - offlineTime));
|
||||
if (System.currentTimeMillis() - offlineTime >= 60 * 1000) {
|
||||
Log.d(TAG, "isLoginConflict login state changed: " + logNum + " in 1min");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -415,6 +435,8 @@ public class CallBackResolution {
|
|||
try {
|
||||
String[] txt = sData.split("\"");
|
||||
String data = txt[1];
|
||||
Log.d(TAG, "at_Play_TTS_cb sData: " + sData);
|
||||
|
||||
String ngx = "\\u";
|
||||
List<String> strings = new ArrayList<>();
|
||||
|
||||
|
|
@ -443,18 +465,23 @@ public class CallBackResolution {
|
|||
for (int k = 0; k < strings.size(); k++) {
|
||||
tempTxt += unicode(strings.get(k));
|
||||
}
|
||||
Log.i(TAG,"at_Play_TTS_cb " + tempTxt);
|
||||
if (tempTxt.contains("已登录")) {
|
||||
String showName = tempTxt.substring(3, tempTxt.length());
|
||||
CallBackUtil.callBackLogin(true, showName);
|
||||
java.util.concurrent.ScheduledExecutorService executor = java.util.concurrent.Executors.newScheduledThreadPool(1);
|
||||
ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
|
||||
Runnable task = () -> {
|
||||
Log.d(TAG, "callBackLogin send tcp and udp");
|
||||
SendAtUtil.sendUDP();
|
||||
SendAtUtil.sendTCP();
|
||||
};
|
||||
executor.scheduleAtFixedRate(task, 0, 40, java.util.concurrent.TimeUnit.SECONDS);
|
||||
executor.scheduleAtFixedRate(task, 0, 40, TimeUnit.SECONDS);
|
||||
} else if (tempTxt.contains("账号已更新")) {
|
||||
} else if (tempTxt.contains("账号或密码错误")) {
|
||||
CallBackUtil.callBackLogin(false, "");
|
||||
}else if (tempTxt.contains("请配置账号")) {
|
||||
}
|
||||
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
|
|
@ -463,8 +490,9 @@ public class CallBackResolution {
|
|||
|
||||
|
||||
public static String unicode(String str) {
|
||||
java.util.regex.Pattern pattern = java.util.regex.Pattern.compile("(\\\\u(\\p{XDigit}{4}))");
|
||||
java.util.regex.Matcher matcher = pattern.matcher(str);
|
||||
|
||||
Pattern pattern = Pattern.compile("(\\\\u(\\p{XDigit}{4}))");
|
||||
Matcher matcher = pattern.matcher(str);
|
||||
char ch;
|
||||
while (matcher.find()) {
|
||||
String group = matcher.group(2);
|
||||
|
|
@ -480,9 +508,13 @@ public class CallBackResolution {
|
|||
StringBuilder str = new StringBuilder();
|
||||
for (int i = 0; i < t; i++) {
|
||||
String s = hex.substring(i * 6, (i + 1) * 6);
|
||||
// 高位需要补上00再转
|
||||
String s1 = s.substring(2, 4) + "00";
|
||||
// 低位直接转
|
||||
String s2 = s.substring(4);
|
||||
// 将16进制的string转为int
|
||||
int n = Integer.valueOf(s1, 16) + Integer.valueOf(s2, 16);
|
||||
// 将int转换为字符
|
||||
char[] chars = Character.toChars(n);
|
||||
str.append(new String(chars));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
package com.example.kingway.ptt;
|
||||
|
||||
import android.os.Handler;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,11 @@ package com.example.kingway.ptt;
|
|||
|
||||
/**
|
||||
* <pre>
|
||||
* author : GaryLiang
|
||||
* e-mail : 595184932@qq.com
|
||||
* time : 2017/11/21 上午9:09
|
||||
* desc : 组
|
||||
* version: 1.0
|
||||
* </pre>
|
||||
*/
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,11 @@ import java.io.Serializable;
|
|||
|
||||
/**
|
||||
* <pre>
|
||||
* author : GaryLiang
|
||||
* e-mail : 595184932@qq.com
|
||||
* time : 2017/11/21 上午9:09
|
||||
* desc : 组 成员
|
||||
* version: 1.0
|
||||
* </pre>
|
||||
*/
|
||||
|
||||
|
|
|
|||
|
|
@ -1,60 +0,0 @@
|
|||
package com.example.kingway.ptt;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
|
||||
public class MyApplication {
|
||||
private static Context mContext;
|
||||
public static String pageName = "";
|
||||
public static pttNative pNative;
|
||||
private static MyApplication mAppInstance = new MyApplication();
|
||||
|
||||
public static void init(Context context) {
|
||||
if (mContext != null) return;
|
||||
mContext = context.getApplicationContext();
|
||||
pageName = mContext.getPackageName();
|
||||
initPTT();
|
||||
}
|
||||
|
||||
public static MyApplication getAppInstance() {
|
||||
if (pNative == null && mContext != null) {
|
||||
initPTT();
|
||||
}
|
||||
return mAppInstance;
|
||||
}
|
||||
|
||||
public pttNative getpNative() {
|
||||
return pNative;
|
||||
}
|
||||
|
||||
public static void initPTT() {
|
||||
if (pNative != null) return;
|
||||
try {
|
||||
pNative = new pttNative();
|
||||
|
||||
pNative.pttNativeSetPackageName(pageName);
|
||||
pNative.pttNativeSetAtCallback();
|
||||
pNative.pttNativeSetPlayCallback();
|
||||
pNative.pttNativeSetPalyStartCallback();
|
||||
pNative.pttNativeSetPlayStopCallback();
|
||||
pNative.pttNativeSetRecordStartCallback();
|
||||
pNative.pttNativeSetRecordStopCallback();
|
||||
pNative.pttNativeSetTTSCallback();
|
||||
|
||||
pNative.pttNativePocTaskStart();
|
||||
Log.i("PTT_INIT", "PTT init success");
|
||||
} catch (Throwable e) {
|
||||
Log.e("PTT_INIT", "Failed to init PTT: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public static void destroy() {
|
||||
if (pNative != null) {
|
||||
pNative.destory();
|
||||
pNative = null;
|
||||
}
|
||||
mContext = null;
|
||||
mAppInstance = new MyApplication();
|
||||
CallBackResolution.resetPttLoginStatus();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,7 @@
|
|||
package com.example.kingway.ptt;
|
||||
|
||||
import com.stand.standapp.MyApplication;
|
||||
|
||||
import timber.log.Timber;
|
||||
|
||||
/**
|
||||
|
|
@ -16,6 +18,13 @@ public class SendAtUtil {
|
|||
sendRawCmd(cmd);
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消登录接口 (清除服务端/本地登录状态)
|
||||
*/
|
||||
public static void toCancelLogin() {
|
||||
send("050000\r\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* 账号注销接口
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1,20 +1,13 @@
|
|||
package com.example.kingway.ptt;
|
||||
|
||||
import android.graphics.Color;
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.Arrays;
|
||||
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
import com.hjq.permissions.Permission;
|
||||
import com.hjq.permissions.XXPermissions;
|
||||
import com.stand.standapp.R;
|
||||
|
|
@ -26,21 +19,22 @@ public class pttActivity extends AppCompatActivity {
|
|||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_ptt);
|
||||
pttBtn = (Button) findViewById(R.id.pttBtn);
|
||||
|
||||
// 初始化 PTT
|
||||
MyApplication.init(this);
|
||||
|
||||
pttBtn = (Button)findViewById(R.id.pttBtn);
|
||||
XXPermissions.with(this)
|
||||
.permission(Permission.RECORD_AUDIO)
|
||||
.request(null);
|
||||
pttBtn.setOnTouchListener(new View.OnTouchListener() {
|
||||
pttBtn.setOnTouchListener(new View.OnTouchListener()
|
||||
{
|
||||
@Override
|
||||
public boolean onTouch(View view, MotionEvent motionEvent) {
|
||||
if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
|
||||
public boolean onTouch(View view, MotionEvent motionEvent)
|
||||
{
|
||||
if (motionEvent.getAction() == MotionEvent.ACTION_DOWN)
|
||||
{
|
||||
pttBtn.setBackgroundColor(Color.RED);
|
||||
SendAtUtil.speakPlay();
|
||||
} else if (motionEvent.getAction() == MotionEvent.ACTION_UP) {
|
||||
}
|
||||
else if(motionEvent.getAction() == MotionEvent.ACTION_UP)
|
||||
{
|
||||
pttBtn.setBackgroundColor(Color.BLUE);
|
||||
SendAtUtil.speakRelease();
|
||||
}
|
||||
|
|
@ -52,6 +46,14 @@ public class pttActivity extends AppCompatActivity {
|
|||
findViewById(R.id.login).setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
SendAtUtil.toLogin("gzzdweb01", "123456", "61.243.1.123", 1, 1);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
findViewById(R.id.login1).setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
// SendAtUtil.toLogin("gzzdweb01", "123456", "61.243.1.123", 1, 1);
|
||||
SendAtUtil.toLogin("test004", "123456", "220.154.131.231", 1, 1);
|
||||
}
|
||||
|
|
@ -80,5 +82,20 @@ public class pttActivity extends AppCompatActivity {
|
|||
SendAtUtil.jumpGroup("00000001");
|
||||
}
|
||||
});
|
||||
|
||||
findViewById(R.id.btnCancel1).setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
SendAtUtil.toCancelLogin();
|
||||
}
|
||||
});
|
||||
|
||||
/** 切换群组 */
|
||||
findViewById(R.id.btnCancel2).setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
SendAtUtil.toLogout();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ public class pttNative {
|
|||
public void OEM_AT_cb(String sData)
|
||||
{
|
||||
Log.e(TAG,"Poc2 AT Callback: " + sData);
|
||||
int len, i;
|
||||
int len, i, j=0;
|
||||
char[] bytes = sData.toCharArray();
|
||||
|
||||
List<String> lisHex = new ArrayList<>();
|
||||
|
|
@ -215,9 +215,9 @@ public class pttNative {
|
|||
int mAudioMinBufSize = AudioTrack.getMinBufferSize(8000, AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT);
|
||||
|
||||
AudioAttributes audioAttributes = new AudioAttributes.Builder()
|
||||
.setUsage(AudioAttributes.USAGE_MEDIA)
|
||||
.setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
|
||||
.setLegacyStreamType(AudioManager.STREAM_MUSIC)
|
||||
.setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION) // 通信场景
|
||||
.setContentType(AudioAttributes.CONTENT_TYPE_MUSIC) // 内容类型
|
||||
.setLegacyStreamType(AudioManager.STREAM_MUSIC) // 设置通话流类型
|
||||
.build();
|
||||
|
||||
AudioFormat audioFormat = new AudioFormat.Builder()
|
||||
|
|
@ -233,7 +233,7 @@ public class pttNative {
|
|||
AudioTrack.MODE_STREAM,
|
||||
AudioManager.AUDIO_SESSION_ID_GENERATE
|
||||
);
|
||||
mAudioTrack.setVolume(1.0f);
|
||||
mAudioTrack.setVolume(1.0f);// 设置音量
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package com.stand.standapp
|
|||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.os.Process
|
||||
import android.widget.*
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
|
|
@ -64,8 +65,30 @@ class LoginActivity : AppCompatActivity() {
|
|||
|
||||
// 4. 退出按钮
|
||||
btnExit.setOnClickListener {
|
||||
pttLogoutAndDestroy()
|
||||
finish()
|
||||
// fullCleanup()
|
||||
// finishAffinity()
|
||||
// android.os.Process.killProcess(android.os.Process.myPid())
|
||||
try {
|
||||
// com.example.kingway.ptt.MyApplication.init(this@LoginActivity)
|
||||
// Thread.sleep(500)
|
||||
// com.example.kingway.ptt.SendAtUtil.toCancelLogin()
|
||||
// com.example.kingway.ptt.SendAtUtil.toLogout()
|
||||
} catch (e: Exception) {
|
||||
Timber.tag("PTT").e(e, "PTT init error")
|
||||
}
|
||||
Thread {
|
||||
try {
|
||||
Thread.sleep(500)
|
||||
runOnUiThread {
|
||||
Toast.makeText(this@LoginActivity, "PTT初始化中", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
Thread.sleep(3000)
|
||||
com.example.kingway.ptt.SendAtUtil.toLogin("gzz22222", "1111", "61.243.1.123", 1, 1)
|
||||
// com.example.kingway.ptt.SendAtUtil.toLogin("gzzdweb01", "123456", "61.243.1.123", 1, 1)
|
||||
} catch (e: Exception) {
|
||||
Timber.tag("PTT").e(e, "PTT login error")
|
||||
}
|
||||
}.start()
|
||||
}
|
||||
|
||||
// 5. 彩蛋:点击底部版权 10 次进入开发者模式
|
||||
|
|
@ -139,9 +162,9 @@ class LoginActivity : AppCompatActivity() {
|
|||
|
||||
Toast.makeText(this@LoginActivity, "登录成功", Toast.LENGTH_SHORT).show()
|
||||
|
||||
// 1. PTT 引擎初始化并异步登录 (避免阻塞 UI)
|
||||
// 1. PTT 引擎强制重置后登录 (销毁旧 session,确保干净状态)
|
||||
try {
|
||||
com.example.kingway.ptt.MyApplication.init(this@LoginActivity)
|
||||
com.example.kingway.ptt.SendAtUtil.toCancelLogin()
|
||||
com.example.kingway.ptt.SendAtUtil.toLogout()
|
||||
} catch (e: Exception) {
|
||||
Timber.tag("PTT").e(e, "PTT init error")
|
||||
|
|
@ -152,7 +175,7 @@ class LoginActivity : AppCompatActivity() {
|
|||
runOnUiThread {
|
||||
Toast.makeText(this@LoginActivity, "PTT初始化中", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
Thread.sleep(1500)
|
||||
Thread.sleep(3000)
|
||||
com.example.kingway.ptt.SendAtUtil.toLogin("gzzdweb01", "123456", "61.243.1.123", 1, 1)
|
||||
} catch (e: Exception) {
|
||||
Timber.tag("PTT").e(e, "PTT login error")
|
||||
|
|
@ -240,14 +263,24 @@ class LoginActivity : AppCompatActivity() {
|
|||
.setTitle("提示")
|
||||
.setMessage("确定要退出应用吗?")
|
||||
.setPositiveButton("确定") { _, _ ->
|
||||
pttLogoutAndDestroy()
|
||||
finish()
|
||||
fullCleanup()
|
||||
finishAffinity()
|
||||
Process.killProcess(Process.myPid())
|
||||
}
|
||||
.setNegativeButton("取消", null)
|
||||
.show()
|
||||
}
|
||||
|
||||
private fun fullCleanup() {
|
||||
pttLogoutAndDestroy()
|
||||
}
|
||||
|
||||
private fun pttLogoutAndDestroy() {
|
||||
try {
|
||||
com.example.kingway.ptt.SendAtUtil.toCancelLogin()
|
||||
} catch (e: Exception) {
|
||||
Timber.tag("LoginActivity").e(e, "PTT cancel failed")
|
||||
}
|
||||
try {
|
||||
com.example.kingway.ptt.SendAtUtil.toLogout()
|
||||
Timber.tag("LoginActivity").i("PTT logout sent")
|
||||
|
|
@ -255,10 +288,32 @@ class LoginActivity : AppCompatActivity() {
|
|||
Timber.tag("LoginActivity").e(e, "PTT logout failed")
|
||||
}
|
||||
try {
|
||||
com.example.kingway.ptt.MyApplication.destroy()
|
||||
com.stand.standapp.utils.GpioManager.stopListening()
|
||||
} catch (e: Exception) {
|
||||
Timber.tag("LoginActivity").e(e, "GPIO stop failed")
|
||||
}
|
||||
try {
|
||||
com.stand.standapp.utils.GpioManager.stopListening()
|
||||
} catch (e: Exception) {
|
||||
Timber.tag("LoginActivity").e(e, "GPIO stop failed")
|
||||
}
|
||||
try {
|
||||
// MyApplication.destroy()
|
||||
Timber.tag("LoginActivity").i("PTT native destroyed")
|
||||
} catch (e: Exception) {
|
||||
Timber.tag("LoginActivity").e(e, "PTT destroy failed")
|
||||
}
|
||||
try {
|
||||
// PrinterManager.shutdown()
|
||||
Timber.tag("LoginActivity").i("Printer shut down")
|
||||
} catch (e: Exception) {
|
||||
Timber.tag("LoginActivity").e(e, "Printer shutdown failed")
|
||||
}
|
||||
try {
|
||||
com.stand.standapp.utils.LogManager.shutdown()
|
||||
Timber.tag("LoginActivity").i("LogManager shut down")
|
||||
} catch (e: Exception) {
|
||||
Timber.tag("LoginActivity").e(e, "LogManager shutdown failed")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,15 +61,15 @@ class MainActivity : AppCompatActivity() {
|
|||
.setMessage("您的 PTT 账号已在其他设备登录,当前设备已被迫下线。\n请点击确认退出并重新登录。")
|
||||
.setCancelable(false)
|
||||
.setPositiveButton("确认") { _, _ ->
|
||||
try {
|
||||
com.example.kingway.ptt.SendAtUtil.toLogout()
|
||||
com.example.kingway.ptt.MyApplication.destroy()
|
||||
com.stand.standapp.utils.GpioManager.stopListening()
|
||||
} catch (_: Exception) {}
|
||||
val pm = ctx.packageManager
|
||||
val intent = pm.getLaunchIntentForPackage(ctx.packageName)
|
||||
intent?.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
ctx.startActivity(intent)
|
||||
// try {
|
||||
// com.example.kingway.ptt.SendAtUtil.toLogout()
|
||||
// com.example.kingway.ptt.MyApplication.destroy()
|
||||
// com.stand.standapp.utils.GpioManager.stopListening()
|
||||
// } catch (_: Exception) {}
|
||||
// val pm = ctx.packageManager
|
||||
// val intent = pm.getLaunchIntentForPackage(ctx.packageName)
|
||||
// intent?.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
// ctx.startActivity(intent)
|
||||
android.os.Process.killProcess(android.os.Process.myPid())
|
||||
}
|
||||
.show()
|
||||
|
|
@ -263,32 +263,55 @@ class MainActivity : AppCompatActivity() {
|
|||
.setTitle("提示")
|
||||
.setMessage("确定要退出应用吗?")
|
||||
.setPositiveButton("确定") { _, _ ->
|
||||
pttLogoutAndDestroy()
|
||||
finish()
|
||||
// pttLogoutAndDestroy()
|
||||
finishAffinity()
|
||||
android.os.Process.killProcess(android.os.Process.myPid())
|
||||
}
|
||||
.setNegativeButton("取消", null)
|
||||
.show()
|
||||
}
|
||||
|
||||
private fun pttLogoutAndDestroy() {
|
||||
try {
|
||||
com.example.kingway.ptt.SendAtUtil.toLogout()
|
||||
Timber.tag("MainActivity").i("PTT logout sent")
|
||||
} catch (e: Exception) {
|
||||
Timber.tag("MainActivity").e(e, "PTT logout failed")
|
||||
}
|
||||
try {
|
||||
com.stand.standapp.utils.GpioManager.stopListening()
|
||||
} catch (e: Exception) {
|
||||
Timber.tag("MainActivity").e(e, "GPIO stop failed")
|
||||
}
|
||||
try {
|
||||
com.example.kingway.ptt.MyApplication.destroy()
|
||||
Timber.tag("MainActivity").i("PTT native destroyed")
|
||||
} catch (e: Exception) {
|
||||
Timber.tag("MainActivity").e(e, "PTT destroy failed")
|
||||
}
|
||||
}
|
||||
// private fun pttLogoutAndDestroy() {
|
||||
// try {
|
||||
// com.example.kingway.ptt.SendAtUtil.toCancelLogin()
|
||||
// } catch (e: Exception) {
|
||||
// Timber.tag("LoginActivity").e(e, "PTT cancel failed")
|
||||
// }
|
||||
// try {
|
||||
// com.example.kingway.ptt.SendAtUtil.toLogout()
|
||||
// Timber.tag("LoginActivity").i("PTT logout sent")
|
||||
// } catch (e: Exception) {
|
||||
// Timber.tag("LoginActivity").e(e, "PTT logout failed")
|
||||
// }
|
||||
// try {
|
||||
// com.stand.standapp.utils.GpioManager.stopListening()
|
||||
// } catch (e: Exception) {
|
||||
// Timber.tag("MainActivity").e(e, "GPIO stop failed")
|
||||
// }
|
||||
// try {
|
||||
// com.stand.standapp.utils.GpioManager.stopListening()
|
||||
// } catch (e: Exception) {
|
||||
// Timber.tag("LoginActivity").e(e, "GPIO stop failed")
|
||||
// }
|
||||
// try {
|
||||
// com.example.kingway.ptt.MyApplication.destroy()
|
||||
// Timber.tag("LoginActivity").i("PTT native destroyed")
|
||||
// } catch (e: Exception) {
|
||||
// Timber.tag("LoginActivity").e(e, "PTT destroy failed")
|
||||
// }
|
||||
// try {
|
||||
//// PrinterManager.shutdown()
|
||||
// Timber.tag("LoginActivity").i("Printer shut down")
|
||||
// } catch (e: Exception) {
|
||||
// Timber.tag("LoginActivity").e(e, "Printer shutdown failed")
|
||||
// }
|
||||
// try {
|
||||
// com.stand.standapp.utils.LogManager.shutdown()
|
||||
// Timber.tag("LoginActivity").i("LogManager shut down")
|
||||
// } catch (e: Exception) {
|
||||
// Timber.tag("LoginActivity").e(e, "LogManager shutdown failed")
|
||||
// }
|
||||
// }
|
||||
|
||||
override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
|
||||
if (keyCode == KeyEvent.KEYCODE_BACK) {
|
||||
|
|
|
|||
|
|
@ -1,50 +1,112 @@
|
|||
package com.stand.standapp
|
||||
|
||||
import android.app.Application
|
||||
import android.util.Log
|
||||
import com.example.kingway.ptt.pttNative
|
||||
import com.stand.standapp.utils.LogManager
|
||||
import com.example.kingway.ptt.MyApplication as PTTMyApplication
|
||||
import timber.log.Timber
|
||||
|
||||
class MyApplication : Application() {
|
||||
|
||||
// companion object {
|
||||
// private var instance: MyApplication? = null
|
||||
// fun getAppInstance(): MyApplication = instance ?: error("MyApplication not yet initialized")
|
||||
// }
|
||||
|
||||
// override fun onCreate() {
|
||||
// super.onCreate()
|
||||
// instance = this
|
||||
// // 第一步:初始化日志
|
||||
// LogManager.init(this)
|
||||
//
|
||||
// // 初始化 xCrash 以捕获 Native (SO) 崩溃
|
||||
// xcrash.XCrash.init(this, xcrash.XCrash.InitParameters().apply {
|
||||
// setAppVersion(packageManager.getPackageInfo(packageName, 0).versionName)
|
||||
// setLogDir(getExternalFilesDir("tombstones")?.absolutePath)
|
||||
// setNativeDumpAllThreads(true)
|
||||
//
|
||||
// setJavaCallback { logPath, emergency ->
|
||||
// LogManager.onCrashDetected(logPath, "Java-xCrash", null)
|
||||
// }
|
||||
//
|
||||
// setNativeCallback { logPath, emergency ->
|
||||
// LogManager.onCrashDetected(logPath, "Native-xCrash", null)
|
||||
// android.util.Log.e("MyApplication", "NATIVE CRASH DETECTED at: $logPath")
|
||||
// }
|
||||
// })
|
||||
//
|
||||
// Timber.tag("MyApplication").i("=== Application Starting ===")
|
||||
// }
|
||||
|
||||
// 单例实例
|
||||
companion object {
|
||||
private var instance: MyApplication? = null
|
||||
fun getAppInstance(): MyApplication = instance!!
|
||||
private lateinit var mApp: MyApplication
|
||||
|
||||
@JvmStatic
|
||||
fun getAppInstance(): MyApplication {
|
||||
if (pNative == null) {
|
||||
initPTT()
|
||||
}
|
||||
return mApp
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun initPTT() {
|
||||
if (pNative != null) return
|
||||
try {
|
||||
pNative = pttNative()
|
||||
|
||||
pNative?.pttNativeSetPackageName(pageName)
|
||||
pNative?.pttNativeSetAtCallback()
|
||||
pNative?.pttNativeSetPlayCallback()
|
||||
pNative?.pttNativeSetPalyStartCallback()
|
||||
pNative?.pttNativeSetPlayStopCallback()
|
||||
pNative?.pttNativeSetRecordStartCallback()
|
||||
pNative?.pttNativeSetRecordStopCallback()
|
||||
pNative?.pttNativeSetTTSCallback()
|
||||
|
||||
pNative?.pttNativePocTaskStart()
|
||||
Log.i("PTT_INIT", "PTT init success")
|
||||
} catch (e: Throwable) {
|
||||
Log.e("PTT_INIT", "Failed to init PTT: ${e.message}")
|
||||
}
|
||||
}
|
||||
|
||||
var pageName: String = ""
|
||||
var pNative: pttNative? = null
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 pttNative 实例(非空)
|
||||
*/
|
||||
fun getpNative(): pttNative? {
|
||||
return pNative
|
||||
}
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
mApp = this
|
||||
pageName = packageName
|
||||
initPTT()
|
||||
// 第一步:初始化日志
|
||||
LogManager.init(this)
|
||||
|
||||
// 【核心】初始化 xCrash 以捕获 Native (SO) 崩溃
|
||||
// 初始化 xCrash 以捕获 Native (SO) 崩溃
|
||||
xcrash.XCrash.init(this, xcrash.XCrash.InitParameters().apply {
|
||||
setAppVersion(packageManager.getPackageInfo(packageName, 0).versionName)
|
||||
setLogDir(getExternalFilesDir("tombstones")?.absolutePath)
|
||||
setNativeDumpAllThreads(true)
|
||||
|
||||
// Java 崩溃回调
|
||||
setJavaCallback { logPath, emergency ->
|
||||
LogManager.onCrashDetected(logPath, "Java-xCrash", null)
|
||||
}
|
||||
|
||||
// Native 崩溃回调
|
||||
setNativeCallback { logPath, emergency ->
|
||||
LogManager.onCrashDetected(logPath, "Native-xCrash", null)
|
||||
android.util.Log.e("MyApplication", "NATIVE CRASH DETECTED at: $logPath")
|
||||
}
|
||||
})
|
||||
|
||||
super.onCreate()
|
||||
instance = this
|
||||
|
||||
Timber.tag("MyApplication").i("=== Application Starting ===")
|
||||
|
||||
// try {
|
||||
// // 第二步:异步或保护性初始化 PTT
|
||||
// PTTMyApplication.init(this)
|
||||
// Timber.tag("MyApplication").i("PTT Module init sequence finished")
|
||||
// } catch (e: Throwable) {
|
||||
// Timber.tag("MyApplication").e(e, "PTT Module CRASH during init")
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
|
@ -161,6 +161,16 @@ object LogManager {
|
|||
}
|
||||
}
|
||||
|
||||
fun shutdown() {
|
||||
Timber.tag("LogManager").i("Shutting down...")
|
||||
try {
|
||||
executor.shutdown()
|
||||
executor.awaitTermination(3, java.util.concurrent.TimeUnit.SECONDS)
|
||||
} catch (e: Exception) {
|
||||
Timber.tag("LogManager").e(e, "Executor shutdown failed")
|
||||
}
|
||||
}
|
||||
|
||||
fun uploadLogs(context: Context, callback: (Boolean, String) -> Unit) {
|
||||
executor.execute {
|
||||
val zipPath = zipLogs(context) ?: return@execute callback(false, "打包失败")
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -53,5 +53,23 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="切换群组" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/btnCancel1"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="取消登录" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/btnCancel2"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="注销" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/login1"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="login1" />
|
||||
</LinearLayout>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
|
|
|||
Loading…
Reference in New Issue