microsoft/vscode-react-native

Public

mirrored from https://github.com/microsoft/vscode-react-nativeAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
0.6.15

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

src/extension/android/adb.ts

208lines · modeblame

52f3873ddigeff10 years ago1// Copyright (c) Microsoft Corporation. All rights reserved.
2// Licensed under the MIT license. See LICENSE file in the project root for details.
3
4import * as Q from "q";
5
43e1a996Ruslan Bikkinin7 years ago6import { ChildProcess, ISpawnResult } from "../../common/node/childProcess";
7import { CommandExecutor } from "../../common/commandExecutor";
8import * as path from "path";
9import * as fs from "fs";
10import { ILogger } from "../log/LogHelper";
52f3873ddigeff10 years ago11
ce7fd946digeff10 years ago12// See android versions usage at: http://developer.android.com/about/dashboards/index.html
52f3873ddigeff10 years ago13export enum AndroidAPILevel {
ce7fd946digeff10 years ago14Marshmallow = 23,
52f3873ddigeff10 years ago15LOLLIPOP_MR1 = 22,
16LOLLIPOP = 21, /* Supports adb reverse */
17KITKAT = 19,
18JELLY_BEAN_MR2 = 18,
19JELLY_BEAN_MR1 = 17,
20JELLY_BEAN = 16,
21ICE_CREAM_SANDWICH_MR1 = 15,
22GINGERBREAD_MR1 = 10,
23}
24
7daed3fcArtem Egorov8 years ago25enum KeyEvents {
26KEYCODE_BACK = 4,
27KEYCODE_DPAD_UP = 19,
28KEYCODE_DPAD_DOWN = 20,
29KEYCODE_DPAD_CENTER = 23,
30KEYCODE_MENU = 82,
31}
32
52f3873ddigeff10 years ago33export enum DeviceType {
34AndroidSdkEmulator, // These seem to have emulator-<port> ids
27710197Vladimir Kotikov8 years ago35Other,
52f3873ddigeff10 years ago36}
37
38export interface IDevice {
39id: string;
40isOnline: boolean;
41type: DeviceType;
42}
43
7daed3fcArtem Egorov8 years ago44const AndroidSDKEmulatorPattern = /^emulator-\d{1,5}$/;
52f3873ddigeff10 years ago45
7daed3fcArtem Egorov8 years ago46export class AdbHelper {
43e1a996Ruslan Bikkinin7 years ago47private childProcess: ChildProcess = new ChildProcess();
48private commandExecutor: CommandExecutor = new CommandExecutor();
49private adbExecutable: string = "";
50
51constructor(projectRoot: string, logger?: ILogger) {
52
53// Trying to read sdk location from local.properties file and if we succueded then
54// we would run adb from inside it, otherwise we would rely to PATH
55const sdkLocation = this.getSdkLocationFromLocalPropertiesFile(projectRoot, logger);
56this.adbExecutable = sdkLocation ? `${path.join(sdkLocation, "platform-tools", "adb")}` : "adb";
57}
52f3873ddigeff10 years ago58
59/**
60* Gets the list of Android connected devices and emulators.
61*/
43e1a996Ruslan Bikkinin7 years ago62public getConnectedDevices(): Q.Promise<IDevice[]> {
63return this.childProcess.execToString(`${this.adbExecutable} devices`)
52f3873ddigeff10 years ago64.then(output => {
65return this.parseConnectedDevices(output);
66});
67}
68
69/**
70* Broadcasts an intent to reload the application in debug mode.
71*/
43e1a996Ruslan Bikkinin7 years ago72public switchDebugMode(projectRoot: string, packageName: string, enable: boolean, debugTarget?: string): Q.Promise<void> {
73let enableDebugCommand = `${this.adbExecutable} ${debugTarget ? "-s " + debugTarget : ""} shell am broadcast -a "${packageName}.RELOAD_APP_ACTION" --ez jsproxy ${enable}`;
b57ea017Artem Egorov8 years ago74return new CommandExecutor(projectRoot).execute(enableDebugCommand)
75.then(() => { // We should stop and start application again after RELOAD_APP_ACTION, otherwise app going to hangs up
76let deferred = Q.defer();
77setTimeout(() => {
78this.stopApp(projectRoot, packageName, debugTarget)
79.then(() => {
80return deferred.resolve({});
81});
82}, 200); // We need a little delay after broadcast command
83
84return deferred.promise;
85})
86.then(() => {
87return this.launchApp(projectRoot, packageName, debugTarget);
88});
52f3873ddigeff10 years ago89}
90
91/**
92* Sends an intent which launches the main activity of the application.
93*/
43e1a996Ruslan Bikkinin7 years ago94public launchApp(projectRoot: string, packageName: string, debugTarget?: string): Q.Promise<void> {
95let launchAppCommand = `${this.adbExecutable} ${debugTarget ? "-s " + debugTarget : ""} shell am start -n ${packageName}/.MainActivity`;
52f3873ddigeff10 years ago96return new CommandExecutor(projectRoot).execute(launchAppCommand);
97}
98
43e1a996Ruslan Bikkinin7 years ago99public stopApp(projectRoot: string, packageName: string, debugTarget?: string): Q.Promise<void> {
100let stopAppCommand = `${this.adbExecutable} ${debugTarget ? "-s " + debugTarget : ""} shell am force-stop ${packageName}`;
b57ea017Artem Egorov8 years ago101return new CommandExecutor(projectRoot).execute(stopAppCommand);
102}
103
43e1a996Ruslan Bikkinin7 years ago104public apiVersion(deviceId: string): Q.Promise<AndroidAPILevel> {
52f3873ddigeff10 years ago105return this.executeQuery(deviceId, "shell getprop ro.build.version.sdk").then(output =>
106parseInt(output, 10));
107}
108
43e1a996Ruslan Bikkinin7 years ago109public reverseAdb(deviceId: string, packagerPort: number): Q.Promise<void> {
b57ea017Artem Egorov8 years ago110return this.execute(deviceId, `reverse tcp:${packagerPort} tcp:${packagerPort}`);
52f3873ddigeff10 years ago111}
112
43e1a996Ruslan Bikkinin7 years ago113public showDevMenu(deviceId?: string): Q.Promise<void> {
114let command = `${this.adbExecutable} ${deviceId ? "-s " + deviceId : ""} shell input keyevent ${KeyEvents.KEYCODE_MENU}`;
7daed3fcArtem Egorov8 years ago115return this.commandExecutor.execute(command);
116}
117
43e1a996Ruslan Bikkinin7 years ago118public reloadApp(deviceId?: string): Q.Promise<void> {
7daed3fcArtem Egorov8 years ago119let commands = [
43e1a996Ruslan Bikkinin7 years ago120`${this.adbExecutable} ${deviceId ? "-s " + deviceId : ""} shell input keyevent ${KeyEvents.KEYCODE_MENU}`,
121`${this.adbExecutable} ${deviceId ? "-s " + deviceId : ""} shell input keyevent ${KeyEvents.KEYCODE_DPAD_UP}`,
122`${this.adbExecutable} ${deviceId ? "-s " + deviceId : ""} shell input keyevent ${KeyEvents.KEYCODE_DPAD_CENTER}`,
7daed3fcArtem Egorov8 years ago123];
124
125return this.executeChain(commands);
126}
127
43e1a996Ruslan Bikkinin7 years ago128public getOnlineDevices(): Q.Promise<IDevice[]> {
7daed3fcArtem Egorov8 years ago129return this.getConnectedDevices().then(devices => {
130return devices.filter(device =>
131device.isOnline);
132});
133}
134
43e1a996Ruslan Bikkinin7 years ago135public startLogCat(adbParameters: string[]): ISpawnResult {
136return new ChildProcess().spawn(`${this.adbExecutable}`, adbParameters);
137}
138
139private parseConnectedDevices(input: string): IDevice[] {
52f3873ddigeff10 years ago140let result: IDevice[] = [];
141let regex = new RegExp("^(\\S+)\\t(\\S+)$", "mg");
142let match = regex.exec(input);
143while (match != null) {
144result.push({ id: match[1], isOnline: match[2] === "device", type: this.extractDeviceType(match[1]) });
145match = regex.exec(input);
146}
147return result;
148}
149
43e1a996Ruslan Bikkinin7 years ago150private extractDeviceType(id: string): DeviceType {
52f3873ddigeff10 years ago151return id.match(AndroidSDKEmulatorPattern)
152? DeviceType.AndroidSdkEmulator
153: DeviceType.Other;
154}
155
43e1a996Ruslan Bikkinin7 years ago156private executeQuery(deviceId: string, command: string): Q.Promise<string> {
52f3873ddigeff10 years ago157return this.childProcess.execToString(this.generateCommandForDevice(deviceId, command));
158}
159
43e1a996Ruslan Bikkinin7 years ago160private execute(deviceId: string, command: string): Q.Promise<void> {
52f3873ddigeff10 years ago161return this.commandExecutor.execute(this.generateCommandForDevice(deviceId, command));
162}
163
43e1a996Ruslan Bikkinin7 years ago164private executeChain(commands: string[]): Q.Promise<any> {
7daed3fcArtem Egorov8 years ago165return commands.reduce((promise, command) => {
166return promise.then(() => this.commandExecutor.execute(command));
167}, Q(void 0));
168}
169
43e1a996Ruslan Bikkinin7 years ago170private generateCommandForDevice(deviceId: string, adbCommand: string): string {
171return `${this.adbExecutable} -s "${deviceId}" ${adbCommand}`;
172}
173
174private getSdkLocationFromLocalPropertiesFile(projectRoot: string, logger?: ILogger): string | null {
175const localPropertiesFilePath = path.join(projectRoot, "android", "local.properties");
176if (!fs.existsSync(localPropertiesFilePath)) {
177if (logger) {
178logger.info(`local.properties file doesn't exist. Using Android SDK location from PATH.`);
179}
180return null;
181}
182
183let fileContent;
184try {
185fileContent = fs.readFileSync(localPropertiesFilePath).toString();
186} catch (e) {
187if (logger) {
188logger.error(`Could read from ${localPropertiesFilePath}.`, e, e.stack);
189logger.info(`Using Android SDK location from PATH.`);
190}
191return null;
192}
193const matches = fileContent.match(/^sdk\.dir=(.+)$/m);
194if (!matches || !matches[1]) {
195if (logger) {
196logger.info(`No sdk.dir value found in local.properties file. Using Android SDK location from PATH.`);
197}
198return null;
199}
200
201const sdkLocation = matches[1].trim();
202if (logger) {
203logger.info(`Using Android SDK location defined in android/local.properties file: ${sdkLocation}.`);
204}
205
206return sdkLocation;
52f3873ddigeff10 years ago207}
208}