当前群组:
-
@@ -625,8 +643,75 @@
}
} catch(e) {}
}
+ // 同步临时呼叫状态
+ syncTempCallStatus();
}, 500);
+ // === 临时呼叫状态管理 ===
+ function syncTempCallStatus() {
+ if (window.android && window.android.getTempCallStatus) {
+ try {
+ var status = JSON.parse(window.android.getTempCallStatus());
+ updateTempCallUI(status.isOpen, status.isMinimized);
+ } catch(e) {}
+ }
+ }
+
+ function updateTempCallUI(isOpen, isMinimized) {
+ var statusDiv = document.getElementById('temp-call-status');
+ var maxBtn = document.getElementById('btn-maximize-temp-call');
+ var groupSpan = document.getElementById('temp-call-group-name');
+
+ // 只有在最小化状态时才显示最大化按钮
+ if (isMinimized) {
+ statusDiv.style.display = 'block';
+ maxBtn.style.display = 'inline-block';
+ maxBtn.disabled = false;
+ maxBtn.style.background = '#f59e0b';
+ maxBtn.style.cursor = 'pointer';
+ } else if (isOpen) {
+ // Activity 打开但未最小化,不显示状态区域
+ statusDiv.style.display = 'none';
+ } else {
+ // Activity 已销毁且未最小化
+ statusDiv.style.display = 'none';
+ }
+ }
+
+ function maximizeTempCall() {
+ if (window.android && window.android.maximizeTempCall) {
+ window.android.maximizeTempCall();
+ }
+ }
+
+ // 临时呼叫状态变化回调 (由 Android 原生调用)
+ window.onTempCallStateChanged = function(state) {
+ console.log("临时呼叫状态变化: " + state);
+ var statusDiv = document.getElementById('temp-call-status');
+ var maxBtn = document.getElementById('btn-maximize-temp-call');
+
+ switch(state) {
+ case 'minimized':
+ // 最小化:显示状态区域和最大化按钮
+ statusDiv.style.display = 'block';
+ maxBtn.style.display = 'inline-block';
+ maxBtn.disabled = false;
+ maxBtn.style.background = '#f59e0b';
+ showPttResult("[回调] 临时呼叫已最小化,可通过最大化按钮恢复");
+ break;
+ case 'resumed':
+ // 恢复:隐藏状态区域
+ statusDiv.style.display = 'none';
+ showPttResult("[回调] 临时呼叫页面已恢复");
+ break;
+ case 'destroyed':
+ // 销毁:隐藏所有
+ statusDiv.style.display = 'none';
+ showPttResult("[回调] 临时呼叫已结束");
+ break;
+ }
+ };
+
// 告知 Android 页面加载完成(已移至 checkApp 中,等 bridge 注入后再调用)
window.onload = function() {};
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 bd79674..bbe3cbe 100644
--- a/app/src/main/java/com/example/kingway/ptt/CallBackResolution.java
+++ b/app/src/main/java/com/example/kingway/ptt/CallBackResolution.java
@@ -238,8 +238,61 @@ public class CallBackResolution {
for (int i = 0; i < stringsTalk.size(); i++) {
tempTxt += unicode(stringsTalk.get(i));
}
- Log.i(TAG, " 临时讲话 信息通知的指令 " + tempTxt);
+ int code=-1;
+ if(tempTxt.equals("退出临时呼叫")){
+ code=0;
+ } else if (tempTxt.startsWith("临时呼叫临时群组")) {
+ code=1;
+ } else if (tempTxt.equals("呼出失败")||tempTxt.equals("呼叫失败")) {
+ code=2;
+ } else if (tempTxt.equals("呼叫成功")||tempTxt.equals("呼出成功")) {
+ code=3;
+ }else{
+ code=-1;
+ }
+
+ Log.i(TAG, " 临时讲话 信息通知的指令 " + tempTxt + " code=" + code);
CallBackUtil.callBackTempCallNotify(tempTxt);
+
+ // 处理临时呼叫页面逻辑
+ if (code == 1) {
+ // 临时呼叫临时群组 → 打开临时呼叫页面
+ try {
+ android.content.Intent intent = new android.content.Intent(
+ com.stand.standapp.MyApplication.getAppInstance(),
+ com.stand.standapp.TempCallActivity.class
+ );
+ // 从84消息中提取临时群名称,格式为"临时呼叫XXX"
+ String tempGroupName = "临时会话";
+ if (tempTxt.startsWith("临时呼叫") && tempTxt.length() > "临时呼叫".length()) {
+ tempGroupName = tempTxt.substring("临时呼叫".length());
+ }
+ intent.putExtra("group_name", tempGroupName);
+ intent.addFlags(
+ android.content.Intent.FLAG_ACTIVITY_NEW_TASK |
+ android.content.Intent.FLAG_ACTIVITY_SINGLE_TOP
+ );
+ com.stand.standapp.MyApplication.getAppInstance().startActivity(intent);
+ } catch (Exception e) {
+ Log.e(TAG, "Failed to open TempCallActivity: " + e.getMessage());
+ }
+ } else if (code == 0) {
+ // 退出临时呼叫 → 关闭临时呼叫页面
+ if (com.stand.standapp.TempCallActivity.isOpen()) {
+ com.stand.standapp.TempCallActivity.closeWithMessage("临时呼叫已结束");
+ } else if (com.stand.standapp.TempCallActivity.isMinimizedState()) {
+ // 最小化状态下收到结束消息,清除状态并通知前端
+ com.stand.standapp.TempCallActivity.clearMinimizedState();
+ }
+ } else if (code == 2) {
+ // 呼叫失败 → 关闭临时呼叫页面
+ if (com.stand.standapp.TempCallActivity.isOpen()) {
+ com.stand.standapp.TempCallActivity.closeWithMessage("呼叫失败");
+ } else if (com.stand.standapp.TempCallActivity.isMinimizedState()) {
+ // 最小化状态下收到失败消息,清除状态并通知前端
+ com.stand.standapp.TempCallActivity.clearMinimizedState();
+ }
+ }
}
break;
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 e18f32d..6b45ebd 100644
--- a/app/src/main/java/com/example/kingway/ptt/SendAtUtil.java
+++ b/app/src/main/java/com/example/kingway/ptt/SendAtUtil.java
@@ -105,6 +105,11 @@ public class SendAtUtil {
send("0E000000000000\r\n");
}
+ /** 结束多成员临时呼叫 */
+ public static void stopTempCall(){
+ send("5500000100000000\r\n");
+ }
+
/**
* 字符串转换成十六进制字符串
diff --git a/app/src/main/java/com/stand/standapp/AndroidInterface.kt b/app/src/main/java/com/stand/standapp/AndroidInterface.kt
index c15eb3e..3184845 100644
--- a/app/src/main/java/com/stand/standapp/AndroidInterface.kt
+++ b/app/src/main/java/com/stand/standapp/AndroidInterface.kt
@@ -83,6 +83,8 @@ class AndroidInterface(private val activity: MainActivity) {
"onPageFinished" -> { onPageFinished(); "" }
"showRestartDialog" -> { showRestartDialog(args.optString(0, ""), args.optString(1, "提示")); "" }
"showJsonDialog" -> { showJsonDialog(args.optString(0, "")); "" }
+ "getTempCallStatus" -> getTempCallStatus()
+ "maximizeTempCall" -> { maximizeTempCall(); "" }
else -> {
Timber.tag("Bridge").w("Unknown method: $method")
""
@@ -464,4 +466,25 @@ class AndroidInterface(private val activity: MainActivity) {
}
}
}
+
+ fun getTempCallStatus(): String {
+ return try {
+ val json = JSONObject()
+ json.put("isOpen", TempCallActivity.isOpen())
+ json.put("isMinimized", TempCallActivity.isMinimizedState())
+ json.toString()
+ } catch (e: Exception) {
+ "{\"isOpen\":false,\"isMinimized\":false}"
+ }
+ }
+
+ fun maximizeTempCall() {
+ Handler(Looper.getMainLooper()).post {
+ try {
+ TempCallActivity.maximize()
+ } catch (e: Exception) {
+ Timber.tag("TempCall").e(e, "maximizeTempCall error")
+ }
+ }
+ }
}
diff --git a/app/src/main/java/com/stand/standapp/TempCallActivity.kt b/app/src/main/java/com/stand/standapp/TempCallActivity.kt
new file mode 100644
index 0000000..46b3eac
--- /dev/null
+++ b/app/src/main/java/com/stand/standapp/TempCallActivity.kt
@@ -0,0 +1,284 @@
+package com.stand.standapp
+
+import android.animation.ObjectAnimator
+import android.os.Bundle
+import android.os.Handler
+import android.os.Looper
+import android.view.MotionEvent
+import android.view.View
+import android.view.WindowManager
+import android.view.animation.AlphaAnimation
+import android.view.animation.Animation
+import android.view.animation.LinearInterpolator
+import android.widget.Button
+import android.widget.ImageView
+import android.widget.TextView
+import android.widget.Toast
+import androidx.appcompat.app.AlertDialog
+import androidx.appcompat.app.AppCompatActivity
+import com.example.kingway.ptt.SendAtUtil
+import timber.log.Timber
+
+class TempCallActivity : AppCompatActivity() {
+
+ private var isSpeaking = false
+ private var lastSpeakTime = 0L
+ private val MIN_SPEAK_DURATION = 200L
+ private val handler = Handler(Looper.getMainLooper())
+ private var pulseAnimator: ObjectAnimator? = null
+
+ companion object {
+ @Volatile
+ var instance: TempCallActivity? = null
+ private set
+
+ @Volatile
+ var isMinimized = false
+ private set
+
+ // 存储当前临时群组名称,用于恢复时传递
+ @Volatile
+ var currentGroupName: String = "临时会话"
+
+ @JvmStatic
+ fun isOpen(): Boolean = instance != null
+
+ @JvmStatic
+ fun isMinimizedState(): Boolean = isMinimized
+
+ @JvmStatic
+ fun maximize() {
+ if (isMinimized) {
+ isMinimized = false
+ val intent = android.content.Intent(
+ com.stand.standapp.MyApplication.getAppInstance(),
+ TempCallActivity::class.java
+ )
+ intent.putExtra("group_name", currentGroupName)
+ intent.addFlags(android.content.Intent.FLAG_ACTIVITY_NEW_TASK)
+ com.stand.standapp.MyApplication.getAppInstance().startActivity(intent)
+ }
+ }
+
+ @JvmStatic
+ fun closeWithMessage(message: String) {
+ instance?.runOnUiThread {
+ Toast.makeText(instance, message, Toast.LENGTH_SHORT).show()
+ instance?.finish()
+ } ?: run {
+ // Activity 已销毁但状态还在,清除状态
+ clearMinimizedState()
+ }
+ }
+
+ @JvmStatic
+ fun clearMinimizedState() {
+ isMinimized = false
+ currentGroupName = "临时会话"
+ MainActivity.executeJs("onTempCallStateChanged('destroyed')")
+ }
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ // 全屏覆盖 + 常亮 + 锁屏显示
+ window.addFlags(
+ WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON or
+ WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED or
+ WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
+ )
+
+ setContentView(R.layout.activity_temp_call)
+ instance = this
+ isMinimized = false
+
+ val groupName = intent.getStringExtra("group_name") ?: "临时会话"
+ currentGroupName = groupName
+ findViewById
(R.id.tv_group_name).text = groupName
+
+ setupMinimizeButton()
+ setupPttButton()
+ setupHangupButton()
+ startPulseAnimation()
+ }
+
+ override fun onResume() {
+ super.onResume()
+ isMinimized = false
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ pulseAnimator?.cancel()
+ if (instance == this) {
+ instance = null
+ // 如果不是最小化状态,说明是真正结束,清除所有状态
+ if (!isMinimized) {
+ currentGroupName = "临时会话"
+ }
+ // 通知 web 页面状态变化
+ MainActivity.executeJs("onTempCallStateChanged('" + if (isMinimized) "minimized" else "destroyed" + "')")
+ }
+ }
+
+ // 拦截返回键
+ override fun onBackPressed() {
+ showMinimizeDialog()
+ }
+
+ // 不要在 recent tasks 中显示
+ override fun finish() {
+ super.finish()
+ overridePendingTransition(0, android.R.anim.fade_out)
+ }
+
+ fun updateGroupName(name: String) {
+ findViewById(R.id.tv_group_name)?.text = name
+ }
+
+ private fun startPulseAnimation() {
+ val pulse = findViewById(R.id.iv_pulse) ?: return
+ pulseAnimator = ObjectAnimator.ofFloat(pulse, "alpha", 1f, 0.3f).apply {
+ duration = 1000
+ repeatCount = ObjectAnimator.INFINITE
+ repeatMode = ObjectAnimator.REVERSE
+ start()
+ }
+ }
+
+ private fun setupPttButton() {
+ val btnPtt = findViewById