mirror of
https://github.com/yume-chan/ya-webadb.git
synced 2025-10-04 18:29:23 +02:00
feat(adb): add power related api
This commit is contained in:
parent
1ea248d57e
commit
45d784c8a5
19 changed files with 196 additions and 106 deletions
|
@ -6,7 +6,7 @@ import AdbWsBackend from '@yume-chan/adb-backend-ws';
|
||||||
import AdbWebCredentialStore from '@yume-chan/adb-credential-web';
|
import AdbWebCredentialStore from '@yume-chan/adb-credential-web';
|
||||||
import { observer } from 'mobx-react-lite';
|
import { observer } from 'mobx-react-lite';
|
||||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||||
import { global, logger } from '../state';
|
import { globalState, logger } from '../state';
|
||||||
import { CommonStackTokens, Icons } from '../utils';
|
import { CommonStackTokens, Icons } from '../utils';
|
||||||
|
|
||||||
const DropdownStyles = { dropdown: { width: '100%' } };
|
const DropdownStyles = { dropdown: { width: '100%' } };
|
||||||
|
@ -33,7 +33,7 @@ function _Connect(): JSX.Element | null {
|
||||||
setSupported(supported);
|
setSupported(supported);
|
||||||
|
|
||||||
if (!supported) {
|
if (!supported) {
|
||||||
global.showErrorDialog('Your browser does not support WebUSB standard, which is required for this site to work.\n\nLatest version of Google Chrome, Microsoft Edge, or other Chromium-based browsers are required.');
|
globalState.showErrorDialog('Your browser does not support WebUSB standard, which is required for this site to work.\n\nLatest version of Google Chrome, Microsoft Edge, or other Chromium-based browsers are required.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,24 +134,24 @@ function _Connect(): JSX.Element | null {
|
||||||
try {
|
try {
|
||||||
setConnecting(true);
|
setConnecting(true);
|
||||||
await device.connect(CredentialStore);
|
await device.connect(CredentialStore);
|
||||||
global.setDevice(device);
|
globalState.setDevice(device);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
device.dispose();
|
device.dispose();
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
global.showErrorDialog(e.message);
|
globalState.showErrorDialog(e.message);
|
||||||
} finally {
|
} finally {
|
||||||
setConnecting(false);
|
setConnecting(false);
|
||||||
}
|
}
|
||||||
}, [selectedBackend]);
|
}, [selectedBackend]);
|
||||||
const disconnect = useCallback(async () => {
|
const disconnect = useCallback(async () => {
|
||||||
try {
|
try {
|
||||||
await global.device!.dispose();
|
await globalState.device!.dispose();
|
||||||
global.setDevice(undefined);
|
globalState.setDevice(undefined);
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
global.showErrorDialog(e.message);
|
globalState.showErrorDialog(e.message);
|
||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
@ -214,7 +214,7 @@ function _Connect(): JSX.Element | null {
|
||||||
tokens={{ childrenGap: 8, padding: '0 0 8px 8px' }}
|
tokens={{ childrenGap: 8, padding: '0 0 8px 8px' }}
|
||||||
>
|
>
|
||||||
<Dropdown
|
<Dropdown
|
||||||
disabled={!!global.device || backendOptions.length === 0}
|
disabled={!!globalState.device || backendOptions.length === 0}
|
||||||
label="Available devices"
|
label="Available devices"
|
||||||
placeholder="No available devices"
|
placeholder="No available devices"
|
||||||
options={backendOptions}
|
options={backendOptions}
|
||||||
|
@ -224,7 +224,7 @@ function _Connect(): JSX.Element | null {
|
||||||
onChange={handleSelectedBackendChange}
|
onChange={handleSelectedBackendChange}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{!global.device
|
{!globalState.device
|
||||||
? (
|
? (
|
||||||
<Stack horizontal tokens={CommonStackTokens}>
|
<Stack horizontal tokens={CommonStackTokens}>
|
||||||
<StackItem grow shrink>
|
<StackItem grow shrink>
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { AdbDemoModeMobileDataType, AdbDemoModeMobileDataTypes, AdbDemoModeSigna
|
||||||
import { autorun, makeAutoObservable, reaction, runInAction } from "mobx";
|
import { autorun, makeAutoObservable, reaction, runInAction } from "mobx";
|
||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
import { CSSProperties, useCallback } from 'react';
|
import { CSSProperties, useCallback } from 'react';
|
||||||
import { global } from "../state";
|
import { globalState } from "../state";
|
||||||
|
|
||||||
const SignalStrengthOptions =
|
const SignalStrengthOptions =
|
||||||
Object.values(AdbDemoModeSignalStrength)
|
Object.values(AdbDemoModeSignalStrength)
|
||||||
|
@ -65,7 +65,7 @@ class DemoModeState {
|
||||||
makeAutoObservable(this);
|
makeAutoObservable(this);
|
||||||
|
|
||||||
reaction(
|
reaction(
|
||||||
() => global.device,
|
() => globalState.device,
|
||||||
async (device) => {
|
async (device) => {
|
||||||
if (device) {
|
if (device) {
|
||||||
const allowed = await device.demoMode.getAllowed();
|
const allowed = await device.demoMode.getAllowed();
|
||||||
|
@ -120,21 +120,21 @@ const FEATURES: FeatureDefinition[][] = [
|
||||||
max: 100,
|
max: 100,
|
||||||
step: 1,
|
step: 1,
|
||||||
initial: 100,
|
initial: 100,
|
||||||
onChange: (value) => global.device!.demoMode.setBatteryLevel(value as number),
|
onChange: (value) => globalState.device!.demoMode.setBatteryLevel(value as number),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'batteryCharging',
|
key: 'batteryCharging',
|
||||||
label: 'Battery Charging',
|
label: 'Battery Charging',
|
||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
initial: false,
|
initial: false,
|
||||||
onChange: (value) => global.device!.demoMode.setBatteryCharging(value as boolean),
|
onChange: (value) => globalState.device!.demoMode.setBatteryCharging(value as boolean),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'powerSaveMode',
|
key: 'powerSaveMode',
|
||||||
label: 'Power Save Mode',
|
label: 'Power Save Mode',
|
||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
initial: false,
|
initial: false,
|
||||||
onChange: (value) => global.device!.demoMode.setPowerSaveMode(value as boolean),
|
onChange: (value) => globalState.device!.demoMode.setPowerSaveMode(value as boolean),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
|
@ -144,14 +144,14 @@ const FEATURES: FeatureDefinition[][] = [
|
||||||
type: 'select',
|
type: 'select',
|
||||||
options: SignalStrengthOptions,
|
options: SignalStrengthOptions,
|
||||||
initial: AdbDemoModeSignalStrength.Level4,
|
initial: AdbDemoModeSignalStrength.Level4,
|
||||||
onChange: (value) => global.device!.demoMode.setWifiSignalStrength(value as AdbDemoModeSignalStrength),
|
onChange: (value) => globalState.device!.demoMode.setWifiSignalStrength(value as AdbDemoModeSignalStrength),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'airplaneMode',
|
key: 'airplaneMode',
|
||||||
label: 'Airplane Mode',
|
label: 'Airplane Mode',
|
||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
initial: false,
|
initial: false,
|
||||||
onChange: (value) => global.device!.demoMode.setAirplaneMode(value as boolean),
|
onChange: (value) => globalState.device!.demoMode.setAirplaneMode(value as boolean),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'mobileDataType',
|
key: 'mobileDataType',
|
||||||
|
@ -159,7 +159,7 @@ const FEATURES: FeatureDefinition[][] = [
|
||||||
type: 'select',
|
type: 'select',
|
||||||
options: MobileDataTypeOptions,
|
options: MobileDataTypeOptions,
|
||||||
initial: 'lte',
|
initial: 'lte',
|
||||||
onChange: (value) => global.device!.demoMode.setMobileDataType(value as AdbDemoModeMobileDataType),
|
onChange: (value) => globalState.device!.demoMode.setMobileDataType(value as AdbDemoModeMobileDataType),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'mobileSignalStrength',
|
key: 'mobileSignalStrength',
|
||||||
|
@ -167,7 +167,7 @@ const FEATURES: FeatureDefinition[][] = [
|
||||||
type: 'select',
|
type: 'select',
|
||||||
options: SignalStrengthOptions,
|
options: SignalStrengthOptions,
|
||||||
initial: AdbDemoModeSignalStrength.Level4,
|
initial: AdbDemoModeSignalStrength.Level4,
|
||||||
onChange: (value) => global.device!.demoMode.setMobileSignalStrength(value as AdbDemoModeSignalStrength),
|
onChange: (value) => globalState.device!.demoMode.setMobileSignalStrength(value as AdbDemoModeSignalStrength),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
|
@ -177,42 +177,42 @@ const FEATURES: FeatureDefinition[][] = [
|
||||||
type: 'select',
|
type: 'select',
|
||||||
options: StatusBarModeOptions,
|
options: StatusBarModeOptions,
|
||||||
initial: 'transparent',
|
initial: 'transparent',
|
||||||
onChange: (value) => global.device!.demoMode.setStatusBarMode(value as AdbDemoModeStatusBarMode),
|
onChange: (value) => globalState.device!.demoMode.setStatusBarMode(value as AdbDemoModeStatusBarMode),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'vibrateMode',
|
key: 'vibrateMode',
|
||||||
label: 'Vibrate Mode Indicator',
|
label: 'Vibrate Mode Indicator',
|
||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
initial: false,
|
initial: false,
|
||||||
onChange: (value) => global.device!.demoMode.setVibrateModeEnabled(value as boolean),
|
onChange: (value) => globalState.device!.demoMode.setVibrateModeEnabled(value as boolean),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'bluetoothConnected',
|
key: 'bluetoothConnected',
|
||||||
label: 'Bluetooth Indicator',
|
label: 'Bluetooth Indicator',
|
||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
initial: false,
|
initial: false,
|
||||||
onChange: (value) => global.device!.demoMode.setBluetoothConnected(value as boolean),
|
onChange: (value) => globalState.device!.demoMode.setBluetoothConnected(value as boolean),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'locatingIcon',
|
key: 'locatingIcon',
|
||||||
label: 'Locating Icon',
|
label: 'Locating Icon',
|
||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
initial: false,
|
initial: false,
|
||||||
onChange: (value) => global.device!.demoMode.setLocatingIcon(value as boolean),
|
onChange: (value) => globalState.device!.demoMode.setLocatingIcon(value as boolean),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'alarmIcon',
|
key: 'alarmIcon',
|
||||||
label: 'Alarm Icon',
|
label: 'Alarm Icon',
|
||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
initial: false,
|
initial: false,
|
||||||
onChange: (value) => global.device!.demoMode.setAlarmIcon(value as boolean),
|
onChange: (value) => globalState.device!.demoMode.setAlarmIcon(value as boolean),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'notificationsVisibility',
|
key: 'notificationsVisibility',
|
||||||
label: 'Notifications Visibility',
|
label: 'Notifications Visibility',
|
||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
initial: true,
|
initial: true,
|
||||||
onChange: (value) => global.device!.demoMode.setNotificationsVisibility(value as boolean),
|
onChange: (value) => globalState.device!.demoMode.setNotificationsVisibility(value as boolean),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'hour',
|
key: 'hour',
|
||||||
|
@ -222,7 +222,7 @@ const FEATURES: FeatureDefinition[][] = [
|
||||||
max: 23,
|
max: 23,
|
||||||
step: 1,
|
step: 1,
|
||||||
initial: 12,
|
initial: 12,
|
||||||
onChange: (value) => global.device!.demoMode.setTime(value as number, state.features.get('minute') as number | undefined ?? 34)
|
onChange: (value) => globalState.device!.demoMode.setTime(value as number, state.features.get('minute') as number | undefined ?? 34)
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'minute',
|
key: 'minute',
|
||||||
|
@ -232,7 +232,7 @@ const FEATURES: FeatureDefinition[][] = [
|
||||||
max: 59,
|
max: 59,
|
||||||
step: 1,
|
step: 1,
|
||||||
initial: 34,
|
initial: 34,
|
||||||
onChange: (value) => global.device!.demoMode.setTime(state.features.get('hour') as number | undefined ?? 34, value as number)
|
onChange: (value) => globalState.device!.demoMode.setTime(state.features.get('hour') as number | undefined ?? 34, value as number)
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
@ -306,7 +306,7 @@ const DemoModeBase = ({
|
||||||
style,
|
style,
|
||||||
}: DemoModeProps) => {
|
}: DemoModeProps) => {
|
||||||
const handleAllowedChange = useCallback(async (e, value?: boolean) => {
|
const handleAllowedChange = useCallback(async (e, value?: boolean) => {
|
||||||
await global.device!.demoMode.setAllowed(value!);
|
await globalState.device!.demoMode.setAllowed(value!);
|
||||||
runInAction(() => {
|
runInAction(() => {
|
||||||
state.allowed = value!;
|
state.allowed = value!;
|
||||||
state.enabled = false;
|
state.enabled = false;
|
||||||
|
@ -314,7 +314,7 @@ const DemoModeBase = ({
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const handleEnabledChange = useCallback(async (e, value?: boolean) => {
|
const handleEnabledChange = useCallback(async (e, value?: boolean) => {
|
||||||
await global.device!.demoMode.setEnabled(value!);
|
await globalState.device!.demoMode.setEnabled(value!);
|
||||||
runInAction(() => state.enabled = value!);
|
runInAction(() => state.enabled = value!);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
@ -322,7 +322,7 @@ const DemoModeBase = ({
|
||||||
<div style={{ padding: 12, overflow: 'hidden auto', ...style }}>
|
<div style={{ padding: 12, overflow: 'hidden auto', ...style }}>
|
||||||
<Toggle
|
<Toggle
|
||||||
label="Allowed"
|
label="Allowed"
|
||||||
disabled={!global.device}
|
disabled={!globalState.device}
|
||||||
checked={state.allowed}
|
checked={state.allowed}
|
||||||
onChange={handleAllowedChange}
|
onChange={handleAllowedChange}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { Dialog, DialogFooter, DialogType, PrimaryButton } from '@fluentui/react';
|
import { Dialog, DialogFooter, DialogType, PrimaryButton } from '@fluentui/react';
|
||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
import { PropsWithChildren } from 'react';
|
import { PropsWithChildren } from 'react';
|
||||||
import { global } from '../state';
|
import { globalState } from '../state';
|
||||||
|
|
||||||
export const ErrorDialogProvider = observer((props: PropsWithChildren<{}>) => {
|
export const ErrorDialogProvider = observer((props: PropsWithChildren<{}>) => {
|
||||||
return (
|
return (
|
||||||
|
@ -9,15 +9,15 @@ export const ErrorDialogProvider = observer((props: PropsWithChildren<{}>) => {
|
||||||
{props.children}
|
{props.children}
|
||||||
|
|
||||||
<Dialog
|
<Dialog
|
||||||
hidden={!global.errorDialogVisible}
|
hidden={!globalState.errorDialogVisible}
|
||||||
dialogContentProps={{
|
dialogContentProps={{
|
||||||
type: DialogType.normal,
|
type: DialogType.normal,
|
||||||
title: 'Error',
|
title: 'Error',
|
||||||
subText: global.errorDialogMessage,
|
subText: globalState.errorDialogMessage,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<DialogFooter>
|
<DialogFooter>
|
||||||
<PrimaryButton text="OK" onClick={global.hideErrorDialog} />
|
<PrimaryButton text="OK" onClick={globalState.hideErrorDialog} />
|
||||||
</DialogFooter>
|
</DialogFooter>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
</>
|
</>
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { AdbPacketInit, decodeUtf8 } from '@yume-chan/adb';
|
||||||
import { DisposableList } from '@yume-chan/event';
|
import { DisposableList } from '@yume-chan/event';
|
||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
import { useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';
|
import { useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';
|
||||||
import { global, logger } from "../state";
|
import { globalState, logger } from "../state";
|
||||||
import { Icons, withDisplayName } from '../utils';
|
import { Icons, withDisplayName } from '../utils';
|
||||||
import { CommandBar } from './command-bar';
|
import { CommandBar } from './command-bar';
|
||||||
|
|
||||||
|
@ -57,10 +57,10 @@ const LogLine = withDisplayName('LoggerLine')(({ packet }: { packet: [string, Ad
|
||||||
export const ToggleLogView = observer(() => {
|
export const ToggleLogView = observer(() => {
|
||||||
return (
|
return (
|
||||||
<IconButton
|
<IconButton
|
||||||
checked={global.logVisible}
|
checked={globalState.logVisible}
|
||||||
iconProps={{ iconName: Icons.TextGrammarError }}
|
iconProps={{ iconName: Icons.TextGrammarError }}
|
||||||
title="Toggle Log"
|
title="Toggle Log"
|
||||||
onClick={global.toggleLog}
|
onClick={globalState.toggleLog}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -142,7 +142,7 @@ export const LogView = observer(({
|
||||||
classNames['logger-container'],
|
classNames['logger-container'],
|
||||||
), [className]);
|
), [className]);
|
||||||
|
|
||||||
if (!global.logVisible) {
|
if (!globalState.logVisible) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -51,6 +51,11 @@ const ROUTES = [
|
||||||
icon: Icons.Box,
|
icon: Icons.Box,
|
||||||
name: 'Install APK',
|
name: 'Install APK',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
url: '/power',
|
||||||
|
icon: Icons.Power,
|
||||||
|
name: 'Power Menu',
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
function NavLink({ link, defaultRender: DefaultRender, ...props }: IComponentAsProps<INavButtonProps>) {
|
function NavLink({ link, defaultRender: DefaultRender, ...props }: IComponentAsProps<INavButtonProps>) {
|
||||||
|
|
|
@ -5,7 +5,7 @@ import type { NextPage } from 'next';
|
||||||
import Head from 'next/head';
|
import Head from 'next/head';
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { ExternalLink } from "../components";
|
import { ExternalLink } from "../components";
|
||||||
import { global } from '../state';
|
import { globalState } from '../state';
|
||||||
import { Icons, RouteStackProps } from "../utils";
|
import { Icons, RouteStackProps } from "../utils";
|
||||||
|
|
||||||
const KNOWN_FEATURES: Record<string, string> = {
|
const KNOWN_FEATURES: Record<string, string> = {
|
||||||
|
@ -52,7 +52,7 @@ const DeviceInfo: NextPage = () => {
|
||||||
</MessageBar>
|
</MessageBar>
|
||||||
<span>
|
<span>
|
||||||
<span>Protocol Version: </span>
|
<span>Protocol Version: </span>
|
||||||
<code>{global.device?.protocolVersion?.toString(16).padStart(8, '0')}</code>
|
<code>{globalState.device?.protocolVersion?.toString(16).padStart(8, '0')}</code>
|
||||||
</span>
|
</span>
|
||||||
<Separator />
|
<Separator />
|
||||||
|
|
||||||
|
@ -60,21 +60,21 @@ const DeviceInfo: NextPage = () => {
|
||||||
<code>ro.product.name</code>
|
<code>ro.product.name</code>
|
||||||
<span> field in Android Build Props</span>
|
<span> field in Android Build Props</span>
|
||||||
</MessageBar>
|
</MessageBar>
|
||||||
<span>Product Name: {global.device?.product}</span>
|
<span>Product Name: {globalState.device?.product}</span>
|
||||||
<Separator />
|
<Separator />
|
||||||
|
|
||||||
<MessageBar>
|
<MessageBar>
|
||||||
<code>ro.product.model</code>
|
<code>ro.product.model</code>
|
||||||
<span> field in Android Build Props</span>
|
<span> field in Android Build Props</span>
|
||||||
</MessageBar>
|
</MessageBar>
|
||||||
<span>Model Name: {global.device?.model}</span>
|
<span>Model Name: {globalState.device?.model}</span>
|
||||||
<Separator />
|
<Separator />
|
||||||
|
|
||||||
<MessageBar>
|
<MessageBar>
|
||||||
<code>ro.product.device</code>
|
<code>ro.product.device</code>
|
||||||
<span> field in Android Build Props</span>
|
<span> field in Android Build Props</span>
|
||||||
</MessageBar>
|
</MessageBar>
|
||||||
<span>Device Name: {global.device?.device}</span>
|
<span>Device Name: {globalState.device?.device}</span>
|
||||||
<Separator />
|
<Separator />
|
||||||
|
|
||||||
<MessageBar>
|
<MessageBar>
|
||||||
|
@ -87,7 +87,7 @@ const DeviceInfo: NextPage = () => {
|
||||||
</MessageBar>
|
</MessageBar>
|
||||||
<span>
|
<span>
|
||||||
<span>Features: </span>
|
<span>Features: </span>
|
||||||
{global.device?.features?.map((feature, index) => (
|
{globalState.device?.features?.map((feature, index) => (
|
||||||
<span key={feature}>
|
<span key={feature}>
|
||||||
{index !== 0 && (<span>, </span>)}
|
{index !== 0 && (<span>, </span>)}
|
||||||
<span>{feature}</span>
|
<span>{feature}</span>
|
||||||
|
|
|
@ -12,7 +12,7 @@ import Router, { useRouter } from "next/router";
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import React, { useCallback, useEffect, useLayoutEffect, useRef, useState } from 'react';
|
import React, { useCallback, useEffect, useLayoutEffect, useRef, useState } from 'react';
|
||||||
import { CommandBar } from '../components';
|
import { CommandBar } from '../components';
|
||||||
import { global } from '../state';
|
import { globalState } from '../state';
|
||||||
import { asyncEffect, chunkFile, formatSize, formatSpeed, Icons, pickFile, RouteStackProps } from '../utils';
|
import { asyncEffect, chunkFile, formatSize, formatSpeed, Icons, pickFile, RouteStackProps } from '../utils';
|
||||||
|
|
||||||
let StreamSaver: typeof import('streamsaver');
|
let StreamSaver: typeof import('streamsaver');
|
||||||
|
@ -140,7 +140,7 @@ class FileManagerState {
|
||||||
iconName: Icons.CloudArrowUp,
|
iconName: Icons.CloudArrowUp,
|
||||||
style: { height: 20, fontSize: 20, lineHeight: 1.5 }
|
style: { height: 20, fontSize: 20, lineHeight: 1.5 }
|
||||||
},
|
},
|
||||||
disabled: !global.device,
|
disabled: !globalState.device,
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
(async () => {
|
(async () => {
|
||||||
const files = await pickFile({ multiple: true });
|
const files = await pickFile({ multiple: true });
|
||||||
|
@ -167,7 +167,7 @@ class FileManagerState {
|
||||||
},
|
},
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
(async () => {
|
(async () => {
|
||||||
const sync = await global.device!.sync();
|
const sync = await globalState.device!.sync();
|
||||||
try {
|
try {
|
||||||
const itemPath = path.resolve(this.path, this.selectedItems[0].name!);
|
const itemPath = path.resolve(this.path, this.selectedItems[0].name!);
|
||||||
const readableStream = createReadableStreamFromBufferIterator(sync.read(itemPath));
|
const readableStream = createReadableStreamFromBufferIterator(sync.read(itemPath));
|
||||||
|
@ -177,7 +177,7 @@ class FileManagerState {
|
||||||
});
|
});
|
||||||
await readableStream.pipeTo(writeableStream);
|
await readableStream.pipeTo(writeableStream);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
global.showErrorDialog(e instanceof Error ? e.message : `${e}`);
|
globalState.showErrorDialog(e instanceof Error ? e.message : `${e}`);
|
||||||
} finally {
|
} finally {
|
||||||
sync.dispose();
|
sync.dispose();
|
||||||
}
|
}
|
||||||
|
@ -199,14 +199,14 @@ class FileManagerState {
|
||||||
(async () => {
|
(async () => {
|
||||||
try {
|
try {
|
||||||
for (const item of this.selectedItems) {
|
for (const item of this.selectedItems) {
|
||||||
const output = await global.device!.rm(path.resolve(this.path, item.name!));
|
const output = await globalState.device!.rm(path.resolve(this.path, item.name!));
|
||||||
if (output) {
|
if (output) {
|
||||||
global.showErrorDialog(output);
|
globalState.showErrorDialog(output);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
global.showErrorDialog(e instanceof Error ? e.message : `${e}`);
|
globalState.showErrorDialog(e instanceof Error ? e.message : `${e}`);
|
||||||
} finally {
|
} finally {
|
||||||
this.loadFiles();
|
this.loadFiles();
|
||||||
}
|
}
|
||||||
|
@ -359,7 +359,7 @@ class FileManagerState {
|
||||||
});
|
});
|
||||||
|
|
||||||
autorun(() => {
|
autorun(() => {
|
||||||
if (global.device) {
|
if (globalState.device) {
|
||||||
if (this.initial && this.visible) {
|
if (this.initial && this.visible) {
|
||||||
this.initial = false;
|
this.initial = false;
|
||||||
this.loadFiles();
|
this.loadFiles();
|
||||||
|
@ -381,7 +381,7 @@ class FileManagerState {
|
||||||
|
|
||||||
this.path = path;
|
this.path = path;
|
||||||
|
|
||||||
if (!global.device) {
|
if (!globalState.device) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -393,13 +393,13 @@ class FileManagerState {
|
||||||
|
|
||||||
runInAction(() => this.items = []);
|
runInAction(() => this.items = []);
|
||||||
|
|
||||||
if (!global.device) {
|
if (!globalState.device) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
runInAction(() => this.loading = true);
|
runInAction(() => this.loading = true);
|
||||||
|
|
||||||
const sync = await global.device.sync();
|
const sync = await globalState.device.sync();
|
||||||
|
|
||||||
const items: ListItem[] = [];
|
const items: ListItem[] = [];
|
||||||
const linkItems: AdbSyncEntryResponse[] = [];
|
const linkItems: AdbSyncEntryResponse[] = [];
|
||||||
|
@ -456,7 +456,7 @@ class FileManagerState {
|
||||||
});
|
});
|
||||||
|
|
||||||
upload = async (file: File) => {
|
upload = async (file: File) => {
|
||||||
const sync = await global.device!.sync();
|
const sync = await globalState.device!.sync();
|
||||||
try {
|
try {
|
||||||
const itemPath = path.resolve(this.path!, file.name);
|
const itemPath = path.resolve(this.path!, file.name);
|
||||||
runInAction(() => {
|
runInAction(() => {
|
||||||
|
@ -491,7 +491,7 @@ class FileManagerState {
|
||||||
clearInterval(intervalId);
|
clearInterval(intervalId);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
global.showErrorDialog(e instanceof Error ? e.message : `${e}`);
|
globalState.showErrorDialog(e instanceof Error ? e.message : `${e}`);
|
||||||
} finally {
|
} finally {
|
||||||
sync.dispose();
|
sync.dispose();
|
||||||
this.loadFiles();
|
this.loadFiles();
|
||||||
|
@ -566,7 +566,7 @@ const FileManager: NextPage = (): JSX.Element | null => {
|
||||||
|
|
||||||
const [previewUrl, setPreviewUrl] = useState<string | undefined>();
|
const [previewUrl, setPreviewUrl] = useState<string | undefined>();
|
||||||
const previewImage = useCallback(async (path: string) => {
|
const previewImage = useCallback(async (path: string) => {
|
||||||
const sync = await global.device!.sync();
|
const sync = await globalState.device!.sync();
|
||||||
try {
|
try {
|
||||||
const readableStream = createReadableStreamFromBufferIterator(sync.read(path));
|
const readableStream = createReadableStreamFromBufferIterator(sync.read(path));
|
||||||
const response = new Response(readableStream);
|
const response = new Response(readableStream);
|
||||||
|
|
|
@ -6,7 +6,7 @@ import { NextPage } from "next";
|
||||||
import Head from "next/head";
|
import Head from "next/head";
|
||||||
import React, { useCallback, useEffect, useRef } from 'react';
|
import React, { useCallback, useEffect, useRef } from 'react';
|
||||||
import { CommandBar, DemoMode, DeviceView } from '../components';
|
import { CommandBar, DemoMode, DeviceView } from '../components';
|
||||||
import { global } from "../state";
|
import { globalState } from "../state";
|
||||||
import { Icons, RouteStackProps } from "../utils";
|
import { Icons, RouteStackProps } from "../utils";
|
||||||
|
|
||||||
class FrameBufferState {
|
class FrameBufferState {
|
||||||
|
@ -38,15 +38,15 @@ const FrameBuffer: NextPage = (): JSX.Element | null => {
|
||||||
const canvasRef = useRef<HTMLCanvasElement | null>(null);
|
const canvasRef = useRef<HTMLCanvasElement | null>(null);
|
||||||
|
|
||||||
const capture = useCallback(async () => {
|
const capture = useCallback(async () => {
|
||||||
if (!global.device) {
|
if (!globalState.device) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const framebuffer = await global.device.framebuffer();
|
const framebuffer = await globalState.device.framebuffer();
|
||||||
state.setImage(framebuffer);
|
state.setImage(framebuffer);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
global.showErrorDialog(e instanceof Error ? e.message : `${e}`);
|
globalState.showErrorDialog(e instanceof Error ? e.message : `${e}`);
|
||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
@ -65,7 +65,7 @@ const FrameBuffer: NextPage = (): JSX.Element | null => {
|
||||||
const commandBarItems = computed(() => [
|
const commandBarItems = computed(() => [
|
||||||
{
|
{
|
||||||
key: 'start',
|
key: 'start',
|
||||||
disabled: !global.device,
|
disabled: !globalState.device,
|
||||||
iconProps: { iconName: Icons.Camera, style: { height: 20, fontSize: 20, lineHeight: 1.5 } },
|
iconProps: { iconName: Icons.Camera, style: { height: 20, fontSize: 20, lineHeight: 1.5 } },
|
||||||
text: 'Capture',
|
text: 'Capture',
|
||||||
onClick: capture,
|
onClick: capture,
|
||||||
|
@ -84,7 +84,7 @@ const FrameBuffer: NextPage = (): JSX.Element | null => {
|
||||||
const url = canvas.toDataURL();
|
const url = canvas.toDataURL();
|
||||||
const a = document.createElement('a');
|
const a = document.createElement('a');
|
||||||
a.href = url;
|
a.href = url;
|
||||||
a.download = `Screenshot of ${global.device!.name}.png`;
|
a.download = `Screenshot of ${globalState.device!.name}.png`;
|
||||||
a.click();
|
a.click();
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -5,7 +5,7 @@ import { observer } from "mobx-react-lite";
|
||||||
import { NextPage } from "next";
|
import { NextPage } from "next";
|
||||||
import Head from "next/head";
|
import Head from "next/head";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { global } from "../state";
|
import { globalState } from "../state";
|
||||||
import { chunkFile, pickFile, RouteStackProps } from "../utils";
|
import { chunkFile, pickFile, RouteStackProps } from "../utils";
|
||||||
|
|
||||||
enum Stage {
|
enum Stage {
|
||||||
|
@ -57,7 +57,7 @@ class InstallPageState {
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
await global.device!.install(chunkFile(file, AdbSyncMaxPacketSize), uploaded => {
|
await globalState.device!.install(chunkFile(file, AdbSyncMaxPacketSize), uploaded => {
|
||||||
runInAction(() => {
|
runInAction(() => {
|
||||||
if (uploaded !== file.size) {
|
if (uploaded !== file.size) {
|
||||||
this.progress = {
|
this.progress = {
|
||||||
|
@ -103,7 +103,7 @@ const Install: NextPage = () => {
|
||||||
|
|
||||||
<Stack horizontal>
|
<Stack horizontal>
|
||||||
<DefaultButton
|
<DefaultButton
|
||||||
disabled={!global.device || state.installing}
|
disabled={!globalState.device || state.installing}
|
||||||
text="Open"
|
text="Open"
|
||||||
onClick={state.install}
|
onClick={state.install}
|
||||||
/>
|
/>
|
||||||
|
|
48
apps/demo/pages/power.tsx
Normal file
48
apps/demo/pages/power.tsx
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
import { DefaultButton, Icon, MessageBar, TooltipHost } from "@fluentui/react";
|
||||||
|
import { observer } from "mobx-react-lite";
|
||||||
|
import { NextPage } from "next";
|
||||||
|
import { globalState } from "../state";
|
||||||
|
import { Icons } from "../utils";
|
||||||
|
|
||||||
|
const Power: NextPage = () => {
|
||||||
|
return (
|
||||||
|
<div style={{ padding: 20 }}>
|
||||||
|
<div>
|
||||||
|
<DefaultButton text="Reboot" disabled={!globalState.device} onClick={() => globalState.device!.power.reboot()} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style={{ marginTop: 20 }}>
|
||||||
|
<DefaultButton text="Reboot to Bootloader" disabled={!globalState.device} onClick={() => globalState.device!.power.bootloader()} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style={{ marginTop: 20 }}>
|
||||||
|
<DefaultButton text="Reboot to Fastboot" disabled={!globalState.device} onClick={() => globalState.device!.power.fastboot()} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style={{ marginTop: 20 }}>
|
||||||
|
<DefaultButton text="Reboot to Recovery" disabled={!globalState.device} onClick={() => globalState.device!.power.recovery()} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style={{ marginTop: 20 }}>
|
||||||
|
<DefaultButton text="Reboot to Sideload" disabled={!globalState.device} onClick={() => globalState.device!.power.sideload()} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style={{ marginTop: 20 }}>
|
||||||
|
<DefaultButton text="Reboot to Qualcomm EDL Mode" disabled={!globalState.device} onClick={() => globalState.device!.power.qualcommEdlMode()} />
|
||||||
|
<TooltipHost content={<span>Only works on some Qualcomm devices.</span>}>
|
||||||
|
<Icon style={{ verticalAlign: 'middle', marginLeft: 4, fontSize: 18 }} iconName={Icons.Info} />
|
||||||
|
</TooltipHost>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style={{ marginTop: 20 }}>
|
||||||
|
<DefaultButton text="Power Off" disabled={!globalState.device} onClick={() => globalState.device!.power.powerOff()} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style={{ marginTop: 20 }}>
|
||||||
|
<DefaultButton text="Press Power Button" disabled={!globalState.device} onClick={() => globalState.device!.power.powerButton()} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default observer(Power);
|
|
@ -8,7 +8,7 @@ import { NextPage } from "next";
|
||||||
import Head from "next/head";
|
import Head from "next/head";
|
||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import { DemoMode, DeviceView, DeviceViewRef, ExternalLink } from "../components";
|
import { DemoMode, DeviceView, DeviceViewRef, ExternalLink } from "../components";
|
||||||
import { global } from "../state";
|
import { globalState } from "../state";
|
||||||
import { CommonStackTokens, formatSpeed, Icons, RouteStackProps } from "../utils";
|
import { CommonStackTokens, formatSpeed, Icons, RouteStackProps } from "../utils";
|
||||||
import SCRCPY_SERVER_VERSION from '@yume-chan/scrcpy/bin/version';
|
import SCRCPY_SERVER_VERSION from '@yume-chan/scrcpy/bin/version';
|
||||||
|
|
||||||
|
@ -201,7 +201,7 @@ class ScrcpyPageState {
|
||||||
if (!this.running) {
|
if (!this.running) {
|
||||||
result.push({
|
result.push({
|
||||||
key: 'start',
|
key: 'start',
|
||||||
disabled: !global.device,
|
disabled: !globalState.device,
|
||||||
iconProps: { iconName: Icons.Play },
|
iconProps: { iconName: Icons.Play },
|
||||||
text: 'Start',
|
text: 'Start',
|
||||||
onClick: this.start as VoidFunction,
|
onClick: this.start as VoidFunction,
|
||||||
|
@ -310,7 +310,7 @@ class ScrcpyPageState {
|
||||||
});
|
});
|
||||||
|
|
||||||
autorun(() => {
|
autorun(() => {
|
||||||
if (global.device) {
|
if (globalState.device) {
|
||||||
runInAction(() => {
|
runInAction(() => {
|
||||||
this.encoders = [];
|
this.encoders = [];
|
||||||
this.selectedEncoder = undefined;
|
this.selectedEncoder = undefined;
|
||||||
|
@ -351,7 +351,7 @@ class ScrcpyPageState {
|
||||||
}
|
}
|
||||||
|
|
||||||
start = async () => {
|
start = async () => {
|
||||||
if (!global.device) {
|
if (!globalState.device) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -395,7 +395,7 @@ class ScrcpyPageState {
|
||||||
}), 1000);
|
}), 1000);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await pushServer(global.device, serverBuffer, {
|
await pushServer(globalState.device, serverBuffer, {
|
||||||
onProgress: action((progress) => {
|
onProgress: action((progress) => {
|
||||||
this.serverUploadedSize = progress;
|
this.serverUploadedSize = progress;
|
||||||
}),
|
}),
|
||||||
|
@ -409,7 +409,7 @@ class ScrcpyPageState {
|
||||||
}
|
}
|
||||||
|
|
||||||
const encoders = await ScrcpyClient.getEncoders(
|
const encoders = await ScrcpyClient.getEncoders(
|
||||||
global.device,
|
globalState.device,
|
||||||
DEFAULT_SERVER_PATH,
|
DEFAULT_SERVER_PATH,
|
||||||
SCRCPY_SERVER_VERSION,
|
SCRCPY_SERVER_VERSION,
|
||||||
new ScrcpyOptions1_21({
|
new ScrcpyOptions1_21({
|
||||||
|
@ -428,7 +428,7 @@ class ScrcpyPageState {
|
||||||
|
|
||||||
// Run scrcpy once will delete the server file
|
// Run scrcpy once will delete the server file
|
||||||
// Re-push it
|
// Re-push it
|
||||||
await pushServer(global.device, serverBuffer);
|
await pushServer(globalState.device, serverBuffer);
|
||||||
|
|
||||||
const factory = this.selectedDecoder.factory;
|
const factory = this.selectedDecoder.factory;
|
||||||
const decoder = new factory();
|
const decoder = new factory();
|
||||||
|
@ -436,7 +436,7 @@ class ScrcpyPageState {
|
||||||
this.decoder = decoder;
|
this.decoder = decoder;
|
||||||
});
|
});
|
||||||
|
|
||||||
const client = new ScrcpyClient(global.device);
|
const client = new ScrcpyClient(globalState.device);
|
||||||
runInAction(() => this.log = []);
|
runInAction(() => this.log = []);
|
||||||
client.onOutput(action(line => this.log.push(line)));
|
client.onOutput(action(line => this.log.push(line)));
|
||||||
client.onClose(this.stop);
|
client.onClose(this.stop);
|
||||||
|
@ -487,7 +487,7 @@ class ScrcpyPageState {
|
||||||
this.running = true;
|
this.running = true;
|
||||||
});
|
});
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
global.showErrorDialog(e.message);
|
globalState.showErrorDialog(e.message);
|
||||||
} finally {
|
} finally {
|
||||||
runInAction(() => {
|
runInAction(() => {
|
||||||
this.connecting = false;
|
this.connecting = false;
|
||||||
|
|
|
@ -5,7 +5,7 @@ import { NextPage } from "next";
|
||||||
import Head from "next/head";
|
import Head from "next/head";
|
||||||
import React, { CSSProperties, useCallback, useEffect, useRef, useState } from 'react';
|
import React, { CSSProperties, useCallback, useEffect, useRef, useState } from 'react';
|
||||||
import 'xterm/css/xterm.css';
|
import 'xterm/css/xterm.css';
|
||||||
import { global } from "../state";
|
import { globalState } from "../state";
|
||||||
import { Icons, ResizeObserver, RouteStackProps } from '../utils';
|
import { Icons, ResizeObserver, RouteStackProps } from '../utils';
|
||||||
|
|
||||||
let terminal: import('../components/terminal').AdbTerminal;
|
let terminal: import('../components/terminal').AdbTerminal;
|
||||||
|
@ -40,9 +40,9 @@ const Shell: NextPage = (): JSX.Element | null => {
|
||||||
const connectingRef = useRef(false);
|
const connectingRef = useRef(false);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
return reaction(
|
return reaction(
|
||||||
() => global.device,
|
() => globalState.device,
|
||||||
async () => {
|
async () => {
|
||||||
if (!global.device) {
|
if (!globalState.device) {
|
||||||
terminal.socket = undefined;
|
terminal.socket = undefined;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -53,10 +53,10 @@ const Shell: NextPage = (): JSX.Element | null => {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
connectingRef.current = true;
|
connectingRef.current = true;
|
||||||
const socket = await global.device.childProcess.shell();
|
const socket = await globalState.device.childProcess.shell();
|
||||||
terminal.socket = socket;
|
terminal.socket = socket;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
global.showErrorDialog(e instanceof Error ? e.message : `${e}`);
|
globalState.showErrorDialog(e instanceof Error ? e.message : `${e}`);
|
||||||
} finally {
|
} finally {
|
||||||
connectingRef.current = false;
|
connectingRef.current = false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ import { NextPage } from "next";
|
||||||
import Head from "next/head";
|
import Head from "next/head";
|
||||||
import React, { useCallback, useEffect } from "react";
|
import React, { useCallback, useEffect } from "react";
|
||||||
import { ExternalLink } from "../components";
|
import { ExternalLink } from "../components";
|
||||||
import { global } from "../state";
|
import { globalState } from "../state";
|
||||||
import { asyncEffect, Icons, RouteStackProps } from "../utils";
|
import { asyncEffect, Icons, RouteStackProps } from "../utils";
|
||||||
|
|
||||||
class TcpIpState {
|
class TcpIpState {
|
||||||
|
@ -26,7 +26,7 @@ class TcpIpState {
|
||||||
|
|
||||||
|
|
||||||
autorun(() => {
|
autorun(() => {
|
||||||
if (global.device) {
|
if (globalState.device) {
|
||||||
if (this.initial && this.visible) {
|
if (this.initial && this.visible) {
|
||||||
this.initial = false;
|
this.initial = false;
|
||||||
this.queryInfo();
|
this.queryInfo();
|
||||||
|
@ -41,14 +41,14 @@ class TcpIpState {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
key: 'refresh',
|
key: 'refresh',
|
||||||
disabled: !global.device,
|
disabled: !globalState.device,
|
||||||
iconProps: { iconName: Icons.ArrowClockwise },
|
iconProps: { iconName: Icons.ArrowClockwise },
|
||||||
text: 'Refresh',
|
text: 'Refresh',
|
||||||
onClick: this.queryInfo as VoidFunction,
|
onClick: this.queryInfo as VoidFunction,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'apply',
|
key: 'apply',
|
||||||
disabled: !global.device,
|
disabled: !globalState.device,
|
||||||
iconProps: { iconName: Icons.Save },
|
iconProps: { iconName: Icons.Save },
|
||||||
text: 'Apply',
|
text: 'Apply',
|
||||||
onClick: this.applyServicePort,
|
onClick: this.applyServicePort,
|
||||||
|
@ -57,7 +57,7 @@ class TcpIpState {
|
||||||
}
|
}
|
||||||
|
|
||||||
queryInfo = asyncEffect(async (signal) => {
|
queryInfo = asyncEffect(async (signal) => {
|
||||||
if (!global.device) {
|
if (!globalState.device) {
|
||||||
runInAction(() => {
|
runInAction(() => {
|
||||||
this.serviceListenAddresses = undefined;
|
this.serviceListenAddresses = undefined;
|
||||||
this.servicePortEnabled = false;
|
this.servicePortEnabled = false;
|
||||||
|
@ -68,9 +68,9 @@ class TcpIpState {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const serviceListenAddresses = await global.device.getProp('service.adb.listen_addrs');
|
const serviceListenAddresses = await globalState.device.getProp('service.adb.listen_addrs');
|
||||||
const servicePort = await global.device.getProp('service.adb.tcp.port');
|
const servicePort = await globalState.device.getProp('service.adb.tcp.port');
|
||||||
const persistPort = await global.device.getProp('persist.adb.tcp.port');
|
const persistPort = await globalState.device.getProp('persist.adb.tcp.port');
|
||||||
|
|
||||||
if (signal.aborted) {
|
if (signal.aborted) {
|
||||||
return;
|
return;
|
||||||
|
@ -98,14 +98,14 @@ class TcpIpState {
|
||||||
});
|
});
|
||||||
|
|
||||||
applyServicePort = async () => {
|
applyServicePort = async () => {
|
||||||
if (!global.device) {
|
if (!globalState.device) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state.servicePortEnabled) {
|
if (state.servicePortEnabled) {
|
||||||
await global.device.tcpip.setPort(Number.parseInt(state.servicePort, 10));
|
await globalState.device.tcpip.setPort(Number.parseInt(state.servicePort, 10));
|
||||||
} else {
|
} else {
|
||||||
await global.device.tcpip.disable();
|
await globalState.device.tcpip.disable();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -183,12 +183,12 @@ const TcpIp: NextPage = () => {
|
||||||
inlineLabel
|
inlineLabel
|
||||||
label="service.adb.tcp.port"
|
label="service.adb.tcp.port"
|
||||||
checked={state.servicePortEnabled}
|
checked={state.servicePortEnabled}
|
||||||
disabled={!global.device || !!state.serviceListenAddresses}
|
disabled={!globalState.device || !!state.serviceListenAddresses}
|
||||||
onText="Enabled"
|
onText="Enabled"
|
||||||
offText="Disabled"
|
offText="Disabled"
|
||||||
onChange={handleServicePortEnabledChange}
|
onChange={handleServicePortEnabledChange}
|
||||||
/>
|
/>
|
||||||
{global && (
|
{globalState && (
|
||||||
<TextField
|
<TextField
|
||||||
disabled={!!state.serviceListenAddresses}
|
disabled={!!state.serviceListenAddresses}
|
||||||
value={state.servicePort}
|
value={state.servicePort}
|
||||||
|
|
|
@ -36,4 +36,4 @@ export class GlobalState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const global = new GlobalState();
|
export const globalState = new GlobalState();
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { registerIcons } from "@fluentui/react";
|
import { registerIcons } from "@fluentui/react";
|
||||||
import { MoreHorizontalRegular, AddCircleRegular, ArrowClockwiseRegular, ArrowSortDownRegular, ArrowSortUpRegular, BookmarkRegular, BoxRegular, CameraRegular, CheckmarkRegular, ChevronDownRegular, ChevronRightRegular, ChevronUpRegular, CircleRegular, CloudArrowDownRegular, CloudArrowUpRegular, CopyRegular, DeleteRegular, DocumentRegular, FolderRegular, FullScreenMaximizeRegular, InfoRegular, NavigationRegular, PersonFeedbackRegular, PhoneLaptopRegular, PhoneRegular, PlayRegular, PlugConnectedRegular, PlugDisconnectedRegular, SaveRegular, SearchRegular, SettingsRegular, StopRegular, TextGrammarErrorRegular, WandRegular, WifiSettingsRegular, WindowConsoleRegular } from '@fluentui/react-icons';
|
import { AddCircleRegular, ArrowClockwiseRegular, ArrowSortDownRegular, ArrowSortUpRegular, BookmarkRegular, BoxRegular, CameraRegular, CheckmarkRegular, ChevronDownRegular, ChevronRightRegular, ChevronUpRegular, CircleRegular, CloudArrowDownRegular, CloudArrowUpRegular, CopyRegular, DeleteRegular, DocumentRegular, FolderRegular, FullScreenMaximizeRegular, InfoRegular, MoreHorizontalRegular, NavigationRegular, PersonFeedbackRegular, PhoneLaptopRegular, PhoneRegular, PlayRegular, PlugConnectedRegular, PlugDisconnectedRegular, PowerRegular, SaveRegular, SearchRegular, SettingsRegular, StopRegular, TextGrammarErrorRegular, WandRegular, WifiSettingsRegular, WindowConsoleRegular } from '@fluentui/react-icons';
|
||||||
|
|
||||||
const STYLE = {};
|
const STYLE = {};
|
||||||
|
|
||||||
|
@ -30,6 +30,7 @@ export function register() {
|
||||||
Play: <PlayRegular style={STYLE} />,
|
Play: <PlayRegular style={STYLE} />,
|
||||||
PlugConnected: <PlugConnectedRegular style={STYLE} />,
|
PlugConnected: <PlugConnectedRegular style={STYLE} />,
|
||||||
PlugDisconnected: <PlugDisconnectedRegular style={STYLE} />,
|
PlugDisconnected: <PlugDisconnectedRegular style={STYLE} />,
|
||||||
|
Power: <PowerRegular style={STYLE} />,
|
||||||
Save: <SaveRegular style={STYLE} />,
|
Save: <SaveRegular style={STYLE} />,
|
||||||
Settings: <SettingsRegular style={STYLE} />,
|
Settings: <SettingsRegular style={STYLE} />,
|
||||||
Stop: <StopRegular style={STYLE} />,
|
Stop: <StopRegular style={STYLE} />,
|
||||||
|
@ -77,6 +78,7 @@ export default {
|
||||||
Play: 'Play',
|
Play: 'Play',
|
||||||
PlugConnected: 'PlugConnected',
|
PlugConnected: 'PlugConnected',
|
||||||
PlugDisconnected: 'PlugDisconnected',
|
PlugDisconnected: 'PlugDisconnected',
|
||||||
|
Power: 'Power',
|
||||||
Save: 'Save',
|
Save: 'Save',
|
||||||
Settings: 'Settings',
|
Settings: 'Settings',
|
||||||
Stop: 'Stop',
|
Stop: 'Stop',
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { PromiseResolver } from '@yume-chan/async';
|
||||||
import { DisposableList } from '@yume-chan/event';
|
import { DisposableList } from '@yume-chan/event';
|
||||||
import { AdbAuthenticationHandler, AdbCredentialStore, AdbDefaultAuthenticators } from './auth';
|
import { AdbAuthenticationHandler, AdbCredentialStore, AdbDefaultAuthenticators } from './auth';
|
||||||
import { AdbBackend } from './backend';
|
import { AdbBackend } from './backend';
|
||||||
import { AdbChildProcess, AdbDemoMode, AdbFrameBuffer, AdbReverseCommand, AdbSync, AdbTcpIpCommand, escapeArg, framebuffer, install } from './commands';
|
import { AdbChildProcess, AdbDemoMode, AdbFrameBuffer, AdbPower, AdbReverseCommand, AdbSync, AdbTcpIpCommand, escapeArg, framebuffer, install } from './commands';
|
||||||
import { AdbFeatures } from './features';
|
import { AdbFeatures } from './features';
|
||||||
import { AdbCommand } from './packet';
|
import { AdbCommand } from './packet';
|
||||||
import { AdbLogger, AdbPacketDispatcher, AdbSocket } from './socket';
|
import { AdbLogger, AdbPacketDispatcher, AdbSocket } from './socket';
|
||||||
|
@ -44,22 +44,21 @@ export class Adb {
|
||||||
private _features: AdbFeatures[] | undefined;
|
private _features: AdbFeatures[] | undefined;
|
||||||
public get features() { return this._features; }
|
public get features() { return this._features; }
|
||||||
|
|
||||||
public readonly tcpip: AdbTcpIpCommand;
|
|
||||||
|
|
||||||
public readonly reverse: AdbReverseCommand;
|
|
||||||
|
|
||||||
public readonly demoMode: AdbDemoMode;
|
|
||||||
|
|
||||||
public readonly childProcess: AdbChildProcess;
|
public readonly childProcess: AdbChildProcess;
|
||||||
|
public readonly demoMode: AdbDemoMode;
|
||||||
|
public readonly power: AdbPower;
|
||||||
|
public readonly reverse: AdbReverseCommand;
|
||||||
|
public readonly tcpip: AdbTcpIpCommand;
|
||||||
|
|
||||||
public constructor(backend: AdbBackend, logger?: AdbLogger) {
|
public constructor(backend: AdbBackend, logger?: AdbLogger) {
|
||||||
this._backend = backend;
|
this._backend = backend;
|
||||||
this.packetDispatcher = new AdbPacketDispatcher(backend, logger);
|
this.packetDispatcher = new AdbPacketDispatcher(backend, logger);
|
||||||
|
|
||||||
this.tcpip = new AdbTcpIpCommand(this);
|
|
||||||
this.reverse = new AdbReverseCommand(this.packetDispatcher);
|
|
||||||
this.demoMode = new AdbDemoMode(this);
|
|
||||||
this.childProcess = new AdbChildProcess(this);
|
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);
|
||||||
|
|
||||||
backend.onDisconnected(this.dispose, this);
|
backend.onDisconnected(this.dispose, this);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ export * from './base';
|
||||||
export * from './demo-mode';
|
export * from './demo-mode';
|
||||||
export * from './framebuffer';
|
export * from './framebuffer';
|
||||||
export * from './install';
|
export * from './install';
|
||||||
|
export * from './power';
|
||||||
export * from './reverse';
|
export * from './reverse';
|
||||||
export * from './shell';
|
export * from './shell';
|
||||||
export * from './sync';
|
export * from './sync';
|
||||||
|
|
35
libraries/adb/src/commands/power.ts
Normal file
35
libraries/adb/src/commands/power.ts
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
import { AdbCommandBase } from "./base";
|
||||||
|
|
||||||
|
export class AdbPower extends AdbCommandBase {
|
||||||
|
public reboot(name: string = '') {
|
||||||
|
return this.adb.createSocketAndReadAll(`reboot:${name}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bootloader() {
|
||||||
|
return this.reboot('bootloader');
|
||||||
|
}
|
||||||
|
|
||||||
|
public fastboot() {
|
||||||
|
return this.reboot('fastboot');
|
||||||
|
}
|
||||||
|
|
||||||
|
public recovery() {
|
||||||
|
return this.reboot('recovery');
|
||||||
|
}
|
||||||
|
|
||||||
|
public sideload() {
|
||||||
|
return this.reboot('sideload');
|
||||||
|
}
|
||||||
|
|
||||||
|
public qualcommEdlMode() {
|
||||||
|
return this.reboot('edl');
|
||||||
|
}
|
||||||
|
|
||||||
|
public powerOff() {
|
||||||
|
return this.adb.childProcess.exec('reboot', '-p');
|
||||||
|
}
|
||||||
|
|
||||||
|
public powerButton(longPress: boolean = false) {
|
||||||
|
return this.adb.childProcess.exec('input', 'keyevent', longPress ? '--longpress POWER' : 'POWER');
|
||||||
|
}
|
||||||
|
}
|
|
@ -51,7 +51,7 @@ export class AdbReverseCommand extends AutoDisposable {
|
||||||
}
|
}
|
||||||
|
|
||||||
const address = decodeUtf8(e.packet.payload!);
|
const address = decodeUtf8(e.packet.payload!);
|
||||||
// tcp:1234\0
|
// tcp:12345\0
|
||||||
const port = Number.parseInt(address.substring(4));
|
const port = Number.parseInt(address.substring(4));
|
||||||
if (this.localPortToHandler.has(port)) {
|
if (this.localPortToHandler.has(port)) {
|
||||||
this.localPortToHandler.get(port)!.onSocket(e.packet, e.socket);
|
this.localPortToHandler.get(port)!.onSocket(e.packet, e.socket);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue