feat: add Xiaomi Wearable SDK AAR + real WatchBridge and watch<->server relay
This commit is contained in:
@@ -23,6 +23,7 @@ android {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
|
implementation fileTree(dir: 'libs', include: ['*.jar', '*.aar'])
|
||||||
implementation 'androidx.appcompat:appcompat:1.6.1'
|
implementation 'androidx.appcompat:appcompat:1.6.1'
|
||||||
implementation 'com.google.android.material:material:1.9.0'
|
implementation 'com.google.android.material:material:1.9.0'
|
||||||
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
|
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
|
||||||
|
|||||||
Binary file not shown.
@@ -13,7 +13,8 @@ import org.json.JSONObject;
|
|||||||
public class MainActivity extends AppCompatActivity {
|
public class MainActivity extends AppCompatActivity {
|
||||||
|
|
||||||
private TextView status;
|
private TextView status;
|
||||||
private ServerClient client;
|
private ServerClient serverClient;
|
||||||
|
private WatchBridge watchBridge;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
@@ -22,30 +23,33 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
|
|
||||||
status = findViewById(R.id.status_text);
|
status = findViewById(R.id.status_text);
|
||||||
|
|
||||||
client = new ServerClient(new ServerClient.Listener() {
|
// 服务器客户端
|
||||||
|
serverClient = new ServerClient(new ServerClient.Listener() {
|
||||||
@Override
|
@Override
|
||||||
public void onConnectionChanged(boolean connected) {
|
public void onConnectionChanged(boolean connected) {
|
||||||
runOnUiThread(() -> status.setText(connected ? "已连接(空壳)" : "连接断开"));
|
runOnUiThread(() -> status.setText(connected ? "服务器已连接" : "服务器断开"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onHello(JSONObject hello) {
|
public void onHello(JSONObject hello) {
|
||||||
// 连接建立后拉一次状态
|
serverClient.sendRequest("harness.status", new JSONObject());
|
||||||
client.sendRequest("harness.status", new JSONObject());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onStatus(JSONObject s) {
|
public void onStatus(JSONObject s) {
|
||||||
runOnUiThread(() -> {
|
if (s != null) {
|
||||||
if (s != null) {
|
runOnUiThread(() -> status.setText("状态: " + s.optString("model") + " / " + s.optString("cwd")));
|
||||||
status.setText("状态: " + s.optString("model") + " / " + s.optString("cwd"));
|
}
|
||||||
}
|
if (watchBridge != null) {
|
||||||
});
|
watchBridge.sendToWatch(s.toString());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onEvent(JSONObject event) {
|
public void onEvent(JSONObject event) {
|
||||||
// 空壳:后续写入事件流
|
if (watchBridge != null) {
|
||||||
|
watchBridge.sendToWatch(event.toString());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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);
|
Button settings = findViewById(R.id.btn_settings);
|
||||||
settings.setOnClickListener(new View.OnClickListener() {
|
settings.setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
@@ -73,7 +107,8 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
status.setText("连接中...");
|
status.setText("连接中...");
|
||||||
// 空壳:默认连本机模拟器 server;真实地址/用户/Token 从设置读取
|
// 空壳:默认连本机模拟器 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
|
@Override
|
||||||
protected void onDestroy() {
|
protected void onDestroy() {
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
if (client != null) client.close();
|
if (serverClient != null) serverClient.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,73 @@
|
|||||||
package com.dshwatch.app;
|
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 互联桥(空壳)。
|
* 手表 BLE 互联桥(使用小米穿戴 xms-wearable SDK)。
|
||||||
* 后续接入小米穿戴 SDK:Wearable / MessageApi / sendMessage / addListener,
|
* 负责:发现手表节点、注册消息监听、把 JSON 发给手表、把收到的消息回传。
|
||||||
* 用于把手表(DSHWatch) 与手机端双向转发。
|
* 与 ServerClient 联动即可实现 手机(Server) <-> 手表(Watch) 双向转发。
|
||||||
*/
|
*/
|
||||||
public interface WatchBridge {
|
public class WatchBridge {
|
||||||
/** 连接手表(小米穿戴服务) */
|
|
||||||
void connect();
|
public interface Listener {
|
||||||
/** 发送消息给手表 */
|
void onWatchConnected(boolean connected, String nodeId);
|
||||||
void sendToWatch(String json);
|
void onWatchMessage(String json);
|
||||||
/** 接收来自手表的消息 */
|
void onError(String message);
|
||||||
String onWatchMessage(String json);
|
}
|
||||||
|
|
||||||
|
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