diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 655e1ac..1871e9a 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -17,7 +17,7 @@ android { testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" ndk { - abiFilters.addAll(listOf("armeabi-v7a","x86")) + abiFilters.addAll(listOf("armeabi-v7a")) } } diff --git a/app/src/main/assets/extensions/bridge/bridge.js b/app/src/main/assets/extensions/bridge/bridge.js index 29d3654..bb9c36b 100644 --- a/app/src/main/assets/extensions/bridge/bridge.js +++ b/app/src/main/assets/extensions/bridge/bridge.js @@ -21,7 +21,7 @@ ' setInterval(function() {', ' var code = prompt("bridge:_poll", "");', ' if (code) { try { eval(code); } catch(e) {} }', - ' }, 500);', + ' }, 1000);', '})();' ].join('\n'); diff --git a/app/src/main/java/com/example/kingway/ptt/AudioRecordManager.java b/app/src/main/java/com/example/kingway/ptt/AudioRecordManager.java index 81e812f..577650a 100644 --- a/app/src/main/java/com/example/kingway/ptt/AudioRecordManager.java +++ b/app/src/main/java/com/example/kingway/ptt/AudioRecordManager.java @@ -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,7 +176,8 @@ public class AudioRecordManager { } } catch (Exception e) { e.printStackTrace(); + } finally { } } -} +} \ No newline at end of file diff --git a/app/src/main/java/com/example/kingway/ptt/CallBackResolution.java b/app/src/main/java/com/example/kingway/ptt/CallBackResolution.java index bf76c59..0358f9a 100644 --- a/app/src/main/java/com/example/kingway/ptt/CallBackResolution.java +++ b/app/src/main/java/com/example/kingway/ptt/CallBackResolution.java @@ -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 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 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)); } diff --git a/app/src/main/java/com/example/kingway/ptt/CallBackUtil.java b/app/src/main/java/com/example/kingway/ptt/CallBackUtil.java index eec4c49..beb4c2f 100644 --- a/app/src/main/java/com/example/kingway/ptt/CallBackUtil.java +++ b/app/src/main/java/com/example/kingway/ptt/CallBackUtil.java @@ -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; diff --git a/app/src/main/java/com/example/kingway/ptt/GroupInfoDto.java b/app/src/main/java/com/example/kingway/ptt/GroupInfoDto.java index 9b4924e..fb48a14 100644 --- a/app/src/main/java/com/example/kingway/ptt/GroupInfoDto.java +++ b/app/src/main/java/com/example/kingway/ptt/GroupInfoDto.java @@ -2,7 +2,11 @@ package com.example.kingway.ptt; /** *
+ *     author : GaryLiang
+ *     e-mail : 595184932@qq.com
+ *     time   : 2017/11/21 上午9:09
  *     desc   :  组
+ *     version: 1.0
  * 
*/ diff --git a/app/src/main/java/com/example/kingway/ptt/GroupMemberInfoDto.java b/app/src/main/java/com/example/kingway/ptt/GroupMemberInfoDto.java index be661bd..9467e95 100644 --- a/app/src/main/java/com/example/kingway/ptt/GroupMemberInfoDto.java +++ b/app/src/main/java/com/example/kingway/ptt/GroupMemberInfoDto.java @@ -4,7 +4,11 @@ import java.io.Serializable; /** *
+ *     author : GaryLiang
+ *     e-mail : 595184932@qq.com
+ *     time   : 2017/11/21 上午9:09
  *     desc   :  组 成员
+ *     version: 1.0
  * 
*/ @@ -77,4 +81,4 @@ public class GroupMemberInfoDto implements Serializable { ", haveVideo=" + haveVideo + '}'; } -} +} \ No newline at end of file diff --git a/app/src/main/java/com/example/kingway/ptt/MyApplication.java b/app/src/main/java/com/example/kingway/ptt/MyApplication.java deleted file mode 100644 index 9e82f70..0000000 --- a/app/src/main/java/com/example/kingway/ptt/MyApplication.java +++ /dev/null @@ -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(); - } -} diff --git a/app/src/main/java/com/example/kingway/ptt/SendAtUtil.java b/app/src/main/java/com/example/kingway/ptt/SendAtUtil.java index a39dd1d..df6eaba 100644 --- a/app/src/main/java/com/example/kingway/ptt/SendAtUtil.java +++ b/app/src/main/java/com/example/kingway/ptt/SendAtUtil.java @@ -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"); + } + /** * 账号注销接口 */ diff --git a/app/src/main/java/com/example/kingway/ptt/pttActivity.java b/app/src/main/java/com/example/kingway/ptt/pttActivity.java index 47b29fb..e59c45d 100644 --- a/app/src/main/java/com/example/kingway/ptt/pttActivity.java +++ b/app/src/main/java/com/example/kingway/ptt/pttActivity.java @@ -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(); + } + }); } } diff --git a/app/src/main/java/com/example/kingway/ptt/pttNative.java b/app/src/main/java/com/example/kingway/ptt/pttNative.java index 7bebf49..9b8428b 100644 --- a/app/src/main/java/com/example/kingway/ptt/pttNative.java +++ b/app/src/main/java/com/example/kingway/ptt/pttNative.java @@ -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 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);// 设置音量 } diff --git a/app/src/main/java/com/stand/standapp/LoginActivity.kt b/app/src/main/java/com/stand/standapp/LoginActivity.kt index 4085a02..f0ef2b3 100644 --- a/app/src/main/java/com/stand/standapp/LoginActivity.kt +++ b/app/src/main/java/com/stand/standapp/LoginActivity.kt @@ -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") + } } } diff --git a/app/src/main/java/com/stand/standapp/MainActivity.kt b/app/src/main/java/com/stand/standapp/MainActivity.kt index 77d7215..8969fb7 100644 --- a/app/src/main/java/com/stand/standapp/MainActivity.kt +++ b/app/src/main/java/com/stand/standapp/MainActivity.kt @@ -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) { diff --git a/app/src/main/java/com/stand/standapp/MyApplication.kt b/app/src/main/java/com/stand/standapp/MyApplication.kt index 990fe41..2c4b595 100644 --- a/app/src/main/java/com/stand/standapp/MyApplication.kt +++ b/app/src/main/java/com/stand/standapp/MyApplication.kt @@ -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") -// } + Timber.tag("MyApplication").i("=== Application Starting ===") } -} +} \ No newline at end of file diff --git a/app/src/main/java/com/stand/standapp/utils/LogManager.kt b/app/src/main/java/com/stand/standapp/utils/LogManager.kt index 0ce4483..09e8dfd 100644 --- a/app/src/main/java/com/stand/standapp/utils/LogManager.kt +++ b/app/src/main/java/com/stand/standapp/utils/LogManager.kt @@ -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, "打包失败") diff --git a/app/src/main/jniLibs/x86/libszzkserialport.so b/app/src/main/jniLibs/x86/libszzkserialport.so deleted file mode 100644 index d523dd4..0000000 Binary files a/app/src/main/jniLibs/x86/libszzkserialport.so and /dev/null differ diff --git a/app/src/main/res/layout/activity_ptt.xml b/app/src/main/res/layout/activity_ptt.xml index 59e4ceb..f6c12ae 100644 --- a/app/src/main/res/layout/activity_ptt.xml +++ b/app/src/main/res/layout/activity_ptt.xml @@ -53,5 +53,23 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:text="切换群组" /> + +