Skip to content

Commit cbd23d7

Browse files
authored
Merge pull request #1 from BBvmlabs/v3
V3
2 parents cc18413 + d7913ac commit cbd23d7

16 files changed

Lines changed: 1991 additions & 224 deletions

.vscode/launch.json

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,22 @@
66
"version": "0.2.0",
77
"configurations": [
88
{
9-
"name": "Run Extension",
9+
"name": "Run Extension (Dev)",
1010
"type": "extensionHost",
1111
"request": "launch",
1212
"args": [
1313
"--extensionDevelopmentPath=${workspaceFolder}"
14-
]
14+
],
15+
"preLaunchTask": "set-flavor-dev"
16+
},
17+
{
18+
"name": "Run Extension (Prod)",
19+
"type": "extensionHost",
20+
"request": "launch",
21+
"args": [
22+
"--extensionDevelopmentPath=${workspaceFolder}"
23+
],
24+
"preLaunchTask": "set-flavor-prod"
1525
}
1626
]
1727
}

.vscode/tasks.json

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
{
2+
"version": "2.0.0",
3+
"tasks": [
4+
{
5+
"label": "set-flavor-dev",
6+
"type": "shell",
7+
"command": "node ./scripts/set-flavor.js dev",
8+
"problemMatcher": []
9+
},
10+
{
11+
"label": "set-flavor-prod",
12+
"type": "shell",
13+
"command": "node ./scripts/set-flavor.js prod",
14+
"problemMatcher": []
15+
},
16+
{
17+
"label": "Build Extension (Prod)",
18+
"type": "shell",
19+
"command": "npm run package",
20+
"group": {
21+
"kind": "build",
22+
"isDefault": true
23+
},
24+
"problemMatcher": []
25+
}
26+
]
27+
}

README.md

Lines changed: 47 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,79 +1,63 @@
1-
# Wireless Debug VS Code Extension
1+
# ADB Wireless Debugger VS Code Extension
22

3-
A Visual Studio Code extension to simplify wireless debugging of Android devices using ADB pairing and connecting commands.
3+
An elegant and powerful Visual Studio Code extension to simplify wireless debugging of Android devices using ADB. Easily connect, pair (via Code or QR), view logs, and mirror your device screen seamlessly in real time!
44

5-
## Features
5+
## 🚀 What's New in Version 1.1.0
66

7-
- Lists your active network IP addresses for easy selection
8-
- Prompts for device IP (last digits only) and port number based on your network
9-
- Supports ADB wireless debugging pair code input
10-
- Provides commands to pair and connect your Android device wirelessly
11-
- Works with system hotspot and standard Wi-Fi networks
7+
### 📺 Buttery Smooth Live View (Screen Mirroring)
8+
- **High-Performance Streaming:** Fully redesigned live-view screen mirroring streaming at **30+ FPS**.
9+
- **Native H.264 Video Stream:** Uses high-efficiency continuous `adb exec-out screenrecord` parsed and played natively using `jmuxer` in a VS Code webview.
10+
- **Low Latency:** Experience seamless screen mirror interaction with minimal delay.
1211

13-
## Requirements
12+
### ⚡ Elegant Webview Sidebar Dashboard
13+
- A sleek, unified control panel in the VS Code Sidebar.
14+
- Quick actions for connecting, pairing, and managing devices.
15+
- Support for **Auto-Discovery**, **Pair via QR**, **Pair via Code**, and **Direct IP Connection**.
1416

15-
- [ADB (Android Debug Bridge)](https://developer.android.com/studio/command-line/adb) must be installed and added to your system PATH
16-
- Your Android device should have **Wireless Debugging** enabled and show a pairing code
17+
### 🔍 Smart Network Auto-Discovery
18+
- Automatically scans your local area network (LAN) for debug-ready Android devices.
19+
- Leverages mDNS/DNS-SD (Bonjour) and ARP table lookups for swift detection.
20+
- Click to connect or pair immediately without manually keying in IPs.
1721

18-
## Usage
22+
### 🔋 Rich Device Insights & Inline Controls
23+
- View device states, release versions, and **real-time battery percentage indicators**.
24+
- Quick, inline action buttons to:
25+
- **Live View** (Internal Screen Mirror)
26+
- **Logcat** (Streams logs to VS Code Debug Console)
27+
- **Disconnect** wireless devices
28+
- **Delete History** items
1929

20-
### Commands
30+
---
2131

22-
- **Wireless Debug: Pair Device**
23-
Starts the pairing process:
24-
1. Select your network IP (e.g., `192.168.1.1`)
25-
2. Enter the last digits of your device IP (e.g., `45`) and port number (usually `5555`)
26-
3. Enter the 6-digit wireless debugging pair code shown on your Android device
27-
4. Optionally connect immediately by entering device port number again
32+
## 🛠️ Requirements
2833

29-
- **Wireless Debug: Connect to Device**
30-
Connects to your device without pairing:
31-
1. Select your network IP
32-
2. Enter the last digits of your device IP and port number
33-
3. Connects via `adb connect ip:port`
34+
1. **ADB (Android Debug Bridge)** must be installed and added to your system's environment `PATH` variable.
35+
2. An Android device on the same local network with **Wireless Debugging** enabled (found under Developer Options).
36+
3. (Optional) For external screen mirroring via windowed mode, [scrcpy](https://github.com/Genymobile/scrcpy) can be installed on your system.
3437

35-
### Running the commands
38+
---
3639

37-
1. Open the Command Palette (`Ctrl+Shift+P` or `Cmd+Shift+P`)
38-
2. Type and select `Wireless Debug: Pair Device` or `Wireless Debug: Connect to Device`
39-
3. Follow the prompts
40+
## 📖 Usage & Commands
4041

41-
## Example
42+
### Sidebar Panel Buttons
43+
Open the **ADB Wireless** tab in the Activity Bar to access the control panel:
44+
- **Auto-Discover & Connect:** Scan network and connect to visible debugging endpoints automatically.
45+
- **Pair via QR:** Displays a QR code terminal to pair your phone instantly by scanning it using your device's Wireless Debugging QR code scanner.
46+
- **Pair via Code:** Enter the 6-digit pair code from your developer options screen.
47+
- **Connect IP:** Direct connect input by typing device IP and port.
48+
- **Refresh:** Reload the active device tree.
49+
- **Clear History:** Erase all stored device connection histories.
4250

43-
If your network IP is `192.168.1.1`, device IP is `192.168.1.45`, and port is `5555`:
51+
### Context Actions on Device List
52+
Right-click or hover over a device in the tree view to access:
53+
- **Live View (30+ FPS):** Stream phone screen directly into a VS Code tab.
54+
- **Open Logcat:** Stream Android system logs into a dedicated VS Code console window.
55+
- **Switch to Wireless mode:** Enable wireless debugging on a USB-connected device.
56+
- **Take Screenshot:** Instantly capture the device screen.
57+
- **Reboot Device:** Perform a system reboot command via ADB.
4458

45-
- Select `192.168.1.1` from network list
46-
- Enter `45` for last digits of device IP
47-
- Enter `5555` as port number
48-
- Enter the 6-digit pair code from your device (for pairing)
49-
- Optionally connect immediately
59+
---
5060

51-
ADB commands run under the hood:
61+
## 📝 License
5262

53-
```bash
54-
adb pair 192.168.1.45:5555
55-
# (pair code sent as input)
56-
adb connect 192.168.1.45:5555
57-
```
58-
59-
## License
60-
61-
MIT License © 2025 BBVMLABS
62-
63-
Permission is hereby granted, free of charge, to any person obtaining a copy
64-
of this software and associated documentation files (the "Software"), to deal
65-
in the Software without restriction, including without limitation the rights
66-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
67-
copies of the Software, and to permit persons to whom the Software is
68-
furnished to do so, subject to the following conditions:
69-
70-
The above copyright notice and this permission notice shall be included in all
71-
copies or substantial portions of the Software.
72-
73-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
74-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
75-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
76-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
77-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
78-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
79-
SOFTWARE.
63+
MIT License © 2026 BBVMLABS

extension.js

Lines changed: 62 additions & 142 deletions
Original file line numberDiff line numberDiff line change
@@ -1,154 +1,74 @@
11
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');
45

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);
749
}
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+
*/
7619
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);
10421

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';
10825

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
14730
});
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+
}
14858

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;
15070
}
15171

152-
function deactivate() {}
72+
function deactivate() { }
15373

15474
module.exports = { activate, deactivate };

media/icon.png

15.6 KB
Loading

0 commit comments

Comments
 (0)