feat: 添加 Temi 机器人应用基础框架和设置功能

- 启用 ViewBinding 并添加 Temi SDK 依赖
- 新增主界面和设置界面布局及活动
- 实现网络 IP 配置的保存与读取功能
- 添加必要的 Android 权限和清单配置
- 创建项目 README 文档说明运行和预览指南
This commit is contained in:
bin
2026-03-10 14:44:08 +08:00
parent 9750a8c4eb
commit cd6f1699ab
7 changed files with 254 additions and 2 deletions

View File

@@ -33,10 +33,13 @@ android {
kotlinOptions {
jvmTarget = "11"
}
buildFeatures {
viewBinding = true
}
}
dependencies {
implementation("com.robotemi:sdk:1.137.1")
implementation(libs.androidx.core.ktx)
implementation(libs.androidx.appcompat)
implementation(libs.material)

View File

@@ -2,6 +2,11 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
@@ -11,6 +16,24 @@
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.Lzwcaiterminaltemi"
tools:targetApi="31" />
tools:targetApi="31">
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".SettingsActivity"
android:exported="false"
android:label="Settings"/>
<meta-data
android:name="com.robotemi.sdk.metadata.SKILL"
android:value="@string/app_name" />
</application>
</manifest>

View File

@@ -1,2 +1,70 @@
package com.example.lzwcai_terminal_temi
import android.annotation.SuppressLint
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.text.method.ScrollingMovementMethod
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)
// 隐藏软键盘
window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN)
// 获取 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
val prefs = getSharedPreferences("app_prefs", Context.MODE_PRIVATE)
val ip = prefs.getString("network_ip", "未设置")
printLog("应用启动完成。目标 IP: $ip")
}
private fun printLog(msg: String) {
runOnUiThread {
binding.tvLog.append("$msg\n")
}
}
override fun onDestroy() {
super.onDestroy()
// 建议在销毁时移除监听器,避免内存泄漏 (虽然 Temi SDK 通常会处理,但显式移除是好习惯)
// robot.removeOn...
}
}

View File

@@ -0,0 +1,34 @@
package com.example.lzwcai_terminal_temi
import android.content.Context
import android.os.Bundle
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.example.lzwcai_terminal_temi.databinding.ActivitySettingsBinding
class SettingsActivity : AppCompatActivity() {
private lateinit var binding: ActivitySettingsBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivitySettingsBinding.inflate(layoutInflater)
setContentView(binding.root)
val prefs = getSharedPreferences("app_prefs", Context.MODE_PRIVATE)
val savedIp = prefs.getString("network_ip", "")
binding.etIpAddress.setText(savedIp)
binding.btnSave.setOnClickListener {
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()
finish()
} else {
Toast.makeText(this, "Please enter a valid IP", Toast.LENGTH_SHORT).show()
}
}
}
}

View File

@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="@+id/tvLog"
android:layout_width="0dp"
android:layout_height="0dp"
android:padding="16dp"
android:scrollbars="vertical"
android:text="Logs will appear here..."
app:layout_constraintBottom_toTopOf="@+id/btnSettings"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/btnSettings"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:text="Settings"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="16dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Network IP Configuration"
android:textSize="18sp"
android:textStyle="bold"
android:layout_marginBottom="16dp"/>
<EditText
android:id="@+id/etIpAddress"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Enter IP Address (e.g., 192.168.1.100)"
android:inputType="textUri"/>
<Button
android:id="@+id/btnSave"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Save"
android:layout_marginTop="16dp"/>
</LinearLayout>