mirror of
https://github.com/yume-chan/ya-webadb.git
synced 2025-10-03 01:39:21 +02:00
feat(bin): use cmd
in settings
This commit is contained in:
parent
9b0e06cdfb
commit
e3bfd1592f
8 changed files with 1490 additions and 1495 deletions
|
@ -33,12 +33,14 @@
|
|||
"dependencies": {
|
||||
"@yume-chan/adb": "workspace:^0.0.20",
|
||||
"@yume-chan/adb-server-node-tcp": "workspace:^0.0.19",
|
||||
"@yume-chan/android-bin": "workspace:^0.0.20",
|
||||
"@yume-chan/stream-extra": "workspace:^0.0.20",
|
||||
"commander": "^10.0.1",
|
||||
"source-map-support": "^0.5.21",
|
||||
"tslib": "^2.5.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^20.2.1",
|
||||
"@yume-chan/eslint-config": "workspace:^1.0.0",
|
||||
"@yume-chan/tsconfig": "workspace:^1.0.0",
|
||||
"eslint": "^8.41.0",
|
||||
|
|
2751
common/config/rush/pnpm-lock.yaml
generated
2751
common/config/rush/pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load diff
|
@ -1,5 +1,5 @@
|
|||
// DO NOT MODIFY THIS FILE MANUALLY BUT DO COMMIT IT. It is generated and used by Rush.
|
||||
{
|
||||
"pnpmShrinkwrapHash": "44a16b54cd6e6ab0bca0baf63df4de9d614e3857",
|
||||
"pnpmShrinkwrapHash": "749c0b292fb7bef0d2e3e177d6dc093da3453d0c",
|
||||
"preferredVersionsHash": "bf21a9e8fbc5a3846fb05b4fa0859e0917b2202f"
|
||||
}
|
||||
|
|
|
@ -108,15 +108,15 @@ export class AdbSubprocess extends AdbCommandBase {
|
|||
command: string | string[],
|
||||
options?: Partial<AdbSubprocessOptions>
|
||||
): Promise<AdbSubprocessWaitResult> {
|
||||
const shell = await this.spawn(command, options);
|
||||
const process = await this.spawn(command, options);
|
||||
|
||||
const stdout = new GatherStringStream();
|
||||
const stderr = new GatherStringStream();
|
||||
|
||||
const [, , exitCode] = await Promise.all([
|
||||
shell.stdout.pipeThrough(new DecodeUtf8Stream()).pipeTo(stdout),
|
||||
shell.stderr.pipeThrough(new DecodeUtf8Stream()).pipeTo(stderr),
|
||||
shell.exit,
|
||||
process.stdout.pipeThrough(new DecodeUtf8Stream()).pipeTo(stdout),
|
||||
process.stderr.pipeThrough(new DecodeUtf8Stream()).pipeTo(stderr),
|
||||
process.exit,
|
||||
]);
|
||||
|
||||
return {
|
||||
|
|
|
@ -1,67 +1,100 @@
|
|||
import type { Adb, AdbSubprocessProtocolConstructor } from "@yume-chan/adb";
|
||||
import type {
|
||||
Adb,
|
||||
AdbSubprocessProtocol,
|
||||
AdbSubprocessProtocolConstructor,
|
||||
AdbSubprocessWaitResult,
|
||||
} from "@yume-chan/adb";
|
||||
import {
|
||||
AdbCommandBase,
|
||||
AdbFeature,
|
||||
AdbSubprocessNoneProtocol,
|
||||
AdbSubprocessShellProtocol,
|
||||
} from "@yume-chan/adb";
|
||||
import { DecodeUtf8Stream, GatherStringStream } from "@yume-chan/stream-extra";
|
||||
|
||||
export class Cmd extends AdbCommandBase {
|
||||
private _supportsShellV2: boolean;
|
||||
private _supportsCmd: boolean;
|
||||
private _supportsAbb: boolean;
|
||||
private _supportsAbbExec: boolean;
|
||||
|
||||
#supportsShellV2: boolean;
|
||||
public get supportsShellV2() {
|
||||
return this._supportsShellV2;
|
||||
return this.#supportsShellV2;
|
||||
}
|
||||
|
||||
#supportsCmd: boolean;
|
||||
public get supportsCmd() {
|
||||
return this._supportsCmd;
|
||||
return this.#supportsCmd;
|
||||
}
|
||||
|
||||
#supportsAbb: boolean;
|
||||
public get supportsAbb() {
|
||||
return this._supportsAbb;
|
||||
return this.#supportsAbb;
|
||||
}
|
||||
|
||||
#supportsAbbExec: boolean;
|
||||
public get supportsAbbExec() {
|
||||
return this._supportsAbbExec;
|
||||
return this.#supportsAbbExec;
|
||||
}
|
||||
|
||||
public constructor(adb: Adb) {
|
||||
super(adb);
|
||||
this._supportsShellV2 = adb.supportsFeature(AdbFeature.ShellV2);
|
||||
this._supportsCmd = adb.supportsFeature(AdbFeature.Cmd);
|
||||
this._supportsAbb = adb.supportsFeature(AdbFeature.Abb);
|
||||
this._supportsAbbExec = adb.supportsFeature(AdbFeature.AbbExec);
|
||||
this.#supportsShellV2 = adb.supportsFeature(AdbFeature.ShellV2);
|
||||
this.#supportsCmd = adb.supportsFeature(AdbFeature.Cmd);
|
||||
this.#supportsAbb = adb.supportsFeature(AdbFeature.Abb);
|
||||
this.#supportsAbbExec = adb.supportsFeature(AdbFeature.AbbExec);
|
||||
}
|
||||
|
||||
public async spawn(
|
||||
shellProtocol: boolean,
|
||||
command: string,
|
||||
...args: string[]
|
||||
) {
|
||||
): Promise<AdbSubprocessProtocol> {
|
||||
let supportsAbb: boolean;
|
||||
let supportsCmd: boolean = this.supportsCmd;
|
||||
let supportsCmd: boolean = this.#supportsCmd;
|
||||
let service: string;
|
||||
let Protocol: AdbSubprocessProtocolConstructor;
|
||||
if (shellProtocol) {
|
||||
supportsAbb = this._supportsAbb;
|
||||
supportsAbb = this.#supportsAbb;
|
||||
supportsCmd &&= this.supportsShellV2;
|
||||
service = "abb";
|
||||
Protocol = AdbSubprocessShellProtocol;
|
||||
} else {
|
||||
supportsAbb = this._supportsAbbExec;
|
||||
supportsAbb = this.#supportsAbbExec;
|
||||
service = "abb_exec";
|
||||
Protocol = AdbSubprocessNoneProtocol;
|
||||
}
|
||||
|
||||
if (supportsAbb) {
|
||||
const socket = await this.adb.createSocket(
|
||||
`${service}:${command}\0${args.join("\0")}\0`
|
||||
return new Protocol(
|
||||
await this.adb.createSocket(
|
||||
`${service}:${command}\0${args.join("\0")}\0`
|
||||
)
|
||||
);
|
||||
return new Protocol(socket);
|
||||
} else if (supportsCmd) {
|
||||
return Protocol.raw(this.adb, `cmd ${command} ${args.join(" ")}`);
|
||||
} else {
|
||||
throw new Error("Not supported");
|
||||
}
|
||||
|
||||
if (supportsCmd) {
|
||||
return Protocol.raw(this.adb, `cmd ${command} ${args.join(" ")}`);
|
||||
}
|
||||
|
||||
throw new Error("Not supported");
|
||||
}
|
||||
|
||||
public async spawnAndWait(
|
||||
command: string,
|
||||
...args: string[]
|
||||
): Promise<AdbSubprocessWaitResult> {
|
||||
const process = await this.spawn(true, command, ...args);
|
||||
|
||||
const stdout = new GatherStringStream();
|
||||
const stderr = new GatherStringStream();
|
||||
|
||||
const [, , exitCode] = await Promise.all([
|
||||
process.stdout.pipeThrough(new DecodeUtf8Stream()).pipeTo(stdout),
|
||||
process.stderr.pipeThrough(new DecodeUtf8Stream()).pipeTo(stderr),
|
||||
process.exit,
|
||||
]);
|
||||
|
||||
return {
|
||||
stdout: stdout.result,
|
||||
stderr: stderr.result,
|
||||
exitCode,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -71,7 +71,7 @@ export class DemoMode extends AdbCommandBase {
|
|||
"global",
|
||||
DemoMode.AllowedSettingKey
|
||||
);
|
||||
return output.trim() === "1";
|
||||
return output === "1";
|
||||
}
|
||||
|
||||
public async setAllowed(value: boolean): Promise<void> {
|
||||
|
@ -88,7 +88,7 @@ export class DemoMode extends AdbCommandBase {
|
|||
"global",
|
||||
DemoMode.EnabledSettingKey
|
||||
);
|
||||
return result.trim() === "1";
|
||||
return result === "1";
|
||||
}
|
||||
|
||||
public async setEnabled(value: boolean): Promise<void> {
|
||||
|
|
|
@ -4,5 +4,6 @@ export * from "./bug-report.js";
|
|||
export * from "./cmd.js";
|
||||
export * from "./demo-mode.js";
|
||||
export * from "./logcat.js";
|
||||
export * from "./overlay-display.js";
|
||||
export * from "./pm.js";
|
||||
export * from "./settings.js";
|
||||
|
|
|
@ -1,77 +1,127 @@
|
|||
import type { Adb, AdbSubprocessWaitResult } from "@yume-chan/adb";
|
||||
import { AdbCommandBase } from "@yume-chan/adb";
|
||||
|
||||
import { Cmd } from "./cmd.js";
|
||||
|
||||
export type SettingsNamespace = "system" | "secure" | "global";
|
||||
|
||||
export type SettingsResetMode =
|
||||
| "untrusted_defaults"
|
||||
| "untrusted_clear"
|
||||
| "trusted_defaults";
|
||||
export enum SettingsResetMode {
|
||||
UntrustedDefaults = "untrusted_defaults",
|
||||
UntrustedClear = "untrusted_clear",
|
||||
TrustedDefaults = "trusted_defaults",
|
||||
}
|
||||
|
||||
export interface SettingsOptions {
|
||||
user?: number | "current";
|
||||
}
|
||||
|
||||
export interface SettingsPutOptions extends SettingsOptions {
|
||||
tag?: string;
|
||||
makeDefault?: boolean;
|
||||
}
|
||||
|
||||
// frameworks/base/packages/SettingsProvider/src/com/android/providers/settings/SettingsService.java
|
||||
export class Settings extends AdbCommandBase {
|
||||
// TODO: `--user <user>` argument
|
||||
#cmd: Cmd;
|
||||
|
||||
public base(
|
||||
command: string,
|
||||
public constructor(adb: Adb) {
|
||||
super(adb);
|
||||
this.#cmd = new Cmd(adb);
|
||||
}
|
||||
|
||||
public async base(
|
||||
verb: string,
|
||||
namespace: SettingsNamespace,
|
||||
options: SettingsOptions | undefined,
|
||||
...args: string[]
|
||||
): Promise<string> {
|
||||
let command = ["settings"];
|
||||
|
||||
if (options?.user !== undefined) {
|
||||
command.push("--user", options.user.toString());
|
||||
}
|
||||
|
||||
command.push(verb, namespace);
|
||||
command = command.concat(args);
|
||||
|
||||
let output: AdbSubprocessWaitResult;
|
||||
if (this.#cmd.supportsCmd) {
|
||||
output = await this.#cmd.spawnAndWait(
|
||||
command[0]!,
|
||||
...command.slice(1)
|
||||
);
|
||||
} else {
|
||||
output = await this.adb.subprocess.spawnAndWait(command);
|
||||
}
|
||||
|
||||
if (output.stderr) {
|
||||
throw new Error(output.stderr);
|
||||
}
|
||||
|
||||
return output.stdout;
|
||||
}
|
||||
|
||||
public async get(
|
||||
namespace: SettingsNamespace,
|
||||
key: string,
|
||||
options?: SettingsOptions
|
||||
) {
|
||||
return this.adb.subprocess.spawnAndWaitLegacy([
|
||||
"settings",
|
||||
command,
|
||||
namespace,
|
||||
...args,
|
||||
]);
|
||||
const output = await this.base("get", namespace, options, key);
|
||||
// Remove last \n
|
||||
return output.substring(0, output.length - 1);
|
||||
}
|
||||
|
||||
public get(namespace: SettingsNamespace, key: string) {
|
||||
return this.base("get", namespace, key);
|
||||
public async delete(
|
||||
namespace: SettingsNamespace,
|
||||
key: string,
|
||||
options?: SettingsOptions
|
||||
): Promise<void> {
|
||||
await this.base("delete", namespace, options, key);
|
||||
}
|
||||
|
||||
public delete(namespace: SettingsNamespace, key: string) {
|
||||
return this.base("delete", namespace, key);
|
||||
}
|
||||
|
||||
public put(
|
||||
public async put(
|
||||
namespace: SettingsNamespace,
|
||||
key: string,
|
||||
value: string,
|
||||
tag?: string,
|
||||
makeDefault?: boolean
|
||||
) {
|
||||
options?: SettingsPutOptions
|
||||
): Promise<void> {
|
||||
const args = [key, value];
|
||||
if (tag) {
|
||||
args.push(tag);
|
||||
if (options?.tag) {
|
||||
args.push(options.tag);
|
||||
}
|
||||
if (makeDefault) {
|
||||
if (options?.makeDefault) {
|
||||
args.push("default");
|
||||
}
|
||||
return this.base("put", namespace, ...args);
|
||||
await this.base("put", namespace, options, ...args);
|
||||
}
|
||||
|
||||
public reset(
|
||||
namespace: SettingsNamespace,
|
||||
mode: SettingsResetMode
|
||||
): Promise<string>;
|
||||
mode: SettingsResetMode,
|
||||
options?: SettingsOptions
|
||||
): Promise<void>;
|
||||
public reset(
|
||||
namespace: SettingsNamespace,
|
||||
packageName: string,
|
||||
tag?: string
|
||||
): Promise<string>;
|
||||
public reset(
|
||||
tag?: string,
|
||||
options?: SettingsOptions
|
||||
): Promise<void>;
|
||||
public async reset(
|
||||
namespace: SettingsNamespace,
|
||||
modeOrPackageName: string,
|
||||
tag?: string
|
||||
): Promise<string> {
|
||||
tagOrOptions?: string | SettingsOptions,
|
||||
options?: SettingsOptions
|
||||
): Promise<void> {
|
||||
const args = [modeOrPackageName];
|
||||
if (tag) {
|
||||
args.push(tag);
|
||||
if (
|
||||
modeOrPackageName === SettingsResetMode.UntrustedDefaults ||
|
||||
modeOrPackageName === SettingsResetMode.UntrustedClear ||
|
||||
modeOrPackageName === SettingsResetMode.TrustedDefaults
|
||||
) {
|
||||
options = tagOrOptions as SettingsOptions;
|
||||
} else if (typeof tagOrOptions === "string") {
|
||||
args.push(tagOrOptions);
|
||||
}
|
||||
return this.base("reset", namespace, ...args);
|
||||
}
|
||||
|
||||
public async list(namespace: SettingsNamespace): Promise<string[]> {
|
||||
const output = await this.base("list", namespace);
|
||||
return output.split("\n");
|
||||
await this.base("reset", namespace, options, ...args);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue