refactor(bin): move demo mode to new package

This commit is contained in:
Simon Chan 2022-02-09 18:32:56 +08:00
parent daf726f2e0
commit 41a9565eeb
18 changed files with 229 additions and 77 deletions

View file

@ -1,26 +1,26 @@
import { Dropdown, IDropdownOption, Position, Separator, SpinButton, Toggle } from '@fluentui/react';
import { AdbDemoModeMobileDataType, AdbDemoModeMobileDataTypes, AdbDemoModeSignalStrength, AdbDemoModeStatusBarMode, AdbDemoModeStatusBarModes } from '@yume-chan/adb';
import { DemoMode, DemoModeMobileDataType, DemoModeMobileDataTypes, DemoModeSignalStrength, DemoModeStatusBarMode, DemoModeStatusBarModes } from '@yume-chan/android-bin';
import { autorun, makeAutoObservable, reaction, runInAction } from "mobx";
import { observer } from "mobx-react-lite";
import { CSSProperties, useCallback } from 'react';
import { globalState } from "../state";
const SignalStrengthOptions =
Object.values(AdbDemoModeSignalStrength)
Object.values(DemoModeSignalStrength)
.map((key) => ({
key,
text: {
[AdbDemoModeSignalStrength.Hidden]: 'Hidden',
[AdbDemoModeSignalStrength.Level0]: 'Level 0',
[AdbDemoModeSignalStrength.Level1]: 'Level 1',
[AdbDemoModeSignalStrength.Level2]: 'Level 2',
[AdbDemoModeSignalStrength.Level3]: 'Level 3',
[AdbDemoModeSignalStrength.Level4]: 'Level 4',
[DemoModeSignalStrength.Hidden]: 'Hidden',
[DemoModeSignalStrength.Level0]: 'Level 0',
[DemoModeSignalStrength.Level1]: 'Level 1',
[DemoModeSignalStrength.Level2]: 'Level 2',
[DemoModeSignalStrength.Level3]: 'Level 3',
[DemoModeSignalStrength.Level4]: 'Level 4',
}[key],
}));
const MobileDataTypeOptions =
AdbDemoModeMobileDataTypes
DemoModeMobileDataTypes
.map((key) => ({
key,
text: {
@ -47,7 +47,7 @@ const MobileDataTypeOptions =
}));
const StatusBarModeOptions =
AdbDemoModeStatusBarModes
DemoModeStatusBarModes
.map((key) => ({
key,
text: {
@ -59,7 +59,9 @@ const StatusBarModeOptions =
}[key],
}));
class DemoModeState {
class DemoModePanelState {
demoMode: DemoMode | undefined;
allowed = false;
enabled = false;
features: Map<string, unknown> = new Map();
@ -71,13 +73,15 @@ class DemoModeState {
() => globalState.device,
async (device) => {
if (device) {
const allowed = await device.demoMode.getAllowed();
runInAction(() => this.demoMode = new DemoMode(device));
const allowed = await this.demoMode!.getAllowed();
runInAction(() => this.allowed = allowed);
if (allowed) {
const enabled = await device.demoMode.getEnabled();
const enabled = await this.demoMode!.getEnabled();
runInAction(() => this.enabled = enabled);
}
} else {
this.demoMode = undefined;
this.allowed = false;
this.enabled = false;
this.features.clear();
@ -99,7 +103,7 @@ class DemoModeState {
}
}
const state = new DemoModeState();
const state = new DemoModePanelState();
interface FeatureDefinition {
key: string;
@ -123,21 +127,21 @@ const FEATURES: FeatureDefinition[][] = [
max: 100,
step: 1,
initial: 100,
onChange: (value) => globalState.device!.demoMode.setBatteryLevel(value as number),
onChange: (value) => state.demoMode!.setBatteryLevel(value as number),
},
{
key: 'batteryCharging',
label: 'Battery Charging',
type: 'boolean',
initial: false,
onChange: (value) => globalState.device!.demoMode.setBatteryCharging(value as boolean),
onChange: (value) => state.demoMode!.setBatteryCharging(value as boolean),
},
{
key: 'powerSaveMode',
label: 'Power Save Mode',
type: 'boolean',
initial: false,
onChange: (value) => globalState.device!.demoMode.setPowerSaveMode(value as boolean),
onChange: (value) => state.demoMode!.setPowerSaveMode(value as boolean),
},
],
[
@ -146,15 +150,15 @@ const FEATURES: FeatureDefinition[][] = [
label: 'Wifi Signal Strength',
type: 'select',
options: SignalStrengthOptions,
initial: AdbDemoModeSignalStrength.Level4,
onChange: (value) => globalState.device!.demoMode.setWifiSignalStrength(value as AdbDemoModeSignalStrength),
initial: DemoModeSignalStrength.Level4,
onChange: (value) => state.demoMode!.setWifiSignalStrength(value as DemoModeSignalStrength),
},
{
key: 'airplaneMode',
label: 'Airplane Mode',
type: 'boolean',
initial: false,
onChange: (value) => globalState.device!.demoMode.setAirplaneMode(value as boolean),
onChange: (value) => state.demoMode!.setAirplaneMode(value as boolean),
},
{
key: 'mobileDataType',
@ -162,15 +166,15 @@ const FEATURES: FeatureDefinition[][] = [
type: 'select',
options: MobileDataTypeOptions,
initial: 'lte',
onChange: (value) => globalState.device!.demoMode.setMobileDataType(value as AdbDemoModeMobileDataType),
onChange: (value) => state.demoMode!.setMobileDataType(value as DemoModeMobileDataType),
},
{
key: 'mobileSignalStrength',
label: 'Mobile Signal Strength',
type: 'select',
options: SignalStrengthOptions,
initial: AdbDemoModeSignalStrength.Level4,
onChange: (value) => globalState.device!.demoMode.setMobileSignalStrength(value as AdbDemoModeSignalStrength),
initial: DemoModeSignalStrength.Level4,
onChange: (value) => state.demoMode!.setMobileSignalStrength(value as DemoModeSignalStrength),
},
],
[
@ -180,42 +184,42 @@ const FEATURES: FeatureDefinition[][] = [
type: 'select',
options: StatusBarModeOptions,
initial: 'transparent',
onChange: (value) => globalState.device!.demoMode.setStatusBarMode(value as AdbDemoModeStatusBarMode),
onChange: (value) => state.demoMode!.setStatusBarMode(value as DemoModeStatusBarMode),
},
{
key: 'vibrateMode',
label: 'Vibrate Mode Indicator',
type: 'boolean',
initial: false,
onChange: (value) => globalState.device!.demoMode.setVibrateModeEnabled(value as boolean),
onChange: (value) => state.demoMode!.setVibrateModeEnabled(value as boolean),
},
{
key: 'bluetoothConnected',
label: 'Bluetooth Indicator',
type: 'boolean',
initial: false,
onChange: (value) => globalState.device!.demoMode.setBluetoothConnected(value as boolean),
onChange: (value) => state.demoMode!.setBluetoothConnected(value as boolean),
},
{
key: 'locatingIcon',
label: 'Locating Icon',
type: 'boolean',
initial: false,
onChange: (value) => globalState.device!.demoMode.setLocatingIcon(value as boolean),
onChange: (value) => state.demoMode!.setLocatingIcon(value as boolean),
},
{
key: 'alarmIcon',
label: 'Alarm Icon',
type: 'boolean',
initial: false,
onChange: (value) => globalState.device!.demoMode.setAlarmIcon(value as boolean),
onChange: (value) => state.demoMode!.setAlarmIcon(value as boolean),
},
{
key: 'notificationsVisibility',
label: 'Notifications Visibility',
type: 'boolean',
initial: true,
onChange: (value) => globalState.device!.demoMode.setNotificationsVisibility(value as boolean),
onChange: (value) => state.demoMode!.setNotificationsVisibility(value as boolean),
},
{
key: 'hour',
@ -225,7 +229,7 @@ const FEATURES: FeatureDefinition[][] = [
max: 23,
step: 1,
initial: 12,
onChange: (value) => globalState.device!.demoMode.setTime(value as number, state.features.get('minute') as number | undefined ?? 34)
onChange: (value) => state.demoMode!.setTime(value as number, state.features.get('minute') as number | undefined ?? 34)
},
{
key: 'minute',
@ -235,7 +239,7 @@ const FEATURES: FeatureDefinition[][] = [
max: 59,
step: 1,
initial: 34,
onChange: (value) => globalState.device!.demoMode.setTime(state.features.get('hour') as number | undefined ?? 34, value as number)
onChange: (value) => state.demoMode!.setTime(state.features.get('hour') as number | undefined ?? 34, value as number)
},
],
];
@ -301,15 +305,15 @@ const FeatureBase = ({ feature }: { feature: FeatureDefinition; }) => {
const Feature = observer(FeatureBase);
export interface DemoModeProps {
export interface DemoModePanelProps {
style?: CSSProperties;
}
const DemoModeBase = ({
export const DemoModePanel = observer(({
style,
}: DemoModeProps) => {
}: DemoModePanelProps) => {
const handleAllowedChange = useCallback(async (e, value?: boolean) => {
await globalState.device!.demoMode.setAllowed(value!);
await state.demoMode!.setAllowed(value!);
runInAction(() => {
state.allowed = value!;
state.enabled = false;
@ -317,7 +321,7 @@ const DemoModeBase = ({
}, []);
const handleEnabledChange = useCallback(async (e, value?: boolean) => {
await globalState.device!.demoMode.setEnabled(value!);
await state.demoMode!.setEnabled(value!);
runInAction(() => state.enabled = value!);
}, []);
@ -351,6 +355,4 @@ const DemoModeBase = ({
))}
</div>
);
};
export const DemoMode = observer(DemoModeBase);
});

View file

@ -1,6 +1,6 @@
export * from './command-bar';
export * from './connect';
export * from './demo-mode';
export * from './demo-mode-panel';
export * from './device-view';
export * from './error-dialog';
export * from './external-link';

View file

@ -20,6 +20,7 @@
"@yume-chan/adb-backend-webusb": "^0.0.10",
"@yume-chan/adb-backend-ws": "^0.0.9",
"@yume-chan/adb-credential-web": "^0.0.10",
"@yume-chan/android-bin": "^0.0.10",
"@yume-chan/async": "^2.1.4",
"@yume-chan/event": "^0.0.10",
"@yume-chan/scrcpy": "^0.0.10",

View file

@ -5,7 +5,7 @@ import { observer } from "mobx-react-lite";
import { NextPage } from "next";
import Head from "next/head";
import React, { useCallback, useEffect, useRef } from 'react';
import { CommandBar, DemoMode, DeviceView } from '../components';
import { CommandBar, DemoModePanel, DeviceView } from '../components';
import { globalState } from "../state";
import { Icons, RouteStackProps } from "../utils";
@ -123,7 +123,7 @@ const FrameBuffer: NextPage = (): JSX.Element | null => {
<canvas ref={canvasRef} style={{ display: 'block' }} />
</DeviceView>
<DemoMode style={{ display: state.demoModeVisible ? 'block' : 'none' }} />
<DemoModePanel style={{ display: state.demoModeVisible ? 'block' : 'none' }} />
</Stack>
</Stack>
);

View file

@ -8,7 +8,7 @@ import { observer } from "mobx-react-lite";
import { NextPage } from "next";
import Head from "next/head";
import React, { useEffect, useMemo, useState } from "react";
import { DemoMode, DeviceView, DeviceViewRef, ExternalLink } from "../components";
import { DemoModePanel, DeviceView, DeviceViewRef, ExternalLink } from "../components";
import { globalState } from "../state";
import { CommonStackTokens, formatSpeed, Icons, RouteStackProps } from "../utils";
@ -894,7 +894,7 @@ const Scrcpy: NextPage = () => {
/>
</div>
<DemoMode
<DemoModePanel
style={{ display: state.demoModeVisible ? 'block' : 'none' }}
/>

View file

@ -16,6 +16,7 @@ specifiers:
'@rush-temp/adb-backend-webusb': file:./projects/adb-backend-webusb.tgz
'@rush-temp/adb-backend-ws': file:./projects/adb-backend-ws.tgz
'@rush-temp/adb-credential-web': file:./projects/adb-credential-web.tgz
'@rush-temp/android-bin': file:./projects/android-bin.tgz
'@rush-temp/dataview-bigint-polyfill': file:./projects/dataview-bigint-polyfill.tgz
'@rush-temp/demo': file:./projects/demo.tgz
'@rush-temp/event': file:./projects/event.tgz
@ -74,6 +75,7 @@ dependencies:
'@rush-temp/adb-backend-webusb': file:projects/adb-backend-webusb.tgz
'@rush-temp/adb-backend-ws': file:projects/adb-backend-ws.tgz
'@rush-temp/adb-credential-web': file:projects/adb-credential-web.tgz
'@rush-temp/android-bin': file:projects/android-bin.tgz
'@rush-temp/dataview-bigint-polyfill': file:projects/dataview-bigint-polyfill.tgz
'@rush-temp/demo': file:projects/demo.tgz_@mdx-js+react@1.6.22
'@rush-temp/event': file:projects/event.tgz
@ -13108,6 +13110,15 @@ packages:
- utf-8-validate
dev: false
file:projects/android-bin.tgz:
resolution: {integrity: sha512-+POm1mf4P1s+NhgwA6IHN+GBBmc00lDi7k+geCc04ts836duRlnJfkIEeIIJmjQHVwDz36BONp8rCXAaX4U/fA==, tarball: file:projects/android-bin.tgz}
name: '@rush-temp/android-bin'
version: 0.0.0
dependencies:
tslib: 2.3.1
typescript: 4.5.5
dev: false
file:projects/dataview-bigint-polyfill.tgz:
resolution: {integrity: sha512-tlwAp44MyiGGyikI+6kFaCkVQjkpKmlMPm0hm6ts97uydxfdNgMnoGp0JW4J4WDvFOjforF3Z1+kfvBTVDHv1w==, tarball: file:projects/dataview-bigint-polyfill.tgz}
name: '@rush-temp/dataview-bigint-polyfill'

View file

@ -2,7 +2,7 @@ import { PromiseResolver } from '@yume-chan/async';
import { DisposableList } from '@yume-chan/event';
import { AdbAuthenticationHandler, AdbCredentialStore, AdbDefaultAuthenticators } from './auth';
import { AdbBackend } from './backend';
import { AdbChildProcess, AdbDemoMode, AdbFrameBuffer, AdbPower, AdbReverseCommand, AdbSync, AdbTcpIpCommand, escapeArg, framebuffer, install } from './commands';
import { AdbChildProcess, AdbFrameBuffer, AdbPower, AdbReverseCommand, AdbSync, AdbTcpIpCommand, escapeArg, framebuffer, install } from './commands';
import { AdbFeatures } from './features';
import { AdbCommand } from './packet';
import { AdbLogger, AdbPacketDispatcher, AdbSocket } from './socket';
@ -45,7 +45,6 @@ export class Adb {
public get features() { return this._features; }
public readonly childProcess: AdbChildProcess;
public readonly demoMode: AdbDemoMode;
public readonly power: AdbPower;
public readonly reverse: AdbReverseCommand;
public readonly tcpip: AdbTcpIpCommand;
@ -55,7 +54,6 @@ export class Adb {
this.packetDispatcher = new AdbPacketDispatcher(backend, logger);
this.childProcess = new AdbChildProcess(this);
this.demoMode = new AdbDemoMode(this);
this.power = new AdbPower(this);
this.reverse = new AdbReverseCommand(this.packetDispatcher);
this.tcpip = new AdbTcpIpCommand(this);
@ -196,12 +194,17 @@ export class Adb {
}
public async getProp(key: string): Promise<string> {
const output = await this.childProcess.exec('getprop', key);
return output.trim();
const stdout = await this.childProcess.spawnAndWaitLegacy(
['getprop', key]
);
return stdout.trim();
}
public async rm(...filenames: string[]): Promise<string> {
return await this.childProcess.exec('rm', '-rf', ...filenames.map(arg => escapeArg(arg)));
const stdout = await this.childProcess.spawnAndWaitLegacy(
['rm', '-rf', ...filenames.map(arg => escapeArg(arg))],
);
return stdout;
}
public async install(

View file

@ -1,5 +1,4 @@
export * from './base';
export * from './demo-mode';
export * from './framebuffer';
export * from './install';
export * from './power';

View file

@ -14,7 +14,7 @@ export async function install(
sync.dispose();
// Invoke `pm install` to install it
await adb.childProcess.exec('pm', 'install', escapeArg(filename));
await adb.childProcess.spawnAndWaitLegacy(['pm', 'install', escapeArg(filename)]);
// Remove the temp file
await adb.rm(filename);

View file

@ -36,11 +36,11 @@ export class AdbPower extends AdbCommandBase {
}
public powerOff() {
return this.adb.childProcess.exec('reboot', '-p');
return this.adb.childProcess.spawnAndWaitLegacy(['reboot', '-p']);
}
public powerButton(longPress: boolean = false) {
return this.adb.childProcess.exec('input', 'keyevent', longPress ? '--longpress POWER' : 'POWER');
return this.adb.childProcess.spawnAndWaitLegacy(['input', 'keyevent', longPress ? '--longpress POWER' : 'POWER']);
}
/**

View file

@ -1,4 +1,6 @@
import { once } from "@yume-chan/event";
import type { Adb } from '../../adb';
import { decodeUtf8 } from "../../utils";
import { AdbLegacyShell } from './legacy';
import { AdbShellProtocol } from './protocol';
import type { AdbShell, AdbShellConstructor } from './types';
@ -27,6 +29,12 @@ const DefaultOptions: AdbChildProcessOptions = {
shells: [AdbShellProtocol, AdbLegacyShell],
};
export interface ChildProcessResult {
stdout: string;
stderr: string;
exitCode: number;
}
export class AdbChildProcess {
public readonly adb: Adb;
@ -80,8 +88,23 @@ export class AdbChildProcess {
* @param args List of command arguments
* @returns The entire output of the command
*/
public exec(command: string, ...args: string[]): Promise<string> {
// `exec` only needs the entire output, use Legacy Shell is simpler.
return this.adb.createSocketAndReadAll(`shell:${command} ${args.join(' ')}`);
public async spawnAndWait(command: string | string[], options?: Partial<AdbChildProcessOptions>): Promise<ChildProcessResult> {
const shell = await this.spawn(command, options);
// Optimization: rope (concat strings) is faster than `[].join('')`
let stdout = '';
let stderr = '';
shell.onStdout(buffer => stdout += decodeUtf8(buffer));
shell.onStderr(buffer => stderr += decodeUtf8(buffer));
const exitCode = await once(shell.onExit);
return {
stdout,
stderr,
exitCode,
};
}
public async spawnAndWaitLegacy(command: string | string[]): Promise<string> {
const { stdout } = await this.spawnAndWait(command, { shells: [AdbLegacyShell] });
return stdout;
}
}

View file

@ -0,0 +1,5 @@
# `@yume-chan/android-bin`
Wrappers for Android built-in executables.
Currently it's bound to `@yume-chan/adb`, maybe one day it can be used with other executors.

View file

@ -0,0 +1,41 @@
{
"name": "@yume-chan/android-bin",
"version": "0.0.10",
"description": "Wrappers for Android built-in executables.",
"keywords": [
"adb",
"Android"
],
"license": "MIT",
"author": {
"name": "Simon Chan",
"email": "cnsimonchan@live.com",
"url": "https://chensi.moe/blog"
},
"homepage": "https://github.com/yume-chan/ya-webadb/tree/master/libraries/android-bin#readme",
"repository": {
"type": "git",
"url": "git+https://github.com/yume-chan/ya-webadb.git",
"directory": "libraries/android-bin"
},
"bugs": {
"url": "https://github.com/yume-chan/ya-webadb/issues"
},
"type": "module",
"module": "esm/index.js",
"types": "esm/index.d.ts",
"scripts": {
"build": "build-ts-package",
"build:watch": "build-ts-package --incremental",
"prepublishOnly": "npm run build"
},
"devDependencies": {
"typescript": "^4.5.5",
"@yume-chan/ts-package-builder": "^1.0.0"
},
"dependencies": {
"@yume-chan/adb": "^0.0.10",
"@yume-chan/event": "^0.0.10",
"tslib": "^2.3.1"
}
}

View file

@ -0,0 +1,35 @@
// cspell: ignore bugreport
// cspell: ignore bugreportz
import { AdbCommandBase, AdbShellProtocol } from "@yume-chan/adb";
export interface BugReportVersion {
major: number;
minor: number;
}
const BUG_REPORT_VERSION_REGEX = /(\d+)\.(\d+)/;
export class BugReport extends AdbCommandBase {
public async bugReportZVersion(): Promise<BugReportVersion | undefined> {
// bugreportz requires shell protocol
if (!AdbShellProtocol.isSupported(this.adb)) {
return undefined;
}
const { stderr, exitCode } = await this.adb.childProcess.spawnAndWait(['bugreportz', '-v']);
if (exitCode !== 0 || stderr === '') {
return undefined;
}
const match = stderr.match(BUG_REPORT_VERSION_REGEX);
if (!match) {
return undefined;
}
return {
major: parseInt(match[1]!, 10),
minor: parseInt(match[2]!, 10),
};
}
}

View file

@ -4,9 +4,9 @@
// cspell: ignore systemui
// cspell: ignore sysui
import { AdbCommandBase } from './base';
import { AdbCommandBase, AdbLegacyShell } from '@yume-chan/adb';
export enum AdbDemoModeSignalStrength {
export enum DemoModeSignalStrength {
Hidden = 'null',
Level0 = '0',
Level1 = '1',
@ -16,17 +16,23 @@ export enum AdbDemoModeSignalStrength {
}
// https://cs.android.com/android/platform/superproject/+/master:frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java;l=1073
export const AdbDemoModeMobileDataTypes = ['1x', '3g', '4g', '4g+', '5g', '5ge', '5g+',
export const DemoModeMobileDataTypes = ['1x', '3g', '4g', '4g+', '5g', '5ge', '5g+',
'e', 'g', 'h', 'h+', 'lte', 'lte+', 'dis', 'not', 'null'] as const;
export type AdbDemoModeMobileDataType = (typeof AdbDemoModeMobileDataTypes)[number];
export type DemoModeMobileDataType = (typeof DemoModeMobileDataTypes)[number];
// https://cs.android.com/android/platform/superproject/+/master:frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java;l=3136
export const AdbDemoModeStatusBarModes = ['opaque', 'translucent', 'semi-transparent', 'transparent', 'warning'] as const;
export const DemoModeStatusBarModes = ['opaque', 'translucent', 'semi-transparent', 'transparent', 'warning'] as const;
export type AdbDemoModeStatusBarMode = (typeof AdbDemoModeStatusBarModes)[number];
export type DemoModeStatusBarMode = (typeof DemoModeStatusBarModes)[number];
export class AdbDemoMode extends AdbCommandBase {
export class Settings extends AdbCommandBase {
public get(key: string, global: boolean = false) {
}
}
export class DemoMode extends AdbCommandBase {
public static readonly AllowedSettingKey = 'sysui_demo_allowed';
// Demo Mode actually doesn't have a setting indicates its enablement
@ -34,36 +40,41 @@ export class AdbDemoMode extends AdbCommandBase {
// So we can only try our best to guess if it's enabled
public static readonly EnabledSettingKey = 'sysui_tuner_demo_on';
private async settings(...command: string[]): Promise<string> {
const { stdout } = await this.adb.childProcess.spawnAndWait(command, { shells: [AdbLegacyShell] });
return stdout.trim();
}
public async getAllowed(): Promise<boolean> {
const result = await this.adb.childProcess.exec('settings', 'get', 'global', AdbDemoMode.AllowedSettingKey);
return result.trim() === '1';
const output = await this.settings('settings', 'get', 'global', DemoMode.AllowedSettingKey);
return output.trim() === '1';
}
public async setAllowed(value: boolean): Promise<void> {
if (value) {
await this.adb.childProcess.exec('settings', 'put', 'global', AdbDemoMode.AllowedSettingKey, '1');
await this.settings('settings', 'put', 'global', DemoMode.AllowedSettingKey, '1');
} else {
await this.setEnabled(false);
await this.adb.childProcess.exec('settings', 'delete', 'global', AdbDemoMode.AllowedSettingKey);
await this.settings('settings', 'delete', 'global', DemoMode.AllowedSettingKey);
}
}
public async getEnabled(): Promise<boolean> {
const result = await this.adb.childProcess.exec('settings', 'get', 'global', AdbDemoMode.EnabledSettingKey);
const result = await this.settings('settings', 'get', 'global', DemoMode.EnabledSettingKey);
return result.trim() === '1';
}
public async setEnabled(value: boolean): Promise<void> {
if (value) {
await this.adb.childProcess.exec('settings', 'put', 'global', AdbDemoMode.EnabledSettingKey, '1');
await this.settings('settings', 'put', 'global', DemoMode.EnabledSettingKey, '1');
} else {
await this.adb.childProcess.exec('settings', 'delete', 'global', AdbDemoMode.EnabledSettingKey);
await this.settings('settings', 'delete', 'global', DemoMode.EnabledSettingKey);
await this.broadcast('exit');
}
}
public async broadcast(command: string, extra?: Record<string, string>): Promise<void> {
await this.adb.childProcess.exec(
await this.adb.childProcess.spawnAndWaitLegacy([
'am',
'broadcast',
'-a',
@ -72,7 +83,7 @@ export class AdbDemoMode extends AdbCommandBase {
'command',
command,
...(extra ? Object.entries(extra).flatMap(([key, value]) => ['-e', key, value]) : []),
);
]);
}
public async setBatteryLevel(level: number): Promise<void> {
@ -91,11 +102,11 @@ export class AdbDemoMode extends AdbCommandBase {
await this.broadcast('network', { airplane: show ? 'show' : 'hide' });
}
public async setWifiSignalStrength(value: AdbDemoModeSignalStrength): Promise<void> {
public async setWifiSignalStrength(value: DemoModeSignalStrength): Promise<void> {
await this.broadcast('network', { wifi: 'show', level: value });
}
public async setMobileDataType(value: AdbDemoModeMobileDataType): Promise<void> {
public async setMobileDataType(value: DemoModeMobileDataType): Promise<void> {
for (let i = 0; i < 2; i += 1) {
await this.broadcast('network', {
mobile: 'show',
@ -113,7 +124,7 @@ export class AdbDemoMode extends AdbCommandBase {
}
}
public async setMobileSignalStrength(value: AdbDemoModeSignalStrength): Promise<void> {
public async setMobileSignalStrength(value: DemoModeSignalStrength): Promise<void> {
await this.broadcast('network', { mobile: 'show', level: value });
}
@ -121,7 +132,7 @@ export class AdbDemoMode extends AdbCommandBase {
await this.broadcast('network', { nosim: show ? 'show' : 'hide' });
}
public async setStatusBarMode(mode: AdbDemoModeStatusBarMode): Promise<void> {
public async setStatusBarMode(mode: DemoModeStatusBarMode): Promise<void> {
await this.broadcast('bars', { mode });
}

View file

@ -0,0 +1 @@
export * from './demo-mode';

View file

@ -0,0 +1,14 @@
{
"extends": "./node_modules/@yume-chan/ts-package-builder/tsconfig.base.json",
"compilerOptions": {
"lib": [
"ESNext",
"DOM"
],
},
"references": [
{
"path": "../adb/tsconfig.json"
}
]
}

View file

@ -474,6 +474,12 @@
"shouldPublish": true,
"versionPolicyName": "adb"
},
{
"packageName": "@yume-chan/android-bin",
"projectFolder": "libraries/android-bin",
"shouldPublish": true,
"versionPolicyName": "adb"
},
{
"packageName": "@yume-chan/scrcpy",
"projectFolder": "libraries/scrcpy",