@yume-chan/android-bin 2.0.1 → 3.0.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (100) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +5 -2
  3. package/esm/am.d.ts +20 -15
  4. package/esm/am.d.ts.map +1 -1
  5. package/esm/am.js +60 -13
  6. package/esm/am.js.map +1 -1
  7. package/esm/bu.d.ts +22 -18
  8. package/esm/bu.d.ts.map +1 -1
  9. package/esm/bu.js +10 -4
  10. package/esm/bu.js.map +1 -1
  11. package/esm/bug-report.d.ts +21 -20
  12. package/esm/bug-report.d.ts.map +1 -1
  13. package/esm/bug-report.js +15 -21
  14. package/esm/bug-report.js.map +1 -1
  15. package/esm/cmd/index.d.ts +2 -0
  16. package/esm/cmd/index.d.ts.map +1 -0
  17. package/esm/cmd/index.js +2 -0
  18. package/esm/cmd/index.js.map +1 -0
  19. package/esm/cmd/none.d.ts +5 -0
  20. package/esm/cmd/none.d.ts.map +1 -0
  21. package/esm/cmd/none.js +39 -0
  22. package/esm/cmd/none.js.map +1 -0
  23. package/esm/cmd/service.d.ts +29 -0
  24. package/esm/cmd/service.d.ts.map +1 -0
  25. package/esm/cmd/service.js +24 -0
  26. package/esm/cmd/service.js.map +1 -0
  27. package/esm/cmd/shell.d.ts +5 -0
  28. package/esm/cmd/shell.d.ts.map +1 -0
  29. package/esm/cmd/shell.js +43 -0
  30. package/esm/cmd/shell.js.map +1 -0
  31. package/esm/cmd/utils.d.ts +5 -0
  32. package/esm/cmd/utils.d.ts.map +1 -0
  33. package/esm/cmd/utils.js +24 -0
  34. package/esm/cmd/utils.js.map +1 -0
  35. package/esm/demo-mode.d.ts +3 -4
  36. package/esm/demo-mode.d.ts.map +1 -1
  37. package/esm/demo-mode.js +13 -21
  38. package/esm/demo-mode.js.map +1 -1
  39. package/esm/dumpsys.d.ts +4 -2
  40. package/esm/dumpsys.d.ts.map +1 -1
  41. package/esm/dumpsys.js +13 -10
  42. package/esm/dumpsys.js.map +1 -1
  43. package/esm/index.d.ts +1 -1
  44. package/esm/index.d.ts.map +1 -1
  45. package/esm/index.js +1 -1
  46. package/esm/index.js.map +1 -1
  47. package/esm/intent.d.ts +37 -9
  48. package/esm/intent.d.ts.map +1 -1
  49. package/esm/intent.js +116 -53
  50. package/esm/intent.js.map +1 -1
  51. package/esm/logcat.d.ts +8 -6
  52. package/esm/logcat.d.ts.map +1 -1
  53. package/esm/logcat.js +9 -6
  54. package/esm/logcat.js.map +1 -1
  55. package/esm/overlay-display.d.ts +17 -14
  56. package/esm/overlay-display.d.ts.map +1 -1
  57. package/esm/overlay-display.js +2 -4
  58. package/esm/overlay-display.js.map +1 -1
  59. package/esm/pm.d.ts +131 -168
  60. package/esm/pm.d.ts.map +1 -1
  61. package/esm/pm.js +229 -112
  62. package/esm/pm.js.map +1 -1
  63. package/esm/settings.d.ts +1 -2
  64. package/esm/settings.d.ts.map +1 -1
  65. package/esm/settings.js +9 -9
  66. package/esm/settings.js.map +1 -1
  67. package/esm/string-format.d.ts +2 -2
  68. package/esm/string-format.d.ts.map +1 -1
  69. package/esm/string-format.js.map +1 -1
  70. package/esm/utils.d.ts +4 -1
  71. package/esm/utils.d.ts.map +1 -1
  72. package/esm/utils.js +25 -14
  73. package/esm/utils.js.map +1 -1
  74. package/package.json +8 -8
  75. package/src/am.ts +94 -34
  76. package/src/bu.ts +31 -20
  77. package/src/bug-report.ts +42 -42
  78. package/src/cmd/index.ts +1 -0
  79. package/src/cmd/none.ts +62 -0
  80. package/src/cmd/service.ts +54 -0
  81. package/src/cmd/shell.ts +67 -0
  82. package/src/cmd/utils.ts +35 -0
  83. package/src/demo-mode.ts +13 -24
  84. package/src/dumpsys.ts +16 -10
  85. package/src/index.ts +1 -1
  86. package/src/intent.ts +187 -49
  87. package/src/logcat.ts +16 -10
  88. package/src/overlay-display.ts +21 -19
  89. package/src/pm.ts +375 -302
  90. package/src/settings.ts +11 -10
  91. package/src/string-format.ts +3 -3
  92. package/src/utils.ts +32 -15
  93. package/tsconfig.build.json +0 -11
  94. package/CHANGELOG.md +0 -171
  95. package/esm/cmd.d.ts +0 -23
  96. package/esm/cmd.d.ts.map +0 -1
  97. package/esm/cmd.js +0 -102
  98. package/esm/cmd.js.map +0 -1
  99. package/src/cmd.ts +0 -164
  100. package/tsconfig.build.tsbuildinfo +0 -1
@@ -0,0 +1,62 @@
1
+ import type { Adb } from "@yume-chan/adb";
2
+ import {
3
+ AdbFeature,
4
+ AdbNoneProtocolProcessImpl,
5
+ adbNoneProtocolSpawner,
6
+ escapeArg,
7
+ } from "@yume-chan/adb";
8
+
9
+ import { Cmd } from "./service.js";
10
+ import { checkCommand, resolveFallback, serializeAbbService } from "./utils.js";
11
+
12
+ export function createNoneProtocol(
13
+ adb: Adb,
14
+ fallback: NonNullable<Cmd.Fallback>,
15
+ ): Cmd.NoneProtocolService;
16
+ export function createNoneProtocol(
17
+ adb: Adb,
18
+ fallback?: Cmd.Fallback,
19
+ ): Cmd.NoneProtocolService | undefined;
20
+ export function createNoneProtocol(
21
+ adb: Adb,
22
+ fallback?: Cmd.Fallback,
23
+ ): Cmd.NoneProtocolService | undefined {
24
+ if (adb.canUseFeature(AdbFeature.AbbExec)) {
25
+ return {
26
+ mode: Cmd.Mode.Abb,
27
+ spawn: adbNoneProtocolSpawner(async (command, signal) => {
28
+ const service = serializeAbbService("abb_exec", command);
29
+ const socket = await adb.createSocket(service);
30
+ return new AdbNoneProtocolProcessImpl(socket, signal);
31
+ }),
32
+ };
33
+ }
34
+
35
+ if (adb.canUseFeature(AdbFeature.Cmd)) {
36
+ return {
37
+ mode: Cmd.Mode.Cmd,
38
+ spawn: adbNoneProtocolSpawner(async (command, signal) => {
39
+ checkCommand(command);
40
+
41
+ const newCommand = command.map(escapeArg);
42
+ newCommand.unshift("cmd");
43
+ return adb.subprocess.noneProtocol.spawn(newCommand, signal);
44
+ }),
45
+ };
46
+ }
47
+
48
+ if (fallback) {
49
+ return {
50
+ mode: Cmd.Mode.Fallback,
51
+ spawn: adbNoneProtocolSpawner(async (command, signal) => {
52
+ checkCommand(command);
53
+
54
+ const newCommand = command.map(escapeArg);
55
+ newCommand[0] = resolveFallback(fallback, command[0]!);
56
+ return adb.subprocess.noneProtocol.spawn(newCommand, signal);
57
+ }),
58
+ };
59
+ }
60
+
61
+ return undefined;
62
+ }
@@ -0,0 +1,54 @@
1
+ import type {
2
+ Adb,
3
+ AdbNoneProtocolSpawner,
4
+ AdbShellProtocolSpawner,
5
+ } from "@yume-chan/adb";
6
+
7
+ import { createNoneProtocol } from "./none.js";
8
+ import { createShellProtocol } from "./shell.js";
9
+
10
+ export class Cmd {
11
+ static readonly Mode = {
12
+ Abb: 0,
13
+ Cmd: 1,
14
+ Fallback: 2,
15
+ } as const;
16
+
17
+ static readonly createNoneProtocol = createNoneProtocol;
18
+ static readonly createShellProtocol = createShellProtocol;
19
+
20
+ #noneProtocol: Cmd.NoneProtocolService | undefined;
21
+ get noneProtocol() {
22
+ return this.#noneProtocol;
23
+ }
24
+
25
+ #shellProtocol: Cmd.ShellProtocolService | undefined;
26
+ get shellProtocol() {
27
+ return this.#shellProtocol;
28
+ }
29
+
30
+ constructor(adb: Adb, fallback?: Cmd.Fallback) {
31
+ this.#noneProtocol = createNoneProtocol(adb, fallback);
32
+ this.#shellProtocol = createShellProtocol(adb, fallback);
33
+ }
34
+ }
35
+
36
+ export namespace Cmd {
37
+ export type Fallback =
38
+ | string
39
+ | Record<string, string>
40
+ | ((service: string) => string)
41
+ | undefined;
42
+
43
+ export type Mode = (typeof Cmd.Mode)[keyof typeof Cmd.Mode];
44
+
45
+ export interface NoneProtocolService {
46
+ mode: Mode;
47
+ spawn: AdbNoneProtocolSpawner;
48
+ }
49
+
50
+ export interface ShellProtocolService {
51
+ mode: Mode;
52
+ spawn: AdbShellProtocolSpawner;
53
+ }
54
+ }
@@ -0,0 +1,67 @@
1
+ import type { Adb } from "@yume-chan/adb";
2
+ import {
3
+ AdbFeature,
4
+ AdbShellProtocolProcessImpl,
5
+ adbShellProtocolSpawner,
6
+ escapeArg,
7
+ } from "@yume-chan/adb";
8
+
9
+ import { Cmd } from "./service.js";
10
+ import { checkCommand, resolveFallback, serializeAbbService } from "./utils.js";
11
+
12
+ export function createShellProtocol(
13
+ adb: Adb,
14
+ fallback: NonNullable<Cmd.Fallback>,
15
+ ): Cmd.ShellProtocolService;
16
+ export function createShellProtocol(
17
+ adb: Adb,
18
+ fallback?: Cmd.Fallback,
19
+ ): Cmd.ShellProtocolService | undefined;
20
+ export function createShellProtocol(
21
+ adb: Adb,
22
+ fallback?: Cmd.Fallback,
23
+ ): Cmd.ShellProtocolService | undefined {
24
+ if (adb.canUseFeature(AdbFeature.Abb)) {
25
+ return {
26
+ mode: Cmd.Mode.Abb,
27
+ spawn: adbShellProtocolSpawner(async (command, signal) => {
28
+ const service = serializeAbbService("abb", command);
29
+ const socket = await adb.createSocket(service);
30
+ return new AdbShellProtocolProcessImpl(socket, signal);
31
+ }),
32
+ };
33
+ }
34
+
35
+ const shellProtocolService = adb.subprocess.shellProtocol;
36
+ if (!shellProtocolService) {
37
+ return undefined;
38
+ }
39
+
40
+ if (adb.canUseFeature(AdbFeature.Cmd)) {
41
+ return {
42
+ mode: Cmd.Mode.Cmd,
43
+ spawn: adbShellProtocolSpawner(async (command, signal) => {
44
+ checkCommand(command);
45
+
46
+ const newCommand = command.map(escapeArg);
47
+ newCommand.unshift("cmd");
48
+ return shellProtocolService.spawn(newCommand, signal);
49
+ }),
50
+ };
51
+ }
52
+
53
+ if (fallback) {
54
+ return {
55
+ mode: Cmd.Mode.Fallback,
56
+ spawn: adbShellProtocolSpawner(async (command, signal) => {
57
+ checkCommand(command);
58
+
59
+ const newCommand = command.map(escapeArg);
60
+ newCommand[0] = resolveFallback(fallback, command[0]!);
61
+ return shellProtocolService.spawn(newCommand, signal);
62
+ }),
63
+ };
64
+ }
65
+
66
+ return undefined;
67
+ }
@@ -0,0 +1,35 @@
1
+ import type { Cmd } from "./service.js";
2
+
3
+ export function resolveFallback(
4
+ fallback: Cmd.Fallback,
5
+ command: string,
6
+ ): string {
7
+ if (typeof fallback === "function") {
8
+ fallback = fallback(command);
9
+ } else if (typeof fallback === "object" && fallback !== null) {
10
+ fallback = fallback[command];
11
+ }
12
+
13
+ if (!fallback) {
14
+ throw new Error(`No fallback configured for command "${command}"`);
15
+ }
16
+
17
+ return fallback;
18
+ }
19
+
20
+ export function checkCommand(command: readonly string[]) {
21
+ if (!command.length) {
22
+ throw new TypeError("Command is empty");
23
+ }
24
+ }
25
+
26
+ export function serializeAbbService(
27
+ prefix: string,
28
+ command: readonly string[],
29
+ ): string {
30
+ checkCommand(command);
31
+
32
+ // `abb` mode uses `\0` as the separator, allowing space in arguments.
33
+ // The last `\0` is required for older versions of `adb`.
34
+ return `${prefix}:${command.join("\0")}\0`;
35
+ }
package/src/demo-mode.ts CHANGED
@@ -5,8 +5,8 @@
5
5
  // cspell: ignore sysui
6
6
 
7
7
  import type { Adb } from "@yume-chan/adb";
8
- import { AdbServiceBase } from "@yume-chan/adb";
9
8
 
9
+ import { ActivityManager } from "./am.js";
10
10
  import { Settings } from "./settings.js";
11
11
 
12
12
  export enum DemoModeSignalStrength {
@@ -51,11 +51,12 @@ export const DemoModeStatusBarModes = [
51
51
 
52
52
  export type DemoModeStatusBarMode = (typeof DemoModeStatusBarModes)[number];
53
53
 
54
- export class DemoMode extends AdbServiceBase {
54
+ export class DemoMode {
55
+ #am: ActivityManager;
55
56
  #settings: Settings;
56
57
 
57
- constructor(adb: Adb) {
58
- super(adb);
58
+ constructor(adb: Adb, apiLevel?: number) {
59
+ this.#am = new ActivityManager(adb, apiLevel);
59
60
  this.#settings = new Settings(adb);
60
61
  }
61
62
 
@@ -108,26 +109,14 @@ export class DemoMode extends AdbServiceBase {
108
109
  }
109
110
  }
110
111
 
111
- async broadcast(
112
- command: string,
113
- extra?: Record<string, string>,
114
- ): Promise<void> {
115
- await this.adb.subprocess.noneProtocol.spawnWaitText([
116
- "am",
117
- "broadcast",
118
- "-a",
119
- "com.android.systemui.demo",
120
- "-e",
121
- "command",
122
- command,
123
- ...(extra
124
- ? Object.entries(extra).flatMap(([key, value]) => [
125
- "-e",
126
- key,
127
- value,
128
- ])
129
- : []),
130
- ]);
112
+ broadcast(command: string, extras?: Record<string, string>): Promise<void> {
113
+ return this.#am.broadcast({
114
+ action: "com.android.systemui.demo",
115
+ extras: {
116
+ command,
117
+ ...extras,
118
+ },
119
+ });
131
120
  }
132
121
 
133
122
  async setBatteryLevel(level: number): Promise<void> {
package/src/dumpsys.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { AdbServiceBase } from "@yume-chan/adb";
1
+ import type { Adb } from "@yume-chan/adb";
2
2
 
3
3
  const BatteryDumpFields: Record<
4
4
  string,
@@ -54,14 +54,20 @@ const Battery = {
54
54
  Health,
55
55
  };
56
56
 
57
- export class DumpSys extends AdbServiceBase {
57
+ export class DumpSys {
58
58
  static readonly Battery = Battery;
59
59
 
60
+ readonly #adb: Adb;
61
+
62
+ constructor(adb: Adb) {
63
+ this.#adb = adb;
64
+ }
65
+
60
66
  async diskStats() {
61
- const result = await this.adb.subprocess.noneProtocol.spawnWaitText([
62
- "dumpsys",
63
- "diskstats",
64
- ]);
67
+ const result = await this.#adb.subprocess.noneProtocol
68
+ .spawn(["dumpsys", "diskstats"])
69
+ .wait()
70
+ .toString();
65
71
 
66
72
  function getSize(name: string) {
67
73
  const match = result.match(
@@ -91,10 +97,10 @@ export class DumpSys extends AdbServiceBase {
91
97
  }
92
98
 
93
99
  async battery(): Promise<DumpSys.Battery.Info> {
94
- const result = await this.adb.subprocess.noneProtocol.spawnWaitText([
95
- "dumpsys",
96
- "battery",
97
- ]);
100
+ const result = await this.#adb.subprocess.noneProtocol
101
+ .spawn(["dumpsys", "battery"])
102
+ .wait()
103
+ .toString();
98
104
 
99
105
  const info: DumpSys.Battery.Info = {
100
106
  acPowered: false,
package/src/index.ts CHANGED
@@ -3,7 +3,7 @@
3
3
  export * from "./am.js";
4
4
  export * from "./bu.js";
5
5
  export * from "./bug-report.js";
6
- export * from "./cmd.js";
6
+ export * from "./cmd/index.js";
7
7
  export * from "./demo-mode.js";
8
8
  export * from "./dumpsys.js";
9
9
  export * from "./intent.js";
package/src/intent.ts CHANGED
@@ -1,73 +1,211 @@
1
- export class IntentBuilder {
2
- #action: string | undefined;
3
- #categories: string[] = [];
4
- #packageName: string | undefined;
5
- #component: string | undefined;
6
- #data: string | undefined;
7
- #type: string | undefined;
8
- #stringExtras = new Map<string, string>();
9
-
10
- setAction(action: string): this {
11
- this.#action = action;
12
- return this;
13
- }
1
+ // cspell: ignore eial
2
+ // cspell: ignore elal
3
+ // cspell: ignore efal
4
+ // cspell: ignore esal
5
+ // cspell: ignore edal
6
+
7
+ export interface ComponentName {
8
+ packageName: string;
9
+ className: string;
10
+ }
11
+
12
+ export interface Intent {
13
+ action?: string | undefined;
14
+ data?: string | undefined;
15
+ type?: string | undefined;
16
+ identifier?: string | undefined;
17
+ categories?: string[] | undefined;
18
+ extras?:
19
+ | Record<
20
+ string,
21
+ | string
22
+ | null
23
+ | number
24
+ | bigint
25
+ | Intent.Extra.String
26
+ | ComponentName
27
+ | Intent.Extra.NumberArray
28
+ | Intent.Extra.StringArray
29
+ | Intent.Extra.Number
30
+ | boolean
31
+ >
32
+ | undefined;
33
+ flags?: number | undefined;
34
+ package?: string | undefined;
35
+ component?: ComponentName | undefined;
36
+ }
37
+
38
+ export namespace Intent {
39
+ export namespace Extra {
40
+ export interface Number {
41
+ type: "long" | "float" | "double";
42
+ value: number;
43
+ }
14
44
 
15
- addCategory(category: string): this {
16
- this.#categories.push(category);
17
- return this;
45
+ export interface String {
46
+ type: "uri";
47
+ value: string;
48
+ }
49
+
50
+ export interface NumberArray {
51
+ type: "array" | "arrayList";
52
+ itemType: "int" | Number["type"];
53
+ value: number[];
54
+ }
55
+
56
+ export interface StringArray {
57
+ type: "array" | "arrayList";
58
+ itemType: "string";
59
+ value: string[];
60
+ }
18
61
  }
62
+ }
19
63
 
20
- setPackage(packageName: string): this {
21
- this.#packageName = packageName;
22
- return this;
64
+ function getNumberType(type: "int" | Intent.Extra.Number["type"]) {
65
+ switch (type) {
66
+ case "int":
67
+ return "--ei";
68
+ case "long":
69
+ return "--el";
70
+ case "float":
71
+ return "--ef";
72
+ case "double":
73
+ return "--ed";
74
+ default:
75
+ throw new Error(`Unknown number type: ${type as string}`);
23
76
  }
77
+ }
24
78
 
25
- setComponent(component: string): this {
26
- this.#component = component;
27
- return this;
79
+ function serializeExtraArray(
80
+ array: Intent.Extra.NumberArray | Intent.Extra.StringArray,
81
+ ): [type: string, value: string] {
82
+ let type: string;
83
+ let value: string;
84
+
85
+ if (array.itemType === "string") {
86
+ type = "--es";
87
+ value = array.value
88
+ .map((item) => item.replaceAll(",", "\\,"))
89
+ .join(",");
90
+ } else {
91
+ type = getNumberType(array.itemType);
92
+ value = array.value.join(",");
28
93
  }
29
94
 
30
- setData(data: string): this {
31
- this.#data = data;
32
- return this;
95
+ if (array.type === "array") {
96
+ type += "a";
97
+ } else {
98
+ type += "al";
33
99
  }
34
100
 
35
- addStringExtra(key: string, value: string): this {
36
- this.#stringExtras.set(key, value);
37
- return this;
101
+ return [type, value];
102
+ }
103
+
104
+ function serializeString(
105
+ result: string[],
106
+ key: string,
107
+ value: string | undefined,
108
+ ) {
109
+ // Treat empty string as not set
110
+ if (value) {
111
+ result.push(key, value);
38
112
  }
113
+ }
39
114
 
40
- build(): string[] {
41
- const result: string[] = [];
115
+ export function serializeIntent(intent: Intent) {
116
+ const result: string[] = [];
42
117
 
43
- if (this.#action) {
44
- result.push("-a", this.#action);
45
- }
118
+ serializeString(result, "-a", intent.action);
119
+ serializeString(result, "-d", intent.data);
120
+ serializeString(result, "-t", intent.type);
121
+ serializeString(result, "-i", intent.identifier);
46
122
 
47
- for (const category of this.#categories) {
123
+ if (intent.categories) {
124
+ for (const category of intent.categories) {
48
125
  result.push("-c", category);
49
126
  }
127
+ }
50
128
 
51
- if (this.#packageName) {
52
- result.push("-p", this.#packageName);
53
- }
129
+ if (intent.extras) {
130
+ for (const [key, value] of Object.entries(intent.extras)) {
131
+ switch (typeof value) {
132
+ case "string":
133
+ result.push("--es", key, value);
134
+ break;
135
+ case "object":
136
+ if (value === null) {
137
+ result.push("--esn", key);
138
+ break;
139
+ }
54
140
 
55
- if (this.#component) {
56
- result.push("-n", this.#component);
57
- }
141
+ // `ComponentName`
142
+ if ("packageName" in value) {
143
+ result.push(
144
+ "--ecn",
145
+ key,
146
+ value.packageName + "/" + value.className,
147
+ );
148
+ break;
149
+ }
58
150
 
59
- if (this.#data) {
60
- result.push("-d", this.#data);
151
+ switch (value.type) {
152
+ case "uri":
153
+ result.push("--eu", key, value.value);
154
+ break;
155
+ case "array":
156
+ case "arrayList":
157
+ {
158
+ const [type, valueString] =
159
+ serializeExtraArray(value);
160
+ result.push(type, key, valueString);
161
+ }
162
+ break;
163
+ default:
164
+ result.push(
165
+ getNumberType(value.type),
166
+ key,
167
+ value.value.toString(),
168
+ );
169
+ break;
170
+ }
171
+ break;
172
+ case "number":
173
+ if (value % 1 !== 0) {
174
+ throw new Error(
175
+ `Extra \`${key}\` is not an integer, must use \`Intent.Extra.Number\` type instead`,
176
+ );
177
+ }
178
+ // Infer type from value
179
+ if (value < -2147483648 || value > 2147483647) {
180
+ result.push("--el", key, value.toString());
181
+ } else {
182
+ result.push("--ei", key, value.toString());
183
+ }
184
+ break;
185
+ case "bigint":
186
+ result.push("--el", key, value.toString());
187
+ break;
188
+ case "boolean":
189
+ result.push("--ez", key, value ? "true" : "false");
190
+ break;
191
+ }
61
192
  }
193
+ }
62
194
 
63
- if (this.#type) {
64
- result.push("-t", this.#type);
65
- }
195
+ if (intent.component) {
196
+ result.push(
197
+ "-n",
198
+ intent.component.packageName + "/" + intent.component.className,
199
+ );
200
+ }
66
201
 
67
- for (const [key, value] of this.#stringExtras) {
68
- result.push("--es", key, value);
69
- }
202
+ serializeString(result, "-p", intent.package);
70
203
 
71
- return result;
204
+ // `0` is the default value for `flags` when deserializing
205
+ // so it can be omitted if it's either `undefined` or `0`
206
+ if (intent.flags) {
207
+ result.push("-f", intent.flags.toString());
72
208
  }
209
+
210
+ return result;
73
211
  }
package/src/logcat.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  // cspell: ignore logcat
2
2
  // cspell: ignore usec
3
3
 
4
- import { AdbServiceBase } from "@yume-chan/adb";
4
+ import type { Adb } from "@yume-chan/adb";
5
5
  import type { ReadableStream } from "@yume-chan/stream-extra";
6
6
  import {
7
7
  BufferedTransformStream,
@@ -90,7 +90,7 @@ export interface LogcatFormatModifiers {
90
90
  export interface LogcatOptions {
91
91
  dump?: boolean | undefined;
92
92
  pid?: number | undefined;
93
- ids?: LogId[] | undefined;
93
+ ids?: readonly LogId[] | undefined;
94
94
  tail?: number | Date | undefined;
95
95
  }
96
96
 
@@ -405,7 +405,7 @@ export interface LogSize {
405
405
  maxPayloadSize: number;
406
406
  }
407
407
 
408
- export class Logcat extends AdbServiceBase {
408
+ export class Logcat {
409
409
  static logIdToName(id: LogId): string {
410
410
  return LogIdName[id]!;
411
411
  }
@@ -415,7 +415,7 @@ export class Logcat extends AdbServiceBase {
415
415
  return LogId[key as keyof typeof LogId];
416
416
  }
417
417
 
418
- static joinLogId(ids: LogId[]): string {
418
+ static joinLogId(ids: readonly LogId[]): string {
419
419
  return ids.map((id) => Logcat.logIdToName(id)).join(",");
420
420
  }
421
421
 
@@ -434,8 +434,14 @@ export class Logcat extends AdbServiceBase {
434
434
  static readonly LOG_SIZE_REGEX_11: RegExp =
435
435
  /(.*): ring buffer is (.*) (.*)B \((.*) (.*)B consumed, (.*) (.*)B readable\), max entry is (.*) B, max payload is (.*) B/;
436
436
 
437
- async getLogSize(ids?: LogId[]): Promise<LogSize[]> {
438
- const process = await this.adb.subprocess.noneProtocol.spawn([
437
+ readonly #adb: Adb;
438
+
439
+ constructor(adb: Adb) {
440
+ this.#adb = adb;
441
+ }
442
+
443
+ async getLogSize(ids?: readonly LogId[]): Promise<LogSize[]> {
444
+ const process = await this.#adb.subprocess.noneProtocol.spawn([
439
445
  "logcat",
440
446
  "-g",
441
447
  ...(ids ? ["-b", Logcat.joinLogId(ids)] : []),
@@ -444,7 +450,7 @@ export class Logcat extends AdbServiceBase {
444
450
  const result: LogSize[] = [];
445
451
  for await (const line of process.output
446
452
  .pipeThrough(new TextDecoderStream())
447
- .pipeThrough(new SplitStringStream("\n"))) {
453
+ .pipeThrough(new SplitStringStream("\n", { trim: true }))) {
448
454
  let match = line.match(Logcat.LOG_SIZE_REGEX_11);
449
455
  if (match) {
450
456
  result.push({
@@ -488,13 +494,13 @@ export class Logcat extends AdbServiceBase {
488
494
  return result;
489
495
  }
490
496
 
491
- async clear(ids?: LogId[]): Promise<void> {
497
+ async clear(ids?: readonly LogId[]): Promise<void> {
492
498
  const args = ["logcat", "-c"];
493
499
  if (ids && ids.length > 0) {
494
500
  args.push("-b", Logcat.joinLogId(ids));
495
501
  }
496
502
 
497
- await this.adb.subprocess.noneProtocol.spawnWaitText(args);
503
+ await this.#adb.subprocess.noneProtocol.spawn(args).wait();
498
504
  }
499
505
 
500
506
  binary(options?: LogcatOptions): ReadableStream<AndroidLogEntry> {
@@ -520,7 +526,7 @@ export class Logcat extends AdbServiceBase {
520
526
 
521
527
  // TODO: make `spawn` return synchronously with streams pending
522
528
  // so it's easier to chain them.
523
- const process = await this.adb.subprocess.noneProtocol.spawn(args);
529
+ const process = await this.#adb.subprocess.noneProtocol.spawn(args);
524
530
  return process.output;
525
531
  }).pipeThrough(
526
532
  new BufferedTransformStream((stream) => {