mirror of
https://github.com/adelphes/android-dev-ext.git
synced 2025-12-22 17:39:19 +00:00
Support for device picker during launch (#86)
This commit is contained in:
@@ -4,6 +4,7 @@ const vscode = require('vscode');
|
|||||||
const { AndroidContentProvider } = require('./src/contentprovider');
|
const { AndroidContentProvider } = require('./src/contentprovider');
|
||||||
const { openLogcatWindow } = require('./src/logcat');
|
const { openLogcatWindow } = require('./src/logcat');
|
||||||
const { selectAndroidProcessID } = require('./src/process-attach');
|
const { selectAndroidProcessID } = require('./src/process-attach');
|
||||||
|
const { selectTargetDevice } = require('./src/utils/device');
|
||||||
|
|
||||||
// this method is called when your extension is activated
|
// this method is called when your extension is activated
|
||||||
// your extension is activated the very first time the command is executed
|
// your extension is activated the very first time the command is executed
|
||||||
@@ -18,6 +19,12 @@ function activate(context) {
|
|||||||
vscode.commands.registerCommand('android-dev-ext.view_logcat', () => {
|
vscode.commands.registerCommand('android-dev-ext.view_logcat', () => {
|
||||||
openLogcatWindow(vscode);
|
openLogcatWindow(vscode);
|
||||||
}),
|
}),
|
||||||
|
// add the device picker handler - used to choose a target device
|
||||||
|
vscode.commands.registerCommand('PickAndroidDevice', async () => {
|
||||||
|
const device = await selectTargetDevice(vscode, "Launch", { alwaysShow:true });
|
||||||
|
// the debugger requires a string value to be returned
|
||||||
|
return JSON.stringify(device);
|
||||||
|
}),
|
||||||
// add the process picker handler - used to choose a PID to attach to
|
// add the process picker handler - used to choose a PID to attach to
|
||||||
vscode.commands.registerCommand('PickAndroidProcess', async () => {
|
vscode.commands.registerCommand('PickAndroidProcess', async () => {
|
||||||
const o = await selectAndroidProcessID(vscode);
|
const o = await selectAndroidProcessID(vscode);
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
},
|
},
|
||||||
"activationEvents": [
|
"activationEvents": [
|
||||||
"onCommand:android-dev-ext.view_logcat",
|
"onCommand:android-dev-ext.view_logcat",
|
||||||
|
"onCommand:PickAndroidDevice",
|
||||||
"onCommand:PickAndroidProcess"
|
"onCommand:PickAndroidProcess"
|
||||||
],
|
],
|
||||||
"repository": {
|
"repository": {
|
||||||
@@ -121,7 +122,7 @@
|
|||||||
"targetDevice": {
|
"targetDevice": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Target Device ID (as indicated by 'adb devices'). Use this to specify which device is used for deployment when multiple devices are connected.",
|
"description": "Target Device ID (as indicated by 'adb devices'). Use this to specify which device is used for deployment when multiple devices are connected.",
|
||||||
"default": ""
|
"default": "${command:PickAndroidDevice}"
|
||||||
},
|
},
|
||||||
"trace": {
|
"trace": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
@@ -155,7 +156,7 @@
|
|||||||
"targetDevice": {
|
"targetDevice": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Target Device ID (as indicated by 'adb devices'). Use this to specify which device is used when multiple devices are connected.",
|
"description": "Target Device ID (as indicated by 'adb devices'). Use this to specify which device is used when multiple devices are connected.",
|
||||||
"default": ""
|
"default": "${command:PickAndroidDevice}"
|
||||||
},
|
},
|
||||||
"trace": {
|
"trace": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
|
|||||||
@@ -305,6 +305,19 @@ class AndroidDebugSession extends DebugSession {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extractTargetDeviceID(s) {
|
||||||
|
if (!s || typeof s !== 'string') {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
// the device picker returns a stringified object
|
||||||
|
try {
|
||||||
|
const o = JSON.parse(s);
|
||||||
|
return o.serial || s;
|
||||||
|
} catch {
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
async attachRequest(response, args) {
|
async attachRequest(response, args) {
|
||||||
this.debug_mode = 'attach';
|
this.debug_mode = 'attach';
|
||||||
if (args && args.trace) {
|
if (args && args.trace) {
|
||||||
@@ -313,6 +326,14 @@ class AndroidDebugSession extends DebugSession {
|
|||||||
}
|
}
|
||||||
D(`Attach: ${JSON.stringify(args)}`);
|
D(`Attach: ${JSON.stringify(args)}`);
|
||||||
|
|
||||||
|
if (args.targetDevice === 'null') {
|
||||||
|
// "null" is returned from the device picker if there's an error or if the
|
||||||
|
// user cancels.
|
||||||
|
D('targetDevice === "null"');
|
||||||
|
this.sendEvent(new TerminatedEvent(false));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!args.processId) {
|
if (!args.processId) {
|
||||||
this.LOG(`Attach failed: Missing "processId" property in launch.json`);
|
this.LOG(`Attach failed: Missing "processId" property in launch.json`);
|
||||||
this.sendEvent(new TerminatedEvent(false));
|
this.sendEvent(new TerminatedEvent(false));
|
||||||
@@ -348,7 +369,7 @@ class AndroidDebugSession extends DebugSession {
|
|||||||
try {
|
try {
|
||||||
let { processId, targetDevice } = attach_info;
|
let { processId, targetDevice } = attach_info;
|
||||||
if (!targetDevice) {
|
if (!targetDevice) {
|
||||||
targetDevice = args.targetDevice;
|
targetDevice = this.extractTargetDeviceID(args.targetDevice);
|
||||||
}
|
}
|
||||||
// make sure ADB exists and is started and look for a connected device
|
// make sure ADB exists and is started and look for a connected device
|
||||||
await checkADBStarted(args.autoStartADB !== false);
|
await checkADBStarted(args.autoStartADB !== false);
|
||||||
@@ -416,6 +437,14 @@ class AndroidDebugSession extends DebugSession {
|
|||||||
}
|
}
|
||||||
D(`Launch: ${JSON.stringify(args)}`);
|
D(`Launch: ${JSON.stringify(args)}`);
|
||||||
|
|
||||||
|
if (args.targetDevice === 'null') {
|
||||||
|
// "null" is returned from the device picker if there's an error or if the
|
||||||
|
// user cancels.
|
||||||
|
D('targetDevice === "null"');
|
||||||
|
this.sendEvent(new TerminatedEvent(false));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// app_src_root must end in a path-separator for correct validation of sub-paths
|
// app_src_root must end in a path-separator for correct validation of sub-paths
|
||||||
this.app_src_root = ensure_path_end_slash(args.appSrcRoot);
|
this.app_src_root = ensure_path_end_slash(args.appSrcRoot);
|
||||||
this.apk_fpn = args.apkFile;
|
this.apk_fpn = args.apkFile;
|
||||||
@@ -465,7 +494,8 @@ class AndroidDebugSession extends DebugSession {
|
|||||||
|
|
||||||
// make sure ADB exists and is started and look for a device to install on
|
// make sure ADB exists and is started and look for a device to install on
|
||||||
await checkADBStarted(args.autoStartADB !== false);
|
await checkADBStarted(args.autoStartADB !== false);
|
||||||
this._device = await this.findSuitableDevice(args.targetDevice, true);
|
const targetDevice = this.extractTargetDeviceID(args.targetDevice);
|
||||||
|
this._device = await this.findSuitableDevice(targetDevice, true);
|
||||||
this._device.adbclient = new ADBClient(this._device.serial);
|
this._device.adbclient = new ADBClient(this._device.serial);
|
||||||
|
|
||||||
// install the APK we are going to debug
|
// install the APK we are going to debug
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ class BuildInfo {
|
|||||||
* @param {string} pkgname
|
* @param {string} pkgname
|
||||||
* @param {Map<string,PackageInfo>} packages
|
* @param {Map<string,PackageInfo>} packages
|
||||||
* @param {string} launchActivity
|
* @param {string} launchActivity
|
||||||
* @param {string[]} amCommandArgs custom arguments passed to `am start`
|
* @param {string[]} [amCommandArgs] custom arguments passed to `am start`
|
||||||
*/
|
*/
|
||||||
constructor(pkgname, packages, launchActivity, amCommandArgs) {
|
constructor(pkgname, packages, launchActivity, amCommandArgs) {
|
||||||
this.pkgname = pkgname;
|
this.pkgname = pkgname;
|
||||||
|
|||||||
@@ -26,9 +26,10 @@ async function showDevicePicker(vscode, devices) {
|
|||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param {import('vscode')} vscode
|
* @param {import('vscode')} vscode
|
||||||
* @param {'Attach'|'Logcat display'} action
|
* @param {'Launch'|'Attach'|'Logcat display'} action
|
||||||
|
* @param {{alwaysShow:boolean}} [options]
|
||||||
*/
|
*/
|
||||||
async function selectTargetDevice(vscode, action) {
|
async function selectTargetDevice(vscode, action, options) {
|
||||||
const devices = await new ADBClient().list_devices();
|
const devices = await new ADBClient().list_devices();
|
||||||
let device;
|
let device;
|
||||||
switch(devices.length) {
|
switch(devices.length) {
|
||||||
@@ -36,14 +37,20 @@ async function selectTargetDevice(vscode, action) {
|
|||||||
vscode.window.showWarningMessage(`${action} failed. No Android devices are connected.`);
|
vscode.window.showWarningMessage(`${action} failed. No Android devices are connected.`);
|
||||||
return null;
|
return null;
|
||||||
case 1:
|
case 1:
|
||||||
|
if (!options || !options.alwaysShow) {
|
||||||
return devices[0]; // only one device - just use it
|
return devices[0]; // only one device - just use it
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
device = await showDevicePicker(vscode, devices);
|
device = await showDevicePicker(vscode, devices);
|
||||||
|
if (!device) {
|
||||||
|
return null; // user cancelled
|
||||||
|
}
|
||||||
// the user might take a while to choose the device, so once
|
// the user might take a while to choose the device, so once
|
||||||
// chosen, recheck it exists
|
// chosen, recheck it exists
|
||||||
const current_devices = await new ADBClient().list_devices();
|
const current_devices = await new ADBClient().list_devices();
|
||||||
if (!current_devices.find(d => d.serial === device.serial)) {
|
if (!current_devices.find(d => d.serial === device.serial)) {
|
||||||
vscode.window.showInformationMessage(`${action} failed. The target device is disconnected`);
|
vscode.window.showInformationMessage(`${action} failed. The target device is disconnected.`);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return device;
|
return device;
|
||||||
|
|||||||
Reference in New Issue
Block a user