diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 85c88a3..acfa2a3 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -5,12 +5,12 @@ plugins { android { namespace = "com.example.lzwcai_terminal_temi" - compileSdk = 35 + compileSdk = 36 defaultConfig { applicationId = "com.example.lzwcai_terminal_temi" minSdk = 23 - targetSdk = 35 + targetSdk = 36 versionCode = 1 versionName = "1.0" @@ -27,11 +27,11 @@ android { } } compileOptions { - sourceCompatibility = JavaVersion.VERSION_11 - targetCompatibility = JavaVersion.VERSION_11 + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 } kotlinOptions { - jvmTarget = "11" + jvmTarget = "17" } buildFeatures { viewBinding = true diff --git a/app/src/main/java/com/example/lzwcai_terminal_temi/LogManager.kt b/app/src/main/java/com/example/lzwcai_terminal_temi/LogManager.kt new file mode 100644 index 0000000..68f7225 --- /dev/null +++ b/app/src/main/java/com/example/lzwcai_terminal_temi/LogManager.kt @@ -0,0 +1,67 @@ +package com.example.lzwcai_terminal_temi + +import android.util.Log +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import java.io.BufferedReader +import java.io.InputStreamReader + +object LogManager { + private val _logs = MutableLiveData("") + val logs: LiveData = _logs + private val logBuffer = StringBuffer() + private var isReading = false + private val currentPid = android.os.Process.myPid().toString() + + fun startLogcatListener() { + if (isReading) return + isReading = true + + Thread { + try { + // 清除之前的日志缓存 + Runtime.getRuntime().exec("logcat -c") + + // 开始读取日志,过滤当前进程ID + val process = Runtime.getRuntime().exec("logcat -v threadtime") + val reader = BufferedReader(InputStreamReader(process.inputStream)) + + var line: String? + while (reader.readLine().also { line = it } != null) { + line?.let { + if (it.contains(currentPid)) { + // 简单的过滤,只显示包含当前PID的行 + // 可以根据需要进一步处理日志格式 + updateLog(it) + } + } + } + } catch (e: Exception) { + Log.e("LogManager", "Error reading logcat", e) + updateLog("Error reading logs: ${e.message}") + } + }.start() + } + + private fun updateLog(msg: String) { + // 限制日志缓冲区大小,避免内存溢出 + if (logBuffer.length > 50000) { + logBuffer.delete(0, 10000) + } + logBuffer.append("$msg\n") + _logs.postValue(logBuffer.toString()) + } + + fun clearLogs() { + logBuffer.setLength(0) + _logs.postValue("") + // 也可以尝试清除系统日志缓存,但通常需要权限或只能清除应用自己的 + Thread { + try { + Runtime.getRuntime().exec("logcat -c") + } catch (e: Exception) { + e.printStackTrace() + } + }.start() + } +} diff --git a/app/src/main/java/com/example/lzwcai_terminal_temi/MainActivity.kt b/app/src/main/java/com/example/lzwcai_terminal_temi/MainActivity.kt index cda95d1..fcc97d9 100644 --- a/app/src/main/java/com/example/lzwcai_terminal_temi/MainActivity.kt +++ b/app/src/main/java/com/example/lzwcai_terminal_temi/MainActivity.kt @@ -4,25 +4,25 @@ import android.annotation.SuppressLint import android.content.Context import android.content.Intent import android.os.Bundle -import android.text.method.ScrollingMovementMethod +import android.util.Log import android.view.WindowManager import androidx.appcompat.app.AppCompatActivity import com.example.lzwcai_terminal_temi.databinding.ActivityMainBinding import com.robotemi.sdk.Robot -import java.util.concurrent.Executors class MainActivity : AppCompatActivity() { private lateinit var robot: Robot private lateinit var binding: ActivityMainBinding - - private val executorService = Executors.newSingleThreadExecutor() @SuppressLint("SetTextI18n") override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityMainBinding.inflate(layoutInflater) setContentView(binding.root) + + // 启动日志监听 + LogManager.startLogcatListener() // 隐藏软键盘 window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN) @@ -30,41 +30,14 @@ class MainActivity : AppCompatActivity() { // 获取 Robot 实例 robot = Robot.getInstance() - // 初始化日志视图 - binding.tvLog.movementMethod = ScrollingMovementMethod.getInstance() - // 设置按钮点击事件 binding.btnSettings.setOnClickListener { startActivity(Intent(this, SettingsActivity::class.java)) } - // --- 轻量化处理:移除不必要的监听器 --- - // 移除了 FaceRecognized, Telepresence, GreetMode 等监听器 - // 仅保留基础的权限和运动状态监听作为示例 - - robot.addOnRequestPermissionResultListener { permission, grantResult, _ -> - printLog("Permission: $permission, Result: $grantResult") - } - - robot.addOnMovementStatusChangedListener { type, status -> - printLog("Movement: $type, Status: $status") - } - - // 读取并显示配置的 IP + // 读取配置的 IP 并记录日志 val prefs = getSharedPreferences("app_prefs", Context.MODE_PRIVATE) val ip = prefs.getString("network_ip", "未设置") - printLog("应用启动完成。目标 IP: $ip") + Log.i("MainActivity", "应用启动完成。目标 IP: $ip") } - - private fun printLog(msg: String) { - runOnUiThread { - binding.tvLog.append("$msg\n") - } - } - - override fun onDestroy() { - super.onDestroy() - // 建议在销毁时移除监听器,避免内存泄漏 (虽然 Temi SDK 通常会处理,但显式移除是好习惯) - // robot.removeOn... - } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/example/lzwcai_terminal_temi/SettingsActivity.kt b/app/src/main/java/com/example/lzwcai_terminal_temi/SettingsActivity.kt index 88f64f3..91a68fb 100644 --- a/app/src/main/java/com/example/lzwcai_terminal_temi/SettingsActivity.kt +++ b/app/src/main/java/com/example/lzwcai_terminal_temi/SettingsActivity.kt @@ -2,6 +2,10 @@ package com.example.lzwcai_terminal_temi import android.content.Context import android.os.Bundle +import android.util.Log +import android.view.View +import android.view.WindowManager +import android.view.inputmethod.InputMethodManager import android.widget.Toast import androidx.appcompat.app.AppCompatActivity import com.example.lzwcai_terminal_temi.databinding.ActivitySettingsBinding @@ -14,21 +18,68 @@ class SettingsActivity : AppCompatActivity() { super.onCreate(savedInstanceState) binding = ActivitySettingsBinding.inflate(layoutInflater) setContentView(binding.root) + + // 默认隐藏软键盘 + window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN) val prefs = getSharedPreferences("app_prefs", Context.MODE_PRIVATE) val savedIp = prefs.getString("network_ip", "") binding.etIpAddress.setText(savedIp) + + // 点击外部隐藏键盘 + binding.root.setOnClickListener { + hideKeyboard() + } binding.btnSave.setOnClickListener { + hideKeyboard() val ip = binding.etIpAddress.text.toString().trim() - // Here you could add regex validation for IP address if needed if (ip.isNotEmpty()) { prefs.edit().putString("network_ip", ip).apply() - Toast.makeText(this, "IP Saved: $ip", Toast.LENGTH_SHORT).show() + Toast.makeText(this, getString(R.string.msg_ip_saved, ip), Toast.LENGTH_SHORT).show() + Log.i("SettingsActivity", "IP Saved: $ip") finish() } else { - Toast.makeText(this, "Please enter a valid IP", Toast.LENGTH_SHORT).show() + Toast.makeText(this, getString(R.string.msg_invalid_ip), Toast.LENGTH_SHORT).show() + Log.w("SettingsActivity", "Invalid IP attempt") + } + } + + binding.btnBack.setOnClickListener { + hideKeyboard() + finish() + } + + binding.btnToggleLogs.setOnClickListener { + hideKeyboard() + if (binding.tvLog.visibility == View.VISIBLE) { + binding.tvLog.visibility = View.GONE + binding.btnToggleLogs.text = getString(R.string.btn_show_logs) + } else { + binding.tvLog.visibility = View.VISIBLE + binding.btnToggleLogs.text = getString(R.string.btn_hide_logs) + } + } + + LogManager.logs.observe(this) { logs -> + binding.tvLog.text = logs + // 自动滚动到底部 + binding.tvLog.post { + if (binding.tvLog.layout != null) { + val scrollAmount = binding.tvLog.layout.getLineTop(binding.tvLog.lineCount) - binding.tvLog.height + if (scrollAmount > 0) + binding.tvLog.scrollTo(0, scrollAmount) + else + binding.tvLog.scrollTo(0, 0) + } } } } -} \ No newline at end of file + + private fun hideKeyboard() { + val imm = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager + currentFocus?.let { + imm.hideSoftInputFromWindow(it.windowToken, 0) + } + } +} diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index c610d3e..eebb14f 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -7,25 +7,28 @@ tools:context=".MainActivity"> + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintVertical_chainStyle="packed" />