feat: 身份页显示本机账号台账(accounts_b64,v1.5)
平台在拉起身份页时顺带推这台设备登记的抖音账号(契约见 平台 doc/DEVICE_AGENT.md §5.2.1 与本仓库 INTERFACE.md §5.2.1): - 解析 `--es accounts_b64`(标准 base64 + UTF-8 → JSONObject),在设备信息下面 渲染账号列表:账号名称 / 抖音号 / [卡·发] 标记 - 一屏放不下:**最多显示 4 个** + "…还有 N 个,见平台「账号」页" (第一版 26sp 一行塞"名称+号+标记",720x1650 上第 3 个号就被切掉了,实测后收紧) - 三种情况分清楚:无 extra → 整块不显示(= 这台没登记账号,行为与旧版逐字一致); 有但解不开 → 显示一行"解析失败"(不静默,否则像"没账号");能解开 → 逐条列出 - 隐私:平台默认不推手机号(身份页是机器旁的公开屏幕) 版本 1.4 → 1.5(versionCode 6)。已在 A03 装机验证(带账号/不带账号两种截图)。
This commit is contained in:
+32
-2
@@ -201,17 +201,47 @@ adb -s <serial> shell am start -n <pkg>/.ClipActivity --es text_b64 <base64(UTF-
|
|||||||
- 平台判定失败的方式:`am start` 输出里有 `unable to resolve Intent` / `does not exist`
|
- 平台判定失败的方式:`am start` 输出里有 `unable to resolve Intent` / `does not exist`
|
||||||
→ 视为"设备未安装 Agent"
|
→ 视为"设备未安装 Agent"
|
||||||
|
|
||||||
### 5.2 设备身份显示(待设备端实现)
|
### 5.2 设备身份显示(已实现)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
adb -s <serial> shell am start -n <pkg>/.InfoActivity \
|
adb -s <serial> shell am start -n <pkg>/.InfoActivity \
|
||||||
--es name "A08" --es ip "192.168.20.100" --es serial "192.168.20.100:5555" \
|
--es name "A08" --es ip "192.168.20.100" --es serial "192.168.20.100:5555" \
|
||||||
--es server "http://192.168.20.220:18050"
|
--es server "http://192.168.20.220:18050" \
|
||||||
|
--es accounts_b64 "<base64(UTF-8 JSON)>" # 可选,见 §5.2.1
|
||||||
# 关闭:--es close 1
|
# 关闭:--es close 1
|
||||||
```
|
```
|
||||||
|
|
||||||
要求:全屏大字、再次调用可覆盖内容、`close` 可关闭、不驻留前台。
|
要求:全屏大字、再次调用可覆盖内容、`close` 可关闭、不驻留前台。
|
||||||
|
|
||||||
|
#### 5.2.1 本机账号台账(`accounts_b64`,可选 extras,已实现 v1.5)
|
||||||
|
|
||||||
|
平台在**打开**身份页时顺带推这台设备在「账号」页登记的抖音账号(`close` 时不带)。
|
||||||
|
**标准 base64(不是 URL_SAFE)+ UTF-8**:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{"v":1,"total":4,"shown":4,"truncated":false,
|
||||||
|
"note":"设备『A03』登记 4 个号",
|
||||||
|
"accounts":[
|
||||||
|
{"name":"AA建材王总","douyin_id":"66057500463","device_name":"A03","device_no":"A03",
|
||||||
|
"sim_in_device":true,"can_post_video":true}]}
|
||||||
|
```
|
||||||
|
|
||||||
|
| 字段 | 说明 |
|
||||||
|
|------|------|
|
||||||
|
| `v` | 块格式版本(当前 **1**) |
|
||||||
|
| `total` / `shown` / `truncated` | 台账里的总数 / 本次几条 / 是否被截断 |
|
||||||
|
| `accounts[].name` / `douyin_id` | 账号名称 / **抖音号(纯号)** |
|
||||||
|
| `accounts[].sim_in_device` / `can_post_video` | 卡在机内 / 可发视频 |
|
||||||
|
| `accounts[].phone` | **默认不推**(大字页是公开屏幕);平台侧可传 `include_phone:true` 要 |
|
||||||
|
|
||||||
|
设备端三种情况要分清(InfoActivity 已按此实现):
|
||||||
|
|
||||||
|
| 情况 | 表现 |
|
||||||
|
|---|---|
|
||||||
|
| 没有该 extra | 账号块**整块不显示**(= 这台设备在台账里没登记账号,旧平台也走这条) |
|
||||||
|
| 有但解不开 | 显示一行**解析失败**提示(不要静默,否则看着像"这台没账号") |
|
||||||
|
| 有且能解开 | 逐条显示;`truncated` 时补"…还有 N 个,见平台「账号」页" |
|
||||||
|
|
||||||
### 5.3 一次性配置下发(建议设备端实现)
|
### 5.3 一次性配置下发(建议设备端实现)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|||||||
+2
-2
@@ -11,8 +11,8 @@ android {
|
|||||||
applicationId "com.example.deviceagent"
|
applicationId "com.example.deviceagent"
|
||||||
minSdk 29 // Android 10;剪贴板限制就是从这一版开始的
|
minSdk 29 // Android 10;剪贴板限制就是从这一版开始的
|
||||||
targetSdk 34
|
targetSdk 34
|
||||||
versionCode 5
|
versionCode 6
|
||||||
versionName "1.4"
|
versionName "1.5" // 1.5:身份页显示本机账号台账(accounts_b64)
|
||||||
}
|
}
|
||||||
|
|
||||||
buildTypes {
|
buildTypes {
|
||||||
|
|||||||
@@ -4,11 +4,13 @@ import android.app.Activity
|
|||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.graphics.Color
|
import android.graphics.Color
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.util.Base64
|
||||||
import android.util.TypedValue
|
import android.util.TypedValue
|
||||||
import android.view.Gravity
|
import android.view.Gravity
|
||||||
import android.view.WindowManager
|
import android.view.WindowManager
|
||||||
import android.widget.LinearLayout
|
import android.widget.LinearLayout
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
|
import org.json.JSONObject
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.Date
|
import java.util.Date
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
@@ -18,16 +20,23 @@ import java.util.Locale
|
|||||||
*
|
*
|
||||||
* adb shell am start -n com.example.deviceagent/.InfoActivity \
|
* adb shell am start -n com.example.deviceagent/.InfoActivity \
|
||||||
* --es name A08 --es ip 192.168.20.100 --es serial 192.168.20.100:5555 \
|
* --es name A08 --es ip 192.168.20.100 --es serial 192.168.20.100:5555 \
|
||||||
* --es server http://192.168.20.220:18050
|
* --es server http://192.168.20.220:18050 \
|
||||||
|
* --es accounts_b64 <base64(UTF-8 JSON)> # 可选:本机账号台账
|
||||||
* # 关闭:--es close 1
|
* # 关闭:--es close 1
|
||||||
*
|
*
|
||||||
* 用途:人站在机架前,一眼看出"手头这台是平台上的哪一台";排查断联时不用连电脑。
|
* 用途:人站在机架前,一眼看出"手头这台是平台上的哪一台"、**登着哪几个号**;
|
||||||
|
* 对号/排查断联时不用连电脑。
|
||||||
* 再次调用会覆盖内容(launchMode=singleTop + onNewIntent)。
|
* 再次调用会覆盖内容(launchMode=singleTop + onNewIntent)。
|
||||||
|
*
|
||||||
|
* `accounts_b64` 是可选的加字段(契约见平台 doc/DEVICE_AGENT.md §5.2.1 与本仓库 INTERFACE.md):
|
||||||
|
* **没有这个 extra = 这台设备在台账里没有账号**(不是"平台忘了给"),此时账号块整块不显示。
|
||||||
|
* 解码用**标准 base64**(不是 URL_SAFE)+ UTF-8。
|
||||||
*/
|
*/
|
||||||
class InfoActivity : Activity() {
|
class InfoActivity : Activity() {
|
||||||
|
|
||||||
private lateinit var tvName: TextView
|
private lateinit var tvName: TextView
|
||||||
private lateinit var tvLines: TextView
|
private lateinit var tvLines: TextView
|
||||||
|
private lateinit var tvAccounts: TextView
|
||||||
private lateinit var tvTime: TextView
|
private lateinit var tvTime: TextView
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
@@ -61,9 +70,19 @@ class InfoActivity : Activity() {
|
|||||||
}
|
}
|
||||||
tvLines = TextView(this).apply {
|
tvLines = TextView(this).apply {
|
||||||
setTextColor(Color.parseColor("#FFD54F"))
|
setTextColor(Color.parseColor("#FFD54F"))
|
||||||
setTextSize(TypedValue.COMPLEX_UNIT_SP, 26f)
|
setTextSize(TypedValue.COMPLEX_UNIT_SP, 24f)
|
||||||
gravity = Gravity.CENTER
|
gravity = Gravity.CENTER
|
||||||
setPadding(0, 40, 0, 40)
|
setPadding(0, 24, 0, 20)
|
||||||
|
}
|
||||||
|
// 本机账号(台账推过来的):站在机器旁就能看出这台登着哪几个号
|
||||||
|
// 字号/行距刻意比上面的设备信息小一档:一屏要塞下"设备信息 + 最多 4 个号",
|
||||||
|
// 26sp 时第 3 个号就被切掉了(实测 720x1650 上溢出)
|
||||||
|
tvAccounts = TextView(this).apply {
|
||||||
|
setTextColor(Color.parseColor("#80DEEA"))
|
||||||
|
setTextSize(TypedValue.COMPLEX_UNIT_SP, 22f)
|
||||||
|
gravity = Gravity.START
|
||||||
|
setPadding(0, 8, 0, 16)
|
||||||
|
visibility = android.view.View.GONE // 没有 accounts_b64 就不占位
|
||||||
}
|
}
|
||||||
tvTime = TextView(this).apply {
|
tvTime = TextView(this).apply {
|
||||||
setTextColor(Color.parseColor("#9E9E9E"))
|
setTextColor(Color.parseColor("#9E9E9E"))
|
||||||
@@ -72,6 +91,7 @@ class InfoActivity : Activity() {
|
|||||||
}
|
}
|
||||||
root.addView(tvName)
|
root.addView(tvName)
|
||||||
root.addView(tvLines)
|
root.addView(tvLines)
|
||||||
|
root.addView(tvAccounts)
|
||||||
root.addView(tvTime)
|
root.addView(tvTime)
|
||||||
setContentView(root)
|
setContentView(root)
|
||||||
}
|
}
|
||||||
@@ -90,5 +110,59 @@ class InfoActivity : Activity() {
|
|||||||
"Agent v${Prefs.agentVersion(this)}"
|
"Agent v${Prefs.agentVersion(this)}"
|
||||||
).filter { it.substringAfter(" ").trim().isNotEmpty() }.joinToString("\n")
|
).filter { it.substringAfter(" ").trim().isNotEmpty() }.joinToString("\n")
|
||||||
tvTime.text = "更新于 " + SimpleDateFormat("HH:mm:ss", Locale.CHINA).format(Date())
|
tvTime.text = "更新于 " + SimpleDateFormat("HH:mm:ss", Locale.CHINA).format(Date())
|
||||||
|
renderAccounts(intent?.getStringExtra("accounts_b64").orEmpty())
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 本机账号块。契约(平台 doc/DEVICE_AGENT.md §5.2.1):
|
||||||
|
* `{"v":1,"total":4,"shown":4,"truncated":false,"accounts":[{"name","douyin_id",…}]}`
|
||||||
|
*
|
||||||
|
* 三种情况要分清,别混成一种:
|
||||||
|
* · 没有 extra → 这台设备在台账里没登记账号 → 整块不显示(旧平台/旧行为)
|
||||||
|
* · 有但解不开 → 格式变了或串被截断 → 显示一行提示(**不要静默**,否则像"没账号")
|
||||||
|
* · 有且能解开 → 逐条显示;`truncated` 时补一行"还有 N 个"
|
||||||
|
*/
|
||||||
|
private fun renderAccounts(b64: String) {
|
||||||
|
if (b64.isEmpty()) {
|
||||||
|
tvAccounts.visibility = android.view.View.GONE
|
||||||
|
return
|
||||||
|
}
|
||||||
|
tvAccounts.visibility = android.view.View.VISIBLE
|
||||||
|
val obj = try {
|
||||||
|
JSONObject(String(Base64.decode(b64, Base64.DEFAULT), Charsets.UTF_8))
|
||||||
|
} catch (e: Exception) {
|
||||||
|
// 解不开要说出来:不然跟"这台没账号"长得一样,平台侧还以为推成功了
|
||||||
|
tvAccounts.setTextColor(Color.parseColor("#FF8A65"))
|
||||||
|
tvAccounts.text = "账号信息解析失败(v?):${e.javaClass.simpleName}"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
tvAccounts.setTextColor(Color.parseColor("#80DEEA"))
|
||||||
|
val total = obj.optInt("total", 0)
|
||||||
|
val arr = obj.optJSONArray("accounts") ?: org.json.JSONArray()
|
||||||
|
if (arr.length() == 0) {
|
||||||
|
// 有块但 0 条:明确写出来,免得人以为"这页没渲染完"
|
||||||
|
tvAccounts.text = "本机账号:暂无(平台「账号」页还没登记这台设备)"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 一屏放不下太多:**只显示前 4 个**,其余用"还有 N 个"交代
|
||||||
|
// (人在机器旁要的是"这台是谁",不是把台账全量投到屏上)
|
||||||
|
val maxShow = 4
|
||||||
|
val n = minOf(arr.length(), maxShow)
|
||||||
|
val sb = StringBuilder("本机账号 $total 个")
|
||||||
|
for (i in 0 until n) {
|
||||||
|
val a = arr.optJSONObject(i) ?: continue
|
||||||
|
val name = a.optString("name").ifEmpty { "(未命名)" }
|
||||||
|
val id = a.optString("douyin_id")
|
||||||
|
val marks = buildList {
|
||||||
|
if (a.optBoolean("sim_in_device")) add("卡")
|
||||||
|
if (a.optBoolean("can_post_video")) add("发")
|
||||||
|
}
|
||||||
|
sb.append("\n").append(i + 1).append(". ").append(name)
|
||||||
|
if (id.isNotEmpty()) sb.append("\n ").append(id)
|
||||||
|
if (marks.isNotEmpty()) sb.append(" ").append(marks.joinToString("·"))
|
||||||
|
}
|
||||||
|
val rest = total - n
|
||||||
|
if (rest > 0) sb.append("\n…还有 ").append(rest).append(" 个,见平台「账号」页")
|
||||||
|
tvAccounts.text = sb.toString()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user