microsoft/vscode-react-native

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
0.9.3

Branches

Tags

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

Clone

HTTPS

Download ZIP

src/extension/android/adb.ts

219lines · 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
db6fd42aRuslan 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";
8b383051Ruslan Bikkinin7 years ago11import * as os from "os";
d7d405aeYuri Skorokhodov7 years ago12import * as nls from "vscode-nls";
13const localize = nls.loadMessageBundle();
52f3873ddigeff10 years ago14
ce7fd946digeff10 years ago15// See android versions usage at: http://developer.android.com/about/dashboards/index.html
52f3873ddigeff10 years ago16export enum AndroidAPILevel {
ce7fd946digeff10 years ago17Marshmallow = 23,
52f3873ddigeff10 years ago18LOLLIPOP_MR1 = 22,
19LOLLIPOP = 21, /* Supports adb reverse */
20KITKAT = 19,
21JELLY_BEAN_MR2 = 18,
22JELLY_BEAN_MR1 = 17,
23JELLY_BEAN = 16,
24ICE_CREAM_SANDWICH_MR1 = 15,
25GINGERBREAD_MR1 = 10,
26}
27
7daed3fcArtem Egorov8 years ago28enum KeyEvents {
29KEYCODE_BACK = 4,
30KEYCODE_DPAD_UP = 19,
31KEYCODE_DPAD_DOWN = 20,
32KEYCODE_DPAD_CENTER = 23,
33KEYCODE_MENU = 82,
34}
35
52f3873ddigeff10 years ago36export enum DeviceType {
37AndroidSdkEmulator, // These seem to have emulator-<port> ids
27710197Vladimir Kotikov8 years ago38Other,
52f3873ddigeff10 years ago39}
40
41export interface IDevice {
42id: string;
43isOnline: boolean;
44type: DeviceType;
45}
46
7daed3fcArtem Egorov8 years ago47const AndroidSDKEmulatorPattern = /^emulator-\d{1,5}$/;
52f3873ddigeff10 years ago48
7daed3fcArtem Egorov8 years ago49export class AdbHelper {
db6fd42aRuslan Bikkinin7 years ago50private childProcess: ChildProcess = new ChildProcess();
51private commandExecutor: CommandExecutor = new CommandExecutor();
52private adbExecutable: string = "";
53
54constructor(projectRoot: string, logger?: ILogger) {
55
56// Trying to read sdk location from local.properties file and if we succueded then
57// we would run adb from inside it, otherwise we would rely to PATH
58const sdkLocation = this.getSdkLocationFromLocalPropertiesFile(projectRoot, logger);
59this.adbExecutable = sdkLocation ? `${path.join(sdkLocation, "platform-tools", "adb")}` : "adb";
60}
52f3873ddigeff10 years ago61
62/**
63* Gets the list of Android connected devices and emulators.
64*/
db6fd42aRuslan Bikkinin7 years ago65public getConnectedDevices(): Q.Promise<IDevice[]> {
66return this.childProcess.execToString(`${this.adbExecutable} devices`)
52f3873ddigeff10 years ago67.then(output => {
68return this.parseConnectedDevices(output);
69});
70}
71
72/**
73* Broadcasts an intent to reload the application in debug mode.
74*/
db6fd42aRuslan Bikkinin7 years ago75public switchDebugMode(projectRoot: string, packageName: string, enable: boolean, debugTarget?: string): Q.Promise<void> {
76let enableDebugCommand = `${this.adbExecutable} ${debugTarget ? "-s " + debugTarget : ""} shell am broadcast -a "${packageName}.RELOAD_APP_ACTION" --ez jsproxy ${enable}`;
b57ea017Artem Egorov8 years ago77return new CommandExecutor(projectRoot).execute(enableDebugCommand)
78.then(() => { // We should stop and start application again after RELOAD_APP_ACTION, otherwise app going to hangs up
79let deferred = Q.defer();
80setTimeout(() => {
81this.stopApp(projectRoot, packageName, debugTarget)
82.then(() => {
83return deferred.resolve({});
84});
85}, 200); // We need a little delay after broadcast command
86
87return deferred.promise;
88})
89.then(() => {
90return this.launchApp(projectRoot, packageName, debugTarget);
91});
52f3873ddigeff10 years ago92}
93
94/**
95* Sends an intent which launches the main activity of the application.
96*/
db6fd42aRuslan Bikkinin7 years ago97public launchApp(projectRoot: string, packageName: string, debugTarget?: string): Q.Promise<void> {
98let launchAppCommand = `${this.adbExecutable} ${debugTarget ? "-s " + debugTarget : ""} shell am start -n ${packageName}/.MainActivity`;
52f3873ddigeff10 years ago99return new CommandExecutor(projectRoot).execute(launchAppCommand);
100}
101
db6fd42aRuslan Bikkinin7 years ago102public stopApp(projectRoot: string, packageName: string, debugTarget?: string): Q.Promise<void> {
103let stopAppCommand = `${this.adbExecutable} ${debugTarget ? "-s " + debugTarget : ""} shell am force-stop ${packageName}`;
b57ea017Artem Egorov8 years ago104return new CommandExecutor(projectRoot).execute(stopAppCommand);
105}
106
db6fd42aRuslan Bikkinin7 years ago107public apiVersion(deviceId: string): Q.Promise<AndroidAPILevel> {
52f3873ddigeff10 years ago108return this.executeQuery(deviceId, "shell getprop ro.build.version.sdk").then(output =>
109parseInt(output, 10));
110}
111
db6fd42aRuslan Bikkinin7 years ago112public reverseAdb(deviceId: string, packagerPort: number): Q.Promise<void> {
b57ea017Artem Egorov8 years ago113return this.execute(deviceId, `reverse tcp:${packagerPort} tcp:${packagerPort}`);
52f3873ddigeff10 years ago114}
115
db6fd42aRuslan Bikkinin7 years ago116public showDevMenu(deviceId?: string): Q.Promise<void> {
117let command = `${this.adbExecutable} ${deviceId ? "-s " + deviceId : ""} shell input keyevent ${KeyEvents.KEYCODE_MENU}`;
7daed3fcArtem Egorov8 years ago118return this.commandExecutor.execute(command);
119}
120
db6fd42aRuslan Bikkinin7 years ago121public reloadApp(deviceId?: string): Q.Promise<void> {
7daed3fcArtem Egorov8 years ago122let commands = [
db6fd42aRuslan Bikkinin7 years ago123`${this.adbExecutable} ${deviceId ? "-s " + deviceId : ""} shell input keyevent ${KeyEvents.KEYCODE_MENU}`,
124`${this.adbExecutable} ${deviceId ? "-s " + deviceId : ""} shell input keyevent ${KeyEvents.KEYCODE_DPAD_UP}`,
125`${this.adbExecutable} ${deviceId ? "-s " + deviceId : ""} shell input keyevent ${KeyEvents.KEYCODE_DPAD_CENTER}`,
7daed3fcArtem Egorov8 years ago126];
127
128return this.executeChain(commands);
129}
130
db6fd42aRuslan Bikkinin7 years ago131public getOnlineDevices(): Q.Promise<IDevice[]> {
7daed3fcArtem Egorov8 years ago132return this.getConnectedDevices().then(devices => {
133return devices.filter(device =>
134device.isOnline);
135});
136}
137
db6fd42aRuslan Bikkinin7 years ago138public startLogCat(adbParameters: string[]): ISpawnResult {
139return new ChildProcess().spawn(`${this.adbExecutable}`, adbParameters);
140}
141
8b383051Ruslan Bikkinin7 years ago142public parseSdkLocation(fileContent: string, logger?: ILogger) {
143const matches = fileContent.match(/^sdk\.dir=(.+)$/m);
144if (!matches || !matches[1]) {
145if (logger) {
d7d405aeYuri Skorokhodov7 years ago146logger.info(localize("NoSdkDirFoundInLocalPropertiesFile", "No sdk.dir value found in local.properties file. Using Android SDK location from PATH."));
8b383051Ruslan Bikkinin7 years ago147}
148return null;
149}
150
151let sdkLocation = matches[1].trim();
152if (os.platform() === "win32") {
153// For Windows we need to unescape files separators and drive letter separators
154sdkLocation = sdkLocation.replace(/\\\\/g, "\\").replace("\\:", ":");
155}
156if (logger) {
d7d405aeYuri Skorokhodov7 years ago157logger.info(localize("UsindAndroidSDKLocationDefinedInLocalPropertiesFile", "Using Android SDK location defined in android/local.properties file: {0}.", sdkLocation));
8b383051Ruslan Bikkinin7 years ago158}
159
160return sdkLocation;
161}
162
db6fd42aRuslan Bikkinin7 years ago163private parseConnectedDevices(input: string): IDevice[] {
52f3873ddigeff10 years ago164let result: IDevice[] = [];
165let regex = new RegExp("^(\\S+)\\t(\\S+)$", "mg");
166let match = regex.exec(input);
167while (match != null) {
168result.push({ id: match[1], isOnline: match[2] === "device", type: this.extractDeviceType(match[1]) });
169match = regex.exec(input);
170}
171return result;
172}
173
db6fd42aRuslan Bikkinin7 years ago174private extractDeviceType(id: string): DeviceType {
52f3873ddigeff10 years ago175return id.match(AndroidSDKEmulatorPattern)
176? DeviceType.AndroidSdkEmulator
177: DeviceType.Other;
178}
179
db6fd42aRuslan Bikkinin7 years ago180private executeQuery(deviceId: string, command: string): Q.Promise<string> {
52f3873ddigeff10 years ago181return this.childProcess.execToString(this.generateCommandForDevice(deviceId, command));
182}
183
db6fd42aRuslan Bikkinin7 years ago184private execute(deviceId: string, command: string): Q.Promise<void> {
52f3873ddigeff10 years ago185return this.commandExecutor.execute(this.generateCommandForDevice(deviceId, command));
186}
187
db6fd42aRuslan Bikkinin7 years ago188private executeChain(commands: string[]): Q.Promise<any> {
7daed3fcArtem Egorov8 years ago189return commands.reduce((promise, command) => {
190return promise.then(() => this.commandExecutor.execute(command));
191}, Q(void 0));
192}
193
db6fd42aRuslan Bikkinin7 years ago194private generateCommandForDevice(deviceId: string, adbCommand: string): string {
195return `${this.adbExecutable} -s "${deviceId}" ${adbCommand}`;
196}
197
198private getSdkLocationFromLocalPropertiesFile(projectRoot: string, logger?: ILogger): string | null {
199const localPropertiesFilePath = path.join(projectRoot, "android", "local.properties");
200if (!fs.existsSync(localPropertiesFilePath)) {
201if (logger) {
d7d405aeYuri Skorokhodov7 years ago202logger.info(localize("LocalPropertiesFileDoesNotExist", "local.properties file doesn't exist. Using Android SDK location from PATH."));
db6fd42aRuslan Bikkinin7 years ago203}
204return null;
205}
206
8b383051Ruslan Bikkinin7 years ago207let fileContent: string;
db6fd42aRuslan Bikkinin7 years ago208try {
209fileContent = fs.readFileSync(localPropertiesFilePath).toString();
210} catch (e) {
211if (logger) {
d7d405aeYuri Skorokhodov7 years ago212logger.error(localize("CouldNotReadFrom", "Couldn't read from {0}.", localPropertiesFilePath), e, e.stack);
213logger.info(localize("UsingAndroidSDKLocationFromPATH", "Using Android SDK location from PATH."));
db6fd42aRuslan Bikkinin7 years ago214}
215return null;
216}
8b383051Ruslan Bikkinin7 years ago217return this.parseSdkLocation(fileContent, logger);
52f3873ddigeff10 years ago218}
219}