Harden read-only thread handling and refresh Android releases
This commit is contained in:
@@ -118,7 +118,7 @@ public class AboutActivity extends BossScreenActivity {
|
||||
appendContent(BossUi.buildWechatMenuRow(
|
||||
this,
|
||||
"当前版本",
|
||||
user == null ? ota.optString("currentVersion", "-") : user.optString("version", ota.optString("currentVersion", "-")),
|
||||
resolveInstalledVersionLabel(user, ota, BuildConfig.VERSION_NAME),
|
||||
"已安装版本",
|
||||
null,
|
||||
null
|
||||
@@ -171,6 +171,23 @@ public class AboutActivity extends BossScreenActivity {
|
||||
return "发现新版本 " + availableRelease.optString("version", "未知版本");
|
||||
}
|
||||
|
||||
private static String resolveInstalledVersionLabel(
|
||||
@Nullable JSONObject user,
|
||||
JSONObject ota,
|
||||
@Nullable String packageVersionName
|
||||
) {
|
||||
if (packageVersionName != null && !packageVersionName.isEmpty()) {
|
||||
return packageVersionName;
|
||||
}
|
||||
if (user != null) {
|
||||
String userVersion = user.optString("version", "");
|
||||
if (!userVersion.isEmpty()) {
|
||||
return userVersion;
|
||||
}
|
||||
}
|
||||
return ota.optString("currentVersion", "-");
|
||||
}
|
||||
|
||||
private static String buildOtaStatusMeta(JSONObject ota) {
|
||||
JSONObject availableRelease = ota.optJSONObject("availableRelease");
|
||||
if (availableRelease == null) {
|
||||
|
||||
@@ -14,6 +14,8 @@ import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
@@ -25,6 +27,11 @@ public class GroupCreateActivity extends BossScreenActivity {
|
||||
private final List<CandidateConversation> candidates = new ArrayList<>();
|
||||
private final Set<String> selectedProjectIds = new LinkedHashSet<>();
|
||||
private final Set<String> lastCandidateProjectIds = new LinkedHashSet<>();
|
||||
private static final Set<String> AUTO_JOIN_GROUP_TITLES = new HashSet<>(Arrays.asList(
|
||||
"主agent",
|
||||
"硬件审计协作",
|
||||
"boss移动控制台"
|
||||
));
|
||||
|
||||
private String sourceProjectId;
|
||||
private String sourceProjectName;
|
||||
@@ -193,21 +200,41 @@ public class GroupCreateActivity extends BossScreenActivity {
|
||||
if (conversations == null) {
|
||||
return result;
|
||||
}
|
||||
boolean hasSourceProject = sourceProjectId != null && !sourceProjectId.isEmpty();
|
||||
for (int i = 0; i < conversations.length(); i++) {
|
||||
JSONObject item = conversations.optJSONObject(i);
|
||||
if (item == null) continue;
|
||||
String projectId = item.optString("projectId", "");
|
||||
if (projectId.isEmpty()
|
||||
|| (hasSourceProject && sourceProjectId.equals(projectId))
|
||||
|| item.optBoolean("isGroup", false)) {
|
||||
continue;
|
||||
if (isEligibleForManualGroupSelection(item, sourceProjectId)) {
|
||||
result.add(item);
|
||||
}
|
||||
result.add(item);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static boolean isEligibleForManualGroupSelection(@Nullable JSONObject item, @Nullable String sourceProjectId) {
|
||||
if (item == null) {
|
||||
return false;
|
||||
}
|
||||
String projectId = item.optString("projectId", "");
|
||||
if (projectId.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
if (sourceProjectId != null && !sourceProjectId.isEmpty() && sourceProjectId.equals(projectId)) {
|
||||
return false;
|
||||
}
|
||||
if (item.optBoolean("isGroup", false)) {
|
||||
return false;
|
||||
}
|
||||
if (!"single_device".equals(item.optString("conversationType", "single_device"))) {
|
||||
return false;
|
||||
}
|
||||
return !AUTO_JOIN_GROUP_TITLES.contains(normalizeConversationTitle(item));
|
||||
}
|
||||
|
||||
private static String normalizeConversationTitle(JSONObject item) {
|
||||
String title = item.optString("projectTitle", item.optString("threadTitle", ""));
|
||||
return title == null ? "" : title.replaceAll("\\s+", "").toLowerCase();
|
||||
}
|
||||
|
||||
static WechatSurfaceMapper.ConversationRow toCandidateConversationRow(JSONObject item, boolean selected) {
|
||||
return new WechatSurfaceMapper.ConversationRow(
|
||||
item.optString("projectTitle", item.optString("threadTitle", "未命名会话")),
|
||||
|
||||
@@ -144,17 +144,27 @@ public class GroupCreateActivityUiTest {
|
||||
JSONArray conversations = new JSONArray()
|
||||
.put(new JSONObject()
|
||||
.put("projectId", "thread-2")
|
||||
.put("projectTitle", "硬件审计协作")
|
||||
.put("projectTitle", "查询树莓派二代")
|
||||
.put("folderLabel", "Mac Studio")
|
||||
.put("lastMessagePreview", "检查摄像头供电链路")
|
||||
.put("lastMessagePreview", "检查树莓派二代供电链路")
|
||||
.put("latestReplyLabel", "09:28")
|
||||
.put("conversationType", "single_device")
|
||||
.put("isGroup", false))
|
||||
.put(new JSONObject()
|
||||
.put("projectId", "thread-3")
|
||||
.put("projectTitle", "Boss 移动控制台")
|
||||
.put("projectTitle", "Boss 线程修复")
|
||||
.put("folderLabel", "Boss")
|
||||
.put("lastMessagePreview", "统一顶部按钮样式")
|
||||
.put("latestReplyLabel", "09:31")
|
||||
.put("conversationType", "single_device")
|
||||
.put("isGroup", false))
|
||||
.put(new JSONObject()
|
||||
.put("projectId", "thread-4")
|
||||
.put("projectTitle", "主Agent")
|
||||
.put("folderLabel", "Boss")
|
||||
.put("lastMessagePreview", "系统自动加入")
|
||||
.put("latestReplyLabel", "09:32")
|
||||
.put("conversationType", "single_device")
|
||||
.put("isGroup", false));
|
||||
return new JSONObject().put("conversations", conversations);
|
||||
}
|
||||
|
||||
@@ -187,6 +187,24 @@ public class WechatSurfaceMapperTest {
|
||||
assertEquals("版本 v1.2.8\n1. 优化设备状态刷新\n2. 修复主 Agent 会话排序\n3. 提升 OTA 回收稳定性", content);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void aboutActivity_prefersInstalledPackageVersionOverServerVersion() throws Exception {
|
||||
JSONObject ota = new StubJSONObject().withString("currentVersion", "v1.4.1");
|
||||
JSONObject user = new StubJSONObject().withString("version", "v1.4.1");
|
||||
|
||||
java.lang.reflect.Method method = AboutActivity.class.getDeclaredMethod(
|
||||
"resolveInstalledVersionLabel",
|
||||
JSONObject.class,
|
||||
JSONObject.class,
|
||||
String.class
|
||||
);
|
||||
method.setAccessible(true);
|
||||
|
||||
String installedVersion = (String) method.invoke(null, user, ota, "2.5.3");
|
||||
|
||||
assertEquals("2.5.3", installedVersion);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void aboutActivity_rejectsStaleDownloadedApkWhenAvailableReleaseChanged() throws Exception {
|
||||
JSONObject availableRelease = new StubJSONObject()
|
||||
|
||||
Reference in New Issue
Block a user