diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index aaa2688..a7bfdc0 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -22,5 +22,8 @@
+
diff --git a/app/src/main/java/com/dshwatch/app/CommandActivity.java b/app/src/main/java/com/dshwatch/app/CommandActivity.java
new file mode 100644
index 0000000..3cbdfa2
--- /dev/null
+++ b/app/src/main/java/com/dshwatch/app/CommandActivity.java
@@ -0,0 +1,115 @@
+package com.dshwatch.app;
+
+import android.os.Bundle;
+import android.view.View;
+import android.widget.ArrayAdapter;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.ListView;
+
+import androidx.appcompat.app.AppCompatActivity;
+
+import org.json.JSONObject;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 命令/聊天页:发送 session.prompt 并流式展示 status/event 回显。
+ * 这是远程控制 Harness 的核心入口。
+ */
+public class CommandActivity extends AppCompatActivity {
+
+ private EditText input;
+ private ArrayAdapter adapter;
+ private ServerClient client;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_command);
+
+ input = findViewById(R.id.command_input);
+ ListView list = findViewById(R.id.command_log);
+ List data = new ArrayList<>();
+ adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, data);
+ list.setAdapter(adapter);
+
+ client = new ServerClient(new ServerClient.Listener() {
+ @Override
+ public void onConnectionChanged(boolean connected) {
+ runOnUiThread(() -> adapter.add(connected ? "[已连接]" : "[连接断开]"));
+ }
+
+ @Override
+ public void onHello(JSONObject hello) {
+ // connected
+ }
+
+ @Override
+ public void onStatus(JSONObject status) {
+ runOnUiThread(() -> adapter.add("[status] " + status.optString("model") + " running=" + status.optBoolean("running")));
+ }
+
+ @Override
+ public void onEvent(JSONObject event) {
+ runOnUiThread(() -> {
+ adapter.add("[event] " + event.toString());
+ adapter.notifyDataSetChanged();
+ });
+ }
+
+ @Override
+ public void onResponse(String requestId, boolean ok, JSONObject result, JSONObject error) {
+ runOnUiThread(() -> {
+ adapter.add(ok ? ("[响应] " + (result != null ? result.toString() : "ok")) : ("[错误] " + (error != null ? error.optString("message") : "unknown")));
+ adapter.notifyDataSetChanged();
+ });
+ }
+
+ @Override
+ public void onError(String message) {
+ runOnUiThread(() -> {
+ adapter.add("[错误] " + message);
+ adapter.notifyDataSetChanged();
+ });
+ }
+ });
+
+ client.connect(
+ SettingsStore.serverUrl(CommandActivity.this),
+ SettingsStore.userId(CommandActivity.this),
+ SettingsStore.token(CommandActivity.this));
+
+ Button send = findViewById(R.id.command_send);
+ send.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ String text = input.getText().toString().trim();
+ if (text.isEmpty()) return;
+ JSONObject params = new JSONObject();
+ try {
+ params.put("content", text);
+ } catch (Exception e) { }
+ client.sendRequest("session.prompt", params);
+ input.setText("");
+ }
+ });
+
+ Button cancel = findViewById(R.id.command_cancel);
+ cancel.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ JSONObject params = new JSONObject();
+ try { params.put("sessionId", JSONObject.NULL); } catch (Exception e) { }
+ client.sendRequest("session.cancel", params);
+ }
+ });
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ if (client != null) client.close();
+ }
+}
diff --git a/app/src/main/java/com/dshwatch/app/MainActivity.java b/app/src/main/java/com/dshwatch/app/MainActivity.java
index 9b2cab9..305a399 100644
--- a/app/src/main/java/com/dshwatch/app/MainActivity.java
+++ b/app/src/main/java/com/dshwatch/app/MainActivity.java
@@ -117,6 +117,14 @@ public class MainActivity extends AppCompatActivity {
}
});
+ Button command = findViewById(R.id.btn_command);
+ command.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ startActivity(new Intent(MainActivity.this, CommandActivity.class));
+ }
+ });
+
Button refresh = findViewById(R.id.btn_refresh);
refresh.setOnClickListener(new View.OnClickListener() {
@Override
diff --git a/app/src/main/res/layout/activity_command.xml b/app/src/main/res/layout/activity_command.xml
new file mode 100644
index 0000000..1e6c299
--- /dev/null
+++ b/app/src/main/res/layout/activity_command.xml
@@ -0,0 +1,54 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index 3d03dfb..a31f998 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -52,6 +52,13 @@
android:layout_marginTop="12dp"
android:text="@string/btn_events" />
+
+
设置
会话列表
事件流
+ 命令
设置
服务器地址
ws://host:port