@yume-chan/android-bin 0.0.23 → 1.0.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 (56) hide show
  1. package/CHANGELOG.md +40 -2
  2. package/LICENSE +1 -1
  3. package/README.md +5 -2
  4. package/esm/am.d.ts.map +1 -1
  5. package/esm/am.js +2 -2
  6. package/esm/am.js.map +1 -1
  7. package/esm/bu.d.ts +2 -2
  8. package/esm/bu.d.ts.map +1 -1
  9. package/esm/bu.js +2 -2
  10. package/esm/bu.js.map +1 -1
  11. package/esm/bug-report.d.ts.map +1 -1
  12. package/esm/bug-report.js +27 -29
  13. package/esm/bug-report.js.map +1 -1
  14. package/esm/cmd.d.ts +12 -0
  15. package/esm/cmd.d.ts.map +1 -1
  16. package/esm/cmd.js +15 -3
  17. package/esm/cmd.js.map +1 -1
  18. package/esm/dumpsys.d.ts +55 -26
  19. package/esm/dumpsys.d.ts.map +1 -1
  20. package/esm/dumpsys.js +66 -69
  21. package/esm/dumpsys.js.map +1 -1
  22. package/esm/intent.d.ts +1 -0
  23. package/esm/intent.d.ts.map +1 -1
  24. package/esm/intent.js +8 -0
  25. package/esm/intent.js.map +1 -1
  26. package/esm/logcat.d.ts +59 -46
  27. package/esm/logcat.d.ts.map +1 -1
  28. package/esm/logcat.js +82 -81
  29. package/esm/logcat.js.map +1 -1
  30. package/esm/overlay-display.d.ts.map +1 -1
  31. package/esm/overlay-display.js +1 -1
  32. package/esm/overlay-display.js.map +1 -1
  33. package/esm/pm.d.ts +5 -5
  34. package/esm/pm.d.ts.map +1 -1
  35. package/esm/pm.js +51 -28
  36. package/esm/pm.js.map +1 -1
  37. package/esm/settings.d.ts.map +1 -1
  38. package/esm/string-format.d.ts +9 -6
  39. package/esm/string-format.d.ts.map +1 -1
  40. package/esm/string-format.js +3 -4
  41. package/esm/string-format.js.map +1 -1
  42. package/package.json +12 -16
  43. package/src/am.ts +5 -3
  44. package/src/bu.ts +4 -4
  45. package/src/bug-report.ts +40 -44
  46. package/src/cmd.ts +19 -7
  47. package/src/dumpsys.ts +100 -66
  48. package/src/intent.ts +10 -0
  49. package/src/logcat.ts +117 -105
  50. package/src/overlay-display.ts +2 -2
  51. package/src/pm.ts +81 -52
  52. package/src/settings.ts +1 -1
  53. package/src/string-format.ts +3 -5
  54. package/tsconfig.build.json +1 -1
  55. package/tsconfig.build.tsbuildinfo +1 -1
  56. package/CHANGELOG.json +0 -175
package/src/bug-report.ts CHANGED
@@ -6,9 +6,9 @@ import { AdbCommandBase, AdbSubprocessShellProtocol } from "@yume-chan/adb";
6
6
  import type { AbortSignal, ReadableStream } from "@yume-chan/stream-extra";
7
7
  import {
8
8
  AbortController,
9
- DecodeUtf8Stream,
10
9
  PushReadableStream,
11
10
  SplitStringStream,
11
+ TextDecoderStream,
12
12
  WrapReadableStream,
13
13
  WritableStream,
14
14
  } from "@yume-chan/stream-extra";
@@ -32,15 +32,15 @@ export interface BugReportZOptions {
32
32
  }
33
33
 
34
34
  export class BugReport extends AdbCommandBase {
35
- static VERSION_REGEX = /(\d+)\.(\d+)/;
35
+ static VERSION_REGEX: RegExp = /(\d+)\.(\d+)/;
36
36
 
37
- static BEGIN_REGEX = /BEGIN:(.*)/;
37
+ static BEGIN_REGEX: RegExp = /BEGIN:(.*)/;
38
38
 
39
- static PROGRESS_REGEX = /PROGRESS:(.*)\/(.*)/;
39
+ static PROGRESS_REGEX: RegExp = /PROGRESS:(.*)\/(.*)/;
40
40
 
41
- static OK_REGEX = /OK:(.*)/;
41
+ static OK_REGEX: RegExp = /OK:(.*)/;
42
42
 
43
- static FAIL_REGEX = /FAIL:(.*)/;
43
+ static FAIL_REGEX: RegExp = /FAIL:(.*)/;
44
44
 
45
45
  /**
46
46
  * Queries the device's bugreport capabilities.
@@ -101,7 +101,7 @@ export class BugReport extends AdbCommandBase {
101
101
  *
102
102
  * Should be `true` for Android version <= 11.
103
103
  */
104
- get supportsBugReport() {
104
+ get supportsBugReport(): boolean {
105
105
  return this.#supportsBugReport;
106
106
  }
107
107
 
@@ -111,7 +111,7 @@ export class BugReport extends AdbCommandBase {
111
111
  *
112
112
  * Will be `undefined` if BugReportZ is not supported.
113
113
  */
114
- get bugReportZVersion() {
114
+ get bugReportZVersion(): string | undefined {
115
115
  return this.#bugReportZVersion;
116
116
  }
117
117
 
@@ -121,7 +121,7 @@ export class BugReport extends AdbCommandBase {
121
121
  *
122
122
  * Should be `true` for Android version >= 7.
123
123
  */
124
- get supportsBugReportZ() {
124
+ get supportsBugReportZ(): boolean {
125
125
  return this.#supportsBugReportZ;
126
126
  }
127
127
 
@@ -131,7 +131,7 @@ export class BugReport extends AdbCommandBase {
131
131
  *
132
132
  * Should be `true` for Android version >= 8.
133
133
  */
134
- get supportsBugReportZProgress() {
134
+ get supportsBugReportZProgress(): boolean {
135
135
  return this.#supportsBugReportZProgress;
136
136
  }
137
137
 
@@ -141,7 +141,7 @@ export class BugReport extends AdbCommandBase {
141
141
  *
142
142
  * Should be `true` for Android version >= 12.
143
143
  */
144
- get supportsBugReportZStream() {
144
+ get supportsBugReportZStream(): boolean {
145
145
  return this.#supportsBugReportZStream;
146
146
  }
147
147
 
@@ -185,7 +185,7 @@ export class BugReport extends AdbCommandBase {
185
185
  */
186
186
  async bugReportZ(options?: BugReportZOptions): Promise<string> {
187
187
  if (options?.signal?.aborted) {
188
- throw options?.signal.reason ?? new Error("Aborted");
188
+ throw options?.signal.reason as Error;
189
189
  }
190
190
 
191
191
  if (!this.#supportsBugReportZ) {
@@ -211,37 +211,33 @@ export class BugReport extends AdbCommandBase {
211
211
  let filename: string | undefined;
212
212
  let error: string | undefined;
213
213
 
214
- await process.stdout
215
- .pipeThrough(new DecodeUtf8Stream())
216
- .pipeThrough(new SplitStringStream("\n"))
217
- .pipeTo(
218
- new WritableStream<string>({
219
- write(line) {
220
- // `BEGIN:` and `PROGRESS:` only appear when `-p` is specified.
221
- let match = line.match(BugReport.PROGRESS_REGEX);
222
- if (match) {
223
- options?.onProgress?.(match[1]!, match[2]!);
224
- }
225
-
226
- match = line.match(BugReport.BEGIN_REGEX);
227
- if (match) {
228
- filename = match[1]!;
229
- }
230
-
231
- match = line.match(BugReport.OK_REGEX);
232
- if (match) {
233
- filename = match[1];
234
- }
235
-
236
- match = line.match(BugReport.FAIL_REGEX);
237
- if (match) {
238
- // Don't report error now
239
- // We want to gather all output.
240
- error = match[1];
241
- }
242
- },
243
- }),
244
- );
214
+ for await (const line of process.stdout
215
+ .pipeThrough(new TextDecoderStream())
216
+ // Each chunk should contain one or several full lines
217
+ .pipeThrough(new SplitStringStream("\n"))) {
218
+ // `BEGIN:` and `PROGRESS:` only appear when `-p` is specified.
219
+ let match = line.match(BugReport.PROGRESS_REGEX);
220
+ if (match) {
221
+ options?.onProgress?.(match[1]!, match[2]!);
222
+ }
223
+
224
+ match = line.match(BugReport.BEGIN_REGEX);
225
+ if (match) {
226
+ filename = match[1]!;
227
+ }
228
+
229
+ match = line.match(BugReport.OK_REGEX);
230
+ if (match) {
231
+ filename = match[1];
232
+ }
233
+
234
+ match = line.match(BugReport.FAIL_REGEX);
235
+ if (match) {
236
+ // Don't report error now
237
+ // We want to gather all output.
238
+ error = match[1];
239
+ }
240
+ }
245
241
 
246
242
  if (error) {
247
243
  throw new Error(error);
@@ -278,7 +274,7 @@ export class BugReport extends AdbCommandBase {
278
274
  controller.error(e);
279
275
  });
280
276
  process.stderr
281
- .pipeThrough(new DecodeUtf8Stream())
277
+ .pipeThrough(new TextDecoderStream())
282
278
  .pipeTo(
283
279
  new WritableStream({
284
280
  write(chunk) {
package/src/cmd.ts CHANGED
@@ -10,26 +10,26 @@ import {
10
10
  AdbSubprocessNoneProtocol,
11
11
  AdbSubprocessShellProtocol,
12
12
  } from "@yume-chan/adb";
13
- import { ConcatStringStream, DecodeUtf8Stream } from "@yume-chan/stream-extra";
13
+ import { ConcatStringStream, TextDecoderStream } from "@yume-chan/stream-extra";
14
14
 
15
15
  export class Cmd extends AdbCommandBase {
16
16
  #supportsShellV2: boolean;
17
- get supportsShellV2() {
17
+ get supportsShellV2(): boolean {
18
18
  return this.#supportsShellV2;
19
19
  }
20
20
 
21
21
  #supportsCmd: boolean;
22
- get supportsCmd() {
22
+ get supportsCmd(): boolean {
23
23
  return this.#supportsCmd;
24
24
  }
25
25
 
26
26
  #supportsAbb: boolean;
27
- get supportsAbb() {
27
+ get supportsAbb(): boolean {
28
28
  return this.#supportsAbb;
29
29
  }
30
30
 
31
31
  #supportsAbbExec: boolean;
32
- get supportsAbbExec() {
32
+ get supportsAbbExec(): boolean {
33
33
  return this.#supportsAbbExec;
34
34
  }
35
35
 
@@ -41,6 +41,18 @@ export class Cmd extends AdbCommandBase {
41
41
  this.#supportsAbbExec = adb.canUseFeature(AdbFeature.AbbExec);
42
42
  }
43
43
 
44
+ /**
45
+ * Spawn a new `cmd` command. It will use ADB's `abb` command if available.
46
+ *
47
+ * @param shellProtocol
48
+ * Whether to use shell protocol. If `true`, `stdout` and `stderr` will be separated.
49
+ *
50
+ * `cmd` doesn't use PTY, so even when shell protocol is used,
51
+ * resizing terminal size and closing `stdin` are not supported.
52
+ * @param command The command to run.
53
+ * @param args The arguments to pass to the command.
54
+ * @returns An `AdbSubprocessProtocol` that provides output streams.
55
+ */
44
56
  async spawn(
45
57
  shellProtocol: boolean,
46
58
  command: string,
@@ -84,10 +96,10 @@ export class Cmd extends AdbCommandBase {
84
96
 
85
97
  const [stdout, stderr, exitCode] = await Promise.all([
86
98
  process.stdout
87
- .pipeThrough(new DecodeUtf8Stream())
99
+ .pipeThrough(new TextDecoderStream())
88
100
  .pipeThrough(new ConcatStringStream()),
89
101
  process.stderr
90
- .pipeThrough(new DecodeUtf8Stream())
102
+ .pipeThrough(new TextDecoderStream())
91
103
  .pipeThrough(new ConcatStringStream()),
92
104
  process.exit,
93
105
  ]);
package/src/dumpsys.ts CHANGED
@@ -1,6 +1,62 @@
1
1
  import { AdbCommandBase } from "@yume-chan/adb";
2
2
 
3
+ const BatteryDumpFields: Record<
4
+ string,
5
+ {
6
+ type: "number" | "boolean" | "string";
7
+ field: keyof DumpSys.Battery.Info;
8
+ }
9
+ > = {
10
+ "AC powered": { type: "boolean", field: "acPowered" },
11
+ "USB powered": { type: "boolean", field: "usbPowered" },
12
+ "Wireless powered": { type: "boolean", field: "wirelessPowered" },
13
+ "Dock powered": { type: "boolean", field: "dockPowered" },
14
+ "Max charging current": {
15
+ type: "number",
16
+ field: "maxChargingCurrent",
17
+ },
18
+ "Max charging voltage": {
19
+ type: "number",
20
+ field: "maxChargingVoltage",
21
+ },
22
+ "Charge counter": { type: "number", field: "chargeCounter" },
23
+ status: { type: "number", field: "status" },
24
+ health: { type: "number", field: "health" },
25
+ present: { type: "boolean", field: "present" },
26
+ level: { type: "number", field: "level" },
27
+ scale: { type: "number", field: "scale" },
28
+ voltage: { type: "number", field: "voltage" },
29
+ temperature: { type: "number", field: "temperature" },
30
+ technology: { type: "string", field: "technology" },
31
+ current: { type: "number", field: "current" },
32
+ };
33
+
34
+ const Status = {
35
+ Unknown: 1,
36
+ Charging: 2,
37
+ Discharging: 3,
38
+ NotCharging: 4,
39
+ Full: 5,
40
+ } as const;
41
+
42
+ const Health = {
43
+ Unknown: 1,
44
+ Good: 2,
45
+ Overheat: 3,
46
+ Dead: 4,
47
+ OverVoltage: 5,
48
+ UnspecifiedFailure: 6,
49
+ Cold: 7,
50
+ } as const;
51
+
52
+ const Battery = {
53
+ Status,
54
+ Health,
55
+ };
56
+
3
57
  export class DumpSys extends AdbCommandBase {
58
+ static readonly Battery = Battery;
59
+
4
60
  async diskStats() {
5
61
  const output = await this.adb.subprocess.spawnAndWaitLegacy([
6
62
  "dumpsys",
@@ -34,96 +90,74 @@ export class DumpSys extends AdbCommandBase {
34
90
  };
35
91
  }
36
92
 
37
- async battery() {
93
+ async battery(): Promise<DumpSys.Battery.Info> {
38
94
  const output = await this.adb.subprocess.spawnAndWaitLegacy([
39
95
  "dumpsys",
40
96
  "battery",
41
97
  ]);
42
98
 
43
- let acPowered = false;
44
- let usbPowered = false;
45
- let wirelessPowered = false;
46
- let level: number | undefined;
47
- let scale: number | undefined;
48
- let voltage: number | undefined;
49
- let current: number | undefined;
50
- let status: DumpSys.Battery.Status | undefined;
51
- let health: DumpSys.Battery.Health | undefined;
99
+ const info: DumpSys.Battery.Info = {
100
+ acPowered: false,
101
+ usbPowered: false,
102
+ wirelessPowered: false,
103
+ dockPowered: false,
104
+ status: DumpSys.Battery.Status.Unknown,
105
+ health: DumpSys.Battery.Health.Unknown,
106
+ };
107
+
52
108
  for (const line of output.split("\n")) {
53
- const parts = line.split(":");
109
+ const parts = line.split(":").map((part) => part.trim());
54
110
  if (parts.length !== 2) {
55
111
  continue;
56
112
  }
57
113
 
58
- switch (parts[0]!.trim()) {
59
- case "AC powered":
60
- acPowered = parts[1]!.trim() === "true";
61
- break;
62
- case "USB powered":
63
- usbPowered = parts[1]!.trim() === "true";
64
- break;
65
- case "Wireless powered":
66
- wirelessPowered = parts[1]!.trim() === "true";
67
- break;
68
- case "level":
69
- level = Number.parseInt(parts[1]!.trim(), 10);
70
- break;
71
- case "scale":
72
- scale = Number.parseInt(parts[1]!.trim(), 10);
73
- break;
74
- case "voltage":
75
- voltage = Number.parseInt(parts[1]!.trim(), 10);
76
- break;
77
- case "current now":
78
- current = Number.parseInt(parts[1]!.trim(), 10);
114
+ const field = BatteryDumpFields[parts[0]!];
115
+ if (!field) {
116
+ continue;
117
+ }
118
+
119
+ switch (field.type) {
120
+ case "boolean":
121
+ info[field.field] = (parts[1]!.trim() === "true") as never;
79
122
  break;
80
- case "status":
81
- status = Number.parseInt(
123
+ case "number":
124
+ info[field.field] = Number.parseInt(
82
125
  parts[1]!.trim(),
83
126
  10,
84
- ) as DumpSys.Battery.Status;
127
+ ) as never;
85
128
  break;
86
- case "health":
87
- health = Number.parseInt(
88
- parts[1]!.trim(),
89
- 10,
90
- ) as DumpSys.Battery.Health;
129
+ case "string":
130
+ info[field.field] = parts[1]! as never;
91
131
  break;
92
132
  }
93
133
  }
94
134
 
95
- return {
96
- acPowered,
97
- usbPowered,
98
- wirelessPowered,
99
- level,
100
- scale,
101
- voltage,
102
- current,
103
- status,
104
- health,
105
- };
135
+ return info;
106
136
  }
107
137
  }
108
138
 
109
139
  export namespace DumpSys {
110
140
  export namespace Battery {
111
- export enum Status {
112
- Unknown = 1,
113
- Charging,
114
- Discharging,
115
- NotCharging,
116
- Full,
117
- }
141
+ export type Status = (typeof Status)[keyof typeof Status];
142
+ export type Health = (typeof Health)[keyof typeof Health];
118
143
 
119
- export enum Health {
120
- Unknown = 1,
121
- Good,
122
- Overheat,
123
- Dead,
124
- OverVoltage,
125
- UnspecifiedFailure,
126
- Cold,
144
+ export interface Info {
145
+ acPowered: boolean;
146
+ usbPowered: boolean;
147
+ wirelessPowered: boolean;
148
+ dockPowered: boolean;
149
+ maxChargingCurrent?: number;
150
+ maxChargingVoltage?: number;
151
+ chargeCounter?: number;
152
+ status: Status;
153
+ health: Health;
154
+ present?: boolean;
155
+ level?: number;
156
+ scale?: number;
157
+ voltage?: number;
158
+ temperature?: number;
159
+ technology?: string;
160
+ current?: number;
127
161
  }
128
162
  }
129
163
  }
package/src/intent.ts CHANGED
@@ -5,6 +5,7 @@ export class IntentBuilder {
5
5
  #component: string | undefined;
6
6
  #data: string | undefined;
7
7
  #type: string | undefined;
8
+ #stringExtras = new Map<string, string>();
8
9
 
9
10
  setAction(action: string): this {
10
11
  this.#action = action;
@@ -31,6 +32,11 @@ export class IntentBuilder {
31
32
  return this;
32
33
  }
33
34
 
35
+ addStringExtra(key: string, value: string): this {
36
+ this.#stringExtras.set(key, value);
37
+ return this;
38
+ }
39
+
34
40
  build(): string[] {
35
41
  const result: string[] = [];
36
42
 
@@ -58,6 +64,10 @@ export class IntentBuilder {
58
64
  result.push("-t", this.#type);
59
65
  }
60
66
 
67
+ for (const [key, value] of this.#stringExtras) {
68
+ result.push("--es", key, value);
69
+ }
70
+
61
71
  return result;
62
72
  }
63
73
  }