|
1 | 1 | const vscode = require('vscode'); |
2 | | -const { exec } = require('child_process'); |
3 | | -const os = require('os'); |
| 2 | +const dns = require('dns'); |
| 3 | +const { AdbDeviceProvider } = require('./src/adbProvider'); |
| 4 | +const { AdbToolbarProvider } = require('./src/adbToolbarProvider'); |
4 | 5 |
|
5 | | -function getNetworkInterfaces() { |
6 | | - const nets = os.networkInterfaces(); |
7 | | - let results = []; |
8 | | - for (const name of Object.keys(nets)) { |
9 | | - for (const net of nets[name]) { |
10 | | - if (net.family === 'IPv4' && !net.internal) { |
11 | | - results.push({ name, address: net.address }); |
12 | | - } |
13 | | - } |
14 | | - } |
15 | | - return results; |
16 | | -} |
17 | | - |
18 | | -function execCommand(command, input) { |
19 | | - return new Promise((resolve, reject) => { |
20 | | - const child = exec(command, (error, stdout, stderr) => { |
21 | | - if (error) reject(stderr || error.message); |
22 | | - else resolve(stdout); |
23 | | - }); |
24 | | - if (input) { |
25 | | - child.stdin.write(input + '\n'); |
26 | | - child.stdin.end(); |
27 | | - } |
28 | | - }); |
29 | | -} |
30 | | - |
31 | | -async function adbPair(ipPort, pairCode) { |
32 | | - return execCommand(`adb pair ${ipPort}`, pairCode); |
33 | | -} |
34 | | - |
35 | | -async function adbConnect(ipPort) { |
36 | | - return execCommand(`adb connect ${ipPort}`); |
37 | | -} |
38 | | - |
39 | | -function getIpPrefix(ip) { |
40 | | - // get first 3 octets, e.g. 192.168.1. |
41 | | - const parts = ip.split('.'); |
42 | | - if (parts.length === 4) { |
43 | | - return parts.slice(0, 3).join('.') + '.'; |
44 | | - } |
45 | | - return ip; |
46 | | -} |
47 | | - |
48 | | -async function promptForLastDigitsAndPort(ipPrefix) { |
49 | | - // last 3 digits of device IP |
50 | | - const lastDigits = await vscode.window.showInputBox({ |
51 | | - prompt: `Enter the last part of device IP address (after ${ipPrefix})`, |
52 | | - validateInput: val => { |
53 | | - if (!val.match(/^\d{1,3}$/)) return 'Enter 1 to 3 digits'; |
54 | | - const n = Number(val); |
55 | | - if (n < 0 || n > 255) return 'Must be between 0 and 255'; |
56 | | - return null; |
57 | | - } |
58 | | - }); |
59 | | - if (!lastDigits) return null; |
60 | | - |
61 | | - // port number |
62 | | - const port = await vscode.window.showInputBox({ |
63 | | - prompt: 'Enter port number', |
64 | | - value: '5555', |
65 | | - validateInput: val => { |
66 | | - const p = Number(val); |
67 | | - if (isNaN(p) || p <= 0 || p > 65535) return 'Enter valid port number'; |
68 | | - return null; |
69 | | - } |
70 | | - }); |
71 | | - if (!port) return null; |
72 | | - |
73 | | - return `${ipPrefix}${lastDigits}:${port}`; |
| 6 | +// Fix for slow IPv6 resolution on some systems |
| 7 | +if (dns.setDefaultAutoSelectFamilyAttemptTimeout) { |
| 8 | + dns.setDefaultAutoSelectFamilyAttemptTimeout(1000); |
74 | 9 | } |
75 | | - |
| 10 | +const { |
| 11 | + mirrorDevice, disconnectDevice, pairDevice, connectDevice, |
| 12 | + openLogcat, takeScreenshot, switchToWireless, rebootDevice, wirelessPairingQr, |
| 13 | + startLiveView, autoDiscoverConnect |
| 14 | +} = require('./src/adbCommands'); |
| 15 | + |
| 16 | +/** |
| 17 | + * @param {vscode.ExtensionContext} context |
| 18 | + */ |
76 | 19 | async function activate(context) { |
77 | | - const disposablePair = vscode.commands.registerCommand('wirelessDebug.pair', async () => { |
78 | | - try { |
79 | | - const nets = getNetworkInterfaces(); |
80 | | - if (nets.length === 0) { |
81 | | - vscode.window.showErrorMessage('No active network interfaces found.'); |
82 | | - return; |
83 | | - } |
84 | | - const pick = await vscode.window.showQuickPick( |
85 | | - nets.map(n => ({ label: `${n.name} - ${n.address}`, ip: n.address })), |
86 | | - { placeHolder: 'Select your network IP to pair' } |
87 | | - ); |
88 | | - if (!pick) return; |
89 | | - |
90 | | - const ipPrefix = getIpPrefix(pick.ip); |
91 | | - |
92 | | - const ipPortInput = await promptForLastDigitsAndPort(ipPrefix); |
93 | | - if (!ipPortInput) return; |
94 | | - |
95 | | - const pairCode = await vscode.window.showInputBox({ |
96 | | - prompt: 'Enter the 6-digit wireless debugging pair code', |
97 | | - placeHolder: 'e.g. 123456', |
98 | | - validateInput: val => { |
99 | | - if (!val.match(/^\d{6}$/)) return 'Pair code must be exactly 6 digits'; |
100 | | - return null; |
101 | | - } |
102 | | - }); |
103 | | - if (!pairCode) return; |
| 20 | + const provider = new AdbDeviceProvider(context); |
104 | 21 |
|
105 | | - vscode.window.showInformationMessage(`Pairing with ${ipPortInput} ...`); |
106 | | - const pairOutput = await adbPair(ipPortInput, pairCode); |
107 | | - vscode.window.showInformationMessage('Pair Output: ' + pairOutput.trim()); |
| 22 | + // Check extension flavor from package name (starts with 'dev-') |
| 23 | + const isDev = context.extension.packageJSON.name.startsWith('dev-'); |
| 24 | + const viewTitle = isDev ? 'Dev-Devices' : 'Devices'; |
108 | 25 |
|
109 | | - const connectNow = await vscode.window.showQuickPick(['Yes', 'No'], { |
110 | | - placeHolder: 'Connect to device now?' |
111 | | - }); |
112 | | - if (connectNow === 'Yes') { |
113 | | - const connectIpPort = await promptForLastDigitsAndPort(ipPrefix); |
114 | | - if (!connectIpPort) return; |
115 | | - |
116 | | - const connectOutput = await adbConnect(connectIpPort); |
117 | | - vscode.window.showInformationMessage('Connect Output: ' + connectOutput.trim()); |
118 | | - } |
119 | | - } catch (e) { |
120 | | - vscode.window.showErrorMessage('Error: ' + e); |
121 | | - } |
122 | | - }); |
123 | | - |
124 | | - const disposableConnect = vscode.commands.registerCommand('wirelessDebug.connect', async () => { |
125 | | - try { |
126 | | - const nets = getNetworkInterfaces(); |
127 | | - if (nets.length === 0) { |
128 | | - vscode.window.showErrorMessage('No active network interfaces found.'); |
129 | | - return; |
130 | | - } |
131 | | - const netPick = await vscode.window.showQuickPick( |
132 | | - nets.map(n => ({ label: `${n.name} - ${n.address}`, ip: n.address })), |
133 | | - { placeHolder: 'Select your network IP' } |
134 | | - ); |
135 | | - if (!netPick) return; |
136 | | - |
137 | | - const ipPrefix = getIpPrefix(netPick.ip); |
138 | | - const deviceIpPort = await promptForLastDigitsAndPort(ipPrefix); |
139 | | - if (!deviceIpPort) return; |
140 | | - |
141 | | - vscode.window.showInformationMessage(`Connecting to ${deviceIpPort} ...`); |
142 | | - const connectOutput = await adbConnect(deviceIpPort); |
143 | | - vscode.window.showInformationMessage('Connect Output: ' + connectOutput.trim()); |
144 | | - } catch (e) { |
145 | | - vscode.window.showErrorMessage('Error: ' + e); |
146 | | - } |
| 26 | + // Register the TreeView |
| 27 | + const treeView = vscode.window.createTreeView('adbDevices', { |
| 28 | + treeDataProvider: provider, |
| 29 | + showCollapseAll: true |
147 | 30 | }); |
| 31 | + treeView.title = viewTitle; |
| 32 | + |
| 33 | + // Register the toolbar WebviewView |
| 34 | + const toolbarProvider = new AdbToolbarProvider(context, isDev); |
| 35 | + context.subscriptions.push( |
| 36 | + vscode.window.registerWebviewViewProvider('adbToolbar', toolbarProvider) |
| 37 | + ); |
| 38 | + |
| 39 | + const commands = [ |
| 40 | + vscode.commands.registerCommand('wirelessDebug.refreshDevices', () => provider.refresh()), |
| 41 | + vscode.commands.registerCommand('wirelessDebug.autoConnect', () => autoDiscoverConnect(provider)), |
| 42 | + vscode.commands.registerCommand('wirelessDebug.clearHistory', () => provider.clearHistory()), |
| 43 | + vscode.commands.registerCommand('wirelessDebug.pair', () => pairDevice(provider)), |
| 44 | + vscode.commands.registerCommand('wirelessDebug.pairQr', () => wirelessPairingQr(provider)), |
| 45 | + vscode.commands.registerCommand('wirelessDebug.connect', (d) => connectDevice(provider, d)), |
| 46 | + vscode.commands.registerCommand('wirelessDebug.disconnect', (d) => d && disconnectDevice(d, provider)), |
| 47 | + vscode.commands.registerCommand('wirelessDebug.mirror', async (d) => await mirrorDevice(d || await selectDevice(provider))), |
| 48 | + vscode.commands.registerCommand('wirelessDebug.liveView', async (d) => await startLiveView(d || await selectDevice(provider))), |
| 49 | + vscode.commands.registerCommand('wirelessDebug.logcat', (d) => d && openLogcat(d)), |
| 50 | + vscode.commands.registerCommand('wirelessDebug.screenshot', (d) => d && takeScreenshot(d)), |
| 51 | + vscode.commands.registerCommand('wirelessDebug.switchToWireless', (d) => d && switchToWireless(d, provider)), |
| 52 | + vscode.commands.registerCommand('wirelessDebug.reboot', (d) => d && rebootDevice(d, provider)), |
| 53 | + vscode.commands.registerCommand('wirelessDebug.deleteHistoryItem', (d) => d && provider.deleteHistoryItem(d)), |
| 54 | + ]; |
| 55 | + |
| 56 | + context.subscriptions.push(provider, treeView, ...commands); |
| 57 | +} |
148 | 58 |
|
149 | | - context.subscriptions.push(disposablePair, disposableConnect); |
| 59 | +async function selectDevice(provider) { |
| 60 | + const devices = provider.devices; |
| 61 | + if (devices.length === 0) { |
| 62 | + vscode.window.showErrorMessage('No devices connected.'); |
| 63 | + return null; |
| 64 | + } |
| 65 | + const pick = await vscode.window.showQuickPick( |
| 66 | + devices.map(d => ({ label: `${d.model || d.id} (${d.state})`, device: d })), |
| 67 | + { placeHolder: 'Select a device' } |
| 68 | + ); |
| 69 | + return pick ? pick.device : null; |
150 | 70 | } |
151 | 71 |
|
152 | | -function deactivate() {} |
| 72 | +function deactivate() { } |
153 | 73 |
|
154 | 74 | module.exports = { activate, deactivate }; |
0 commit comments