mirror of
https://github.com/yume-chan/ya-webadb.git
synced 2025-10-05 19:42:15 +02:00
refactor(bin): move demo mode to new package
This commit is contained in:
parent
daf726f2e0
commit
41a9565eeb
18 changed files with 229 additions and 77 deletions
|
@ -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);
|
||||
});
|
|
@ -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';
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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>
|
||||
);
|
||||
|
|
|
@ -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' }}
|
||||
/>
|
||||
|
||||
|
|
11
common/config/rush/pnpm-lock.yaml
generated
11
common/config/rush/pnpm-lock.yaml
generated
|
@ -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'
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
export * from './base';
|
||||
export * from './demo-mode';
|
||||
export * from './framebuffer';
|
||||
export * from './install';
|
||||
export * from './power';
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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']);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
5
libraries/android-bin/README.md
Normal file
5
libraries/android-bin/README.md
Normal 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.
|
41
libraries/android-bin/package.json
Normal file
41
libraries/android-bin/package.json
Normal 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"
|
||||
}
|
||||
}
|
35
libraries/android-bin/src/bug-report.ts
Normal file
35
libraries/android-bin/src/bug-report.ts
Normal 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),
|
||||
};
|
||||
}
|
||||
}
|
|
@ -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 });
|
||||
}
|
||||
|
1
libraries/android-bin/src/index.ts
Normal file
1
libraries/android-bin/src/index.ts
Normal file
|
@ -0,0 +1 @@
|
|||
export * from './demo-mode';
|
14
libraries/android-bin/tsconfig.json
Normal file
14
libraries/android-bin/tsconfig.json
Normal 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"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -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",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue