feat: add phone CommandActivity (send session.prompt + stream events)

This commit is contained in:
2026-09-01 19:04:19 +08:00
parent fd62ea9d95
commit 4e88f0e5c4
6 changed files with 188 additions and 0 deletions
+3
View File
@@ -22,5 +22,8 @@
<activity
android:name=".EventLogActivity"
android:exported="false" />
<activity
android:name=".CommandActivity"
android:exported="false" />
</application>
</manifest>
@@ -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<String> 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<String> 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();
}
}
@@ -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
@@ -0,0 +1,54 @@
<?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"
android:background="@color/deep_blue">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="命令 / 聊天"
android:textColor="@color/white"
android:textSize="20sp"
android:textStyle="bold" />
<EditText
android:id="@+id/command_input"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:hint="输入要发给 DeepSeek 的指令..."
android:textColor="@color/white"
android:textColorHint="@color/light_blue" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginTop="8dp">
<Button
android:id="@+id/command_send"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="发送" />
<Button
android:id="@+id/command_cancel"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_marginStart="8dp"
android:text="取消" />
</LinearLayout>
<ListView
android:id="@+id/command_log"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:layout_marginTop="12dp"
android:divider="@color/light_blue"
android:dividerHeight="1dp" />
</LinearLayout>
@@ -52,6 +52,13 @@
android:layout_marginTop="12dp"
android:text="@string/btn_events" />
<Button
android:id="@+id/btn_command"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:text="@string/btn_command" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
+1
View File
@@ -6,6 +6,7 @@
<string name="btn_settings">设置</string>
<string name="btn_sessions">会话列表</string>
<string name="btn_events">事件流</string>
<string name="btn_command">命令</string>
<string name="settings_title">设置</string>
<string name="label_server">服务器地址</string>
<string name="hint_server">ws://host:port</string>