feat: add Xiaomi Wearable SDK AAR + real WatchBridge and watch<->server relay
This commit is contained in:
@@ -23,6 +23,7 @@ android {
|
||||
}
|
||||
}
|
||||
dependencies {
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar', '*.aar'])
|
||||
implementation 'androidx.appcompat:appcompat:1.6.1'
|
||||
implementation 'com.google.android.material:material:1.9.0'
|
||||
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
|
||||
|
||||
Binary file not shown.
@@ -13,7 +13,8 @@ import org.json.JSONObject;
|
||||
public class MainActivity extends AppCompatActivity {
|
||||
|
||||
private TextView status;
|
||||
private ServerClient client;
|
||||
private ServerClient serverClient;
|
||||
private WatchBridge watchBridge;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
@@ -22,30 +23,33 @@ public class MainActivity extends AppCompatActivity {
|
||||
|
||||
status = findViewById(R.id.status_text);
|
||||
|
||||
client = new ServerClient(new ServerClient.Listener() {
|
||||
// 服务器客户端
|
||||
serverClient = new ServerClient(new ServerClient.Listener() {
|
||||
@Override
|
||||
public void onConnectionChanged(boolean connected) {
|
||||
runOnUiThread(() -> status.setText(connected ? "已连接(空壳)" : "连接断开"));
|
||||
runOnUiThread(() -> status.setText(connected ? "服务器已连接" : "服务器断开"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onHello(JSONObject hello) {
|
||||
// 连接建立后拉一次状态
|
||||
client.sendRequest("harness.status", new JSONObject());
|
||||
serverClient.sendRequest("harness.status", new JSONObject());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStatus(JSONObject s) {
|
||||
runOnUiThread(() -> {
|
||||
if (s != null) {
|
||||
status.setText("状态: " + s.optString("model") + " / " + s.optString("cwd"));
|
||||
}
|
||||
});
|
||||
if (s != null) {
|
||||
runOnUiThread(() -> status.setText("状态: " + s.optString("model") + " / " + s.optString("cwd")));
|
||||
}
|
||||
if (watchBridge != null) {
|
||||
watchBridge.sendToWatch(s.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEvent(JSONObject event) {
|
||||
// 空壳:后续写入事件流
|
||||
if (watchBridge != null) {
|
||||
watchBridge.sendToWatch(event.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -59,6 +63,36 @@ public class MainActivity extends AppCompatActivity {
|
||||
}
|
||||
});
|
||||
|
||||
// 手表互联桥
|
||||
watchBridge = new WatchBridge(this, new WatchBridge.Listener() {
|
||||
@Override
|
||||
public void onWatchConnected(boolean connected, String nodeId) {
|
||||
runOnUiThread(() -> status.setText(connected ? "手表已连接: " + nodeId : "未找到手表"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWatchMessage(String json) {
|
||||
try {
|
||||
JSONObject msg = new JSONObject(json);
|
||||
String type = msg.optString("type", "");
|
||||
if ("command".equals(type) && "prompt".equals(msg.optString("kind", ""))) {
|
||||
JSONObject payload = msg.optJSONObject("payload");
|
||||
String content = payload != null ? payload.optString("content", "") : "";
|
||||
JSONObject params = new JSONObject();
|
||||
params.put("content", content);
|
||||
serverClient.sendRequest("harness.prompt", params);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// ignore malformed
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(String message) {
|
||||
runOnUiThread(() -> status.setText("WatchBridge: " + message));
|
||||
}
|
||||
});
|
||||
|
||||
Button settings = findViewById(R.id.btn_settings);
|
||||
settings.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
@@ -73,7 +107,8 @@ public class MainActivity extends AppCompatActivity {
|
||||
public void onClick(View v) {
|
||||
status.setText("连接中...");
|
||||
// 空壳:默认连本机模拟器 server;真实地址/用户/Token 从设置读取
|
||||
client.connect("ws://10.0.2.2:8787/ws", "dshwatch", "change-me");
|
||||
serverClient.connect("ws://10.0.2.2:8787/ws", "dshwatch", "change-me");
|
||||
watchBridge.connect();
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -81,6 +116,6 @@ public class MainActivity extends AppCompatActivity {
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
if (client != null) client.close();
|
||||
if (serverClient != null) serverClient.close();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,73 @@
|
||||
package com.dshwatch.app;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
|
||||
import com.xiaomi.xms.wearable.Wearable;
|
||||
import com.xiaomi.xms.wearable.message.MessageApi;
|
||||
import com.xiaomi.xms.wearable.message.OnMessageReceivedListener;
|
||||
import com.xiaomi.xms.wearable.node.Node;
|
||||
import com.xiaomi.xms.wearable.node.NodeApi;
|
||||
|
||||
/**
|
||||
* 手表 BLE 互联桥(空壳)。
|
||||
* 后续接入小米穿戴 SDK:Wearable / MessageApi / sendMessage / addListener,
|
||||
* 用于把手表(DSHWatch) 与手机端双向转发。
|
||||
* 手表 BLE 互联桥(使用小米穿戴 xms-wearable SDK)。
|
||||
* 负责:发现手表节点、注册消息监听、把 JSON 发给手表、把收到的消息回传。
|
||||
* 与 ServerClient 联动即可实现 手机(Server) <-> 手表(Watch) 双向转发。
|
||||
*/
|
||||
public interface WatchBridge {
|
||||
/** 连接手表(小米穿戴服务) */
|
||||
void connect();
|
||||
/** 发送消息给手表 */
|
||||
void sendToWatch(String json);
|
||||
/** 接收来自手表的消息 */
|
||||
String onWatchMessage(String json);
|
||||
public class WatchBridge {
|
||||
|
||||
public interface Listener {
|
||||
void onWatchConnected(boolean connected, String nodeId);
|
||||
void onWatchMessage(String json);
|
||||
void onError(String message);
|
||||
}
|
||||
|
||||
private final Context context;
|
||||
private final Listener listener;
|
||||
private final Handler main = new Handler(Looper.getMainLooper());
|
||||
private final NodeApi nodeApi;
|
||||
private final MessageApi messageApi;
|
||||
private Node node;
|
||||
|
||||
public WatchBridge(Context context, Listener listener) {
|
||||
this.context = context.getApplicationContext();
|
||||
this.listener = listener;
|
||||
this.nodeApi = Wearable.getNodeApi(this.context);
|
||||
this.messageApi = Wearable.getMessageApi(this.context);
|
||||
}
|
||||
|
||||
public void connect() {
|
||||
nodeApi.getConnectedNodes()
|
||||
.addOnSuccessListener(nodes -> {
|
||||
if (nodes != null && nodes.size() > 0) {
|
||||
node = nodes.get(0);
|
||||
main.post(() -> listener.onWatchConnected(true, node.getId()));
|
||||
registerListener();
|
||||
} else {
|
||||
main.post(() -> listener.onWatchConnected(false, null));
|
||||
}
|
||||
})
|
||||
.addOnFailureListener(e -> main.post(() -> listener.onError("getConnectedNodes: " + e.getMessage())));
|
||||
}
|
||||
|
||||
private void registerListener() {
|
||||
OnMessageReceivedListener l = new OnMessageReceivedListener() {
|
||||
@Override
|
||||
public void onMessageReceived(String nodeId, byte[] message) {
|
||||
final String json = new String(message);
|
||||
main.post(() -> listener.onWatchMessage(json));
|
||||
}
|
||||
};
|
||||
messageApi.addListener(node.getId(), l)
|
||||
.addOnSuccessListener(ignore -> { })
|
||||
.addOnFailureListener(e -> main.post(() -> listener.onError("addListener: " + e.getMessage())));
|
||||
}
|
||||
|
||||
public void sendToWatch(String json) {
|
||||
if (node == null) return;
|
||||
messageApi.sendMessage(node.getId(), json.getBytes())
|
||||
.addOnSuccessListener(ignore -> { })
|
||||
.addOnFailureListener(e -> main.post(() -> listener.onError("sendMessage: " + e.getMessage())));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user