├── .gitignore
├── .travis.yml
├── ADBWiFiConnect.iml
├── ADBWiFiConnectGUI
├── build.gradle
└── src
│ └── main
│ ├── java
│ └── dk
│ │ └── appdictive
│ │ └── adbwificonnect
│ │ ├── ADBCommands.java
│ │ ├── Device.java
│ │ ├── IPHelper.java
│ │ ├── ListViewCell.java
│ │ ├── Main.java
│ │ ├── OnScreenConsoleOutputDelegate.java
│ │ └── SerializeHelper.java
│ └── resources
│ ├── icons
│ ├── ic_adbremoteconnect.png
│ └── ic_adbremoteconnect@2x.png
│ ├── list_cell_item.fxml
│ ├── main.fxml
│ └── stylesheet.css
├── ADBWiFiConnect_screen1.png
├── README.md
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── settings.gradle
└── src
└── main
├── java
└── dk
│ └── appdictive
│ └── adbwificonnect
│ └── plugin
│ ├── OSValidator.java
│ └── RemoteConnect.java
└── resources
├── META-INF
└── plugin.xml
└── icons
├── ic_adbremoteconnect.png
└── ic_adbremoteconnect@2x.png
/.gitignore:
--------------------------------------------------------------------------------
1 | # IntelliJ
2 | out/
3 | .idea/
4 | target/
5 | *.iml
6 | local.properties
7 |
8 | ### Java ###
9 | *.class
10 | classes/
11 |
12 | # Package Files #
13 | *.jar
14 | !ADBWiFiConnectGUI/build/libs/ADBWiFiConnectGUI.jar
15 |
16 | ### Gradle ###
17 | .gradle
18 | build/
19 |
20 | ### Specific ###
21 | *.zip
22 |
23 | # Ignore Gradle GUI config
24 | gradle-app.setting
25 |
26 | # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
27 | !gradle-wrapper.jar
28 |
29 | # Avoid ignoring ADBWiFiConnect.iml file to be able to import the project into any IntelliJ IDE and run/debug the pulgin without problems
30 | !ADBWiFiConnect.iml
31 |
32 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: java
2 | jdk: oraclejdk7
3 | env:
4 | matrix:
5 | - TERM=dumb
6 | after_success:
7 | - ./gradlew test jacocoTestReport coveralls
8 |
9 | script:
10 | ./gradlew checkstyle build
11 |
--------------------------------------------------------------------------------
/ADBWiFiConnect.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/ADBWiFiConnectGUI/build.gradle:
--------------------------------------------------------------------------------
1 | group 'com.github.appdictive'
2 |
3 | apply plugin: 'java'
4 | apply plugin: 'application'
5 |
6 | sourceCompatibility = 1.8
7 |
8 | repositories {
9 | mavenCentral()
10 | }
11 |
12 | mainClassName = "dk.appdictive.adbwificonnect.Main"
13 |
14 | dependencies {
15 | // compile group: 'org.apache.logging.log4j', name: 'log4j-api', version: '1.2.16'
16 | // compile group: 'org.apache.logging.log4j', name: 'log4j-core', version: '1.2.16'
17 | compile 'log4j:log4j:1.2.17'
18 |
19 | //JFoenix does not work with all linux distributions it seems (issues reported on Github)
20 | // compile 'com.jfoenix:jfoenix:1.4.0'
21 | }
22 |
23 | jar {
24 | from {
25 | configurations.compile.collect {
26 | it.isDirectory() ? it : zipTree(it)
27 | }
28 | configurations.runtime.collect {
29 | it.isDirectory() ? it : zipTree(it)
30 | }
31 | }
32 | manifest {
33 | attributes(
34 | 'Main-Class': 'dk.appdictive.adbwificonnect.Main'
35 | )
36 | // 'Class-Path': configurations.compile.collect { it.getName() }.join(' '),
37 | }
38 | }
--------------------------------------------------------------------------------
/ADBWiFiConnectGUI/src/main/java/dk/appdictive/adbwificonnect/ADBCommands.java:
--------------------------------------------------------------------------------
1 | package dk.appdictive.adbwificonnect;
2 |
3 | import javafx.application.Platform;
4 | import javafx.scene.control.Button;
5 | import org.apache.log4j.Logger;
6 |
7 | import java.io.BufferedReader;
8 | import java.io.IOException;
9 | import java.io.InputStreamReader;
10 |
11 | /**
12 | * Created by JesperLR on 05-11-2016.
13 | */
14 | public class ADBCommands {
15 |
16 | private static final String ADB_DEVICE_PORT = "5555";
17 | private static Logger log = Logger.getLogger(Main.class.getName());
18 |
19 | public static String runCommand(String command) {
20 | try
21 | {
22 | Process p=Runtime.getRuntime().exec(command);
23 | p.waitFor();
24 | BufferedReader reader=new BufferedReader(
25 | new InputStreamReader(p.getInputStream())
26 | );
27 | String result = "";
28 | String line;
29 | while((line = reader.readLine()) != null)
30 | {
31 | result += line + "\n";
32 | }
33 | result = result.replace("\n\n", "\n");
34 | return result;
35 | }
36 | catch(IOException e1) {log.error(e1.getMessage());}
37 | catch(InterruptedException e2) {log.error(e2.getMessage());}
38 |
39 | return null;
40 | }
41 |
42 | public static String runCommand(String[] cmd)
43 | {
44 | String s;
45 | String results = "";
46 | try {
47 | Runtime rt = Runtime.getRuntime();
48 | Process p = rt.exec(cmd, null);
49 |
50 | BufferedReader stdInput = new BufferedReader(new
51 | InputStreamReader(p.getInputStream()));
52 | BufferedReader stdError = new BufferedReader(new
53 | InputStreamReader(p.getErrorStream()));
54 | // read the output from the command
55 | //System.out.println("Here is the standard output of the command:\n");
56 | while ((s = stdInput.readLine()) != null)
57 | {
58 | System.out.println(s);
59 | results = results + s;
60 | }
61 | // read any errors from the attempted command
62 | //System.out.println("Here is the standard error of the command (if any):\n");
63 | while ((s = stdError.readLine()) != null)
64 | {
65 | System.out.println(s);
66 | results = results + s;
67 | }
68 | return results.toString();
69 | }
70 | catch (IOException e)
71 | {
72 | log.error(e.getMessage());
73 | return e.getMessage();
74 | }
75 | }
76 |
77 | private static String getAdbSpecificDevice(Device device) {
78 | String adbCommand = Main.adbPath + " -s ";
79 | if (device.getType() == Device.DEVICE_TYPE_USB) {
80 | adbCommand += device.getSerialID();
81 | } else if (device.getType() == Device.DEVICE_TYPE_REMOTE) {
82 | adbCommand += device.getRemoteIP()+":"+ADB_DEVICE_PORT;
83 | }
84 | return adbCommand;
85 | }
86 |
87 | public static String getDeviceName(Device device) {
88 | String model = runCommand(getAdbSpecificDevice(device) + " shell getprop ro.product.model");
89 | String manufacturer = runCommand(getAdbSpecificDevice(device) + " shell getprop ro.product.manufacturer");
90 | String androidVersionName = runCommand(getAdbSpecificDevice(device) + " shell getprop ro.build.version.release");
91 | String androidVersionCode = runCommand(getAdbSpecificDevice(device) + " shell getprop ro.build.version.sdk");
92 |
93 | String deviceName = manufacturer.trim() + " " + model.trim() + " (Android " + androidVersionName.trim() + ", SDK " + androidVersionCode.trim() + ")";
94 |
95 | return deviceName;
96 | }
97 |
98 | public static String getDeviceSerialNo(Device device) {
99 | String output = runCommand(getAdbSpecificDevice(device) + " shell getprop ro.serialno");
100 | String serialNumber = output.trim();
101 | return serialNumber;
102 | }
103 |
104 | public static String getDeviceIP(Device device) {
105 | String output = runCommand(getAdbSpecificDevice(device) + " shell ip -f inet addr show wlan0");
106 |
107 | String ipFromText = IPHelper.getIPFromText(output);
108 | if (ipFromText == null) {
109 | log.error("Could not get device IP - make sure the device is connected to your WiFi");
110 | }
111 | return ipFromText;
112 | }
113 |
114 | public static boolean disconnectDevice(Device device) {
115 | String output = runCommand(Main.adbPath + " disconnect " + device.getRemoteIP() + ":" + ADB_DEVICE_PORT);
116 | if (output.contains("disconnected")) {
117 | return true;
118 | } else {
119 | return false;
120 | }
121 | }
122 |
123 | public static void disconnectDeviceAsync(Device device) {
124 | Runnable r = new Runnable() {
125 | public void run() {
126 | disconnectDevice(device);
127 | }
128 | };
129 | new Thread(r).start();
130 | }
131 |
132 | public static boolean usbConnectToDevice(Device device) {
133 | runCommand(getAdbSpecificDevice(device) + " tcpip " + ADB_DEVICE_PORT);
134 | String output = runCommand(Main.adbPath + " connect " + device.getRemoteIP() + ":" + ADB_DEVICE_PORT);
135 | log.debug(output);
136 | if (output.contains("unable")) {
137 | return false;
138 | } else {
139 | return true;
140 | }
141 | }
142 |
143 | public static void usbConnectToDeviceAsync(Device device, Button connectButton) {
144 | connectButton.setDisable(true);
145 | Runnable r = new Runnable() {
146 | public void run() {
147 | usbConnectToDevice(device);
148 |
149 | Platform.runLater(new Runnable() {
150 | @Override
151 | public void run() {
152 | if (connectButton != null) connectButton.setDisable(false);
153 | }
154 | });
155 | }
156 | };
157 | new Thread(r).start();
158 | }
159 |
160 | public static boolean remoteConnectToDevice(Device device) {
161 | String output = runCommand(Main.adbPath + " connect " + device.getRemoteIP() + ":" + ADB_DEVICE_PORT);
162 | log.debug(output);
163 | if (output.contains("unable")) {
164 | return false;
165 | } else {
166 | return true;
167 | }
168 | }
169 |
170 | public static void remoteConnectToDeviceAsync(Device device, Button connectButton) {
171 | connectButton.setDisable(true);
172 | Runnable r = new Runnable() {
173 | public void run() {
174 | remoteConnectToDevice(device);
175 |
176 | Platform.runLater(new Runnable() {
177 | @Override
178 | public void run() {
179 | if (connectButton != null) connectButton.setDisable(false);
180 | }
181 | });
182 | }
183 | };
184 | new Thread(r).start();
185 | }
186 |
187 |
188 | }
189 |
--------------------------------------------------------------------------------
/ADBWiFiConnectGUI/src/main/java/dk/appdictive/adbwificonnect/Device.java:
--------------------------------------------------------------------------------
1 | package dk.appdictive.adbwificonnect;
2 |
3 | import java.io.Serializable;
4 |
5 | /**
6 | * Created by JesperLR on 05-11-2016.
7 | */
8 | public class Device implements Serializable {
9 |
10 | public static int DEVICE_TYPE_USB = 0, DEVICE_TYPE_REMOTE = 1, DEVICE_TYPE_SAVED_REMOTE = 2, DEVICE_TYPE_OFFLINE = 3;
11 |
12 | public Device() {
13 | }
14 |
15 | public String getName() {
16 | return name;
17 | }
18 |
19 | public void setName(String name) {
20 | this.name = name;
21 | }
22 |
23 | public String getRemoteIP() {
24 | return remoteIP;
25 | }
26 |
27 | public void setRemoteIP(String remoteIP) {
28 | this.remoteIP = remoteIP;
29 | }
30 |
31 | public String getSerialID() {
32 | return serialID;
33 | }
34 |
35 | public void setSerialID(String serialID) {
36 | this.serialID = serialID;
37 | }
38 |
39 | public int getType() {
40 | return type;
41 | }
42 |
43 | public void setType(int type) {
44 | this.type = type;
45 | }
46 |
47 | String name;
48 | String remoteIP;
49 | String serialID;
50 | int type;
51 |
52 |
53 |
54 | }
55 |
--------------------------------------------------------------------------------
/ADBWiFiConnectGUI/src/main/java/dk/appdictive/adbwificonnect/IPHelper.java:
--------------------------------------------------------------------------------
1 | package dk.appdictive.adbwificonnect;
2 |
3 | import java.util.regex.Matcher;
4 | import java.util.regex.Pattern;
5 |
6 | /**
7 | * Created by JesperLR on 05-11-2016.
8 | */
9 | public class IPHelper {
10 |
11 | private static final String IP_ADDRESS_REGEX = "(?:[0-9]{1,3}\\.){3}[0-9]{1,3}";
12 |
13 | public static String getIPFromText(String text) {
14 | Pattern ipAddressPattern = Pattern.compile(IP_ADDRESS_REGEX);
15 |
16 | Matcher m = ipAddressPattern.matcher(text);
17 | String ipAddress = null;
18 | while (m.find()) {
19 | String s = m.group(0);
20 | if (ipAddress == null) {
21 | //we assume the first IP address is the one we want to address
22 | ipAddress = s;
23 | }
24 | }
25 | return ipAddress;
26 | }
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/ADBWiFiConnectGUI/src/main/java/dk/appdictive/adbwificonnect/ListViewCell.java:
--------------------------------------------------------------------------------
1 | package dk.appdictive.adbwificonnect;
2 |
3 | import javafx.event.ActionEvent;
4 | import javafx.event.EventHandler;
5 | import javafx.fxml.FXML;
6 | import javafx.fxml.FXMLLoader;
7 | import javafx.fxml.Initializable;
8 | import javafx.scene.control.Button;
9 | import javafx.scene.control.Label;
10 | import javafx.scene.control.ListCell;
11 | import javafx.scene.control.TextInputDialog;
12 | import javafx.scene.input.MouseEvent;
13 | import javafx.scene.layout.HBox;
14 |
15 | import java.io.IOException;
16 | import java.net.URL;
17 | import java.util.Optional;
18 | import java.util.ResourceBundle;
19 |
20 | public class ListViewCell extends ListCell implements Initializable
21 | {
22 |
23 | FXMLLoader fxmlLoader;
24 |
25 | @FXML
26 | private HBox hBox;
27 | @FXML
28 | private Label connectionType;
29 | @FXML
30 | private Label deviceName;
31 | @FXML
32 | private Label deviceAddress;
33 | @FXML
34 | private Button connectAndSaveButton;
35 | @FXML
36 | private Button deleteAndDisconnectButton;
37 |
38 | private Main main;
39 |
40 | public ListViewCell(Main main) {
41 | this.main = main;
42 | }
43 |
44 | @Override
45 | public void updateItem(Device device, boolean empty)
46 | {
47 | super.updateItem(device,empty);
48 |
49 | if(empty || device == null) {
50 | setText(null);
51 | setGraphic(null);
52 | } else {
53 | if (fxmlLoader == null) {
54 | fxmlLoader = new FXMLLoader(getClass().getResource("/list_cell_item.fxml"));
55 | fxmlLoader.setController(this);
56 |
57 | try {
58 | fxmlLoader.load();
59 | } catch (IOException e) {
60 | e.printStackTrace();
61 | }
62 | }
63 |
64 | deviceName.setText(device.getName());
65 | deleteAndDisconnectButton.setVisible(true);
66 | connectAndSaveButton.setDisable(false);
67 |
68 | if (device.getType() == Device.DEVICE_TYPE_USB) {
69 | deleteAndDisconnectButton.setVisible(false);
70 | connectAndSaveButton.setText("CONNECT");
71 | connectionType.setText("USB");
72 | deviceAddress.setText(device.getSerialID());
73 | } else if (device.getType() == Device.DEVICE_TYPE_REMOTE) {
74 | deleteAndDisconnectButton.setText("DISCONNECT");
75 | connectionType.setText("WI-FI");
76 | deviceAddress.setText(device.getRemoteIP());
77 | connectAndSaveButton.setText("SAVE");
78 | if (main.hasRemoteIPSaved(device.getRemoteIP())) {
79 | connectAndSaveButton.setDisable(true);
80 | }
81 | } else if (device.getType() == Device.DEVICE_TYPE_SAVED_REMOTE) {
82 | if (main.isCurrentlyConnectedToRemoteIP(device.getRemoteIP())) {
83 | connectAndSaveButton.setDisable(true);
84 | }
85 | connectAndSaveButton.setText("CONNECT");
86 | connectionType.setText("");
87 | deviceAddress.setText(device.getRemoteIP());
88 | deleteAndDisconnectButton.setText("DELETE");
89 | } else {
90 | connectAndSaveButton.setVisible(false);
91 | deleteAndDisconnectButton.setVisible(false);
92 | if (device.getType() == Device.DEVICE_TYPE_OFFLINE) connectionType.setText("OFFLINE");
93 | }
94 |
95 | setText(null);
96 | setGraphic(hBox);
97 | }
98 |
99 | }
100 |
101 | @Override
102 | public void initialize(URL location, ResourceBundle resources) {
103 | setOnMouseClicked(new EventHandler() {
104 | @Override
105 | public void handle(MouseEvent event) {
106 | Device item = getItem();
107 | if (item != null && item.getType() == Device.DEVICE_TYPE_SAVED_REMOTE){
108 | TextInputDialog textInputDialog = new TextInputDialog(item.getName());
109 | textInputDialog.setTitle("Set device name");
110 | textInputDialog.setHeaderText("");
111 | Optional s = textInputDialog.showAndWait();
112 |
113 | if (s.isPresent() && !s.get().trim().isEmpty()) {
114 | item.setName(s.get().trim());
115 | main.saveConnection(item);
116 | }
117 | }
118 | }
119 | });
120 |
121 | connectAndSaveButton.setOnAction(new EventHandler() {
122 | @Override
123 | public void handle(ActionEvent event) {
124 | Device item = getItem();
125 | if (item.getType() == Device.DEVICE_TYPE_USB) {
126 | ADBCommands.usbConnectToDeviceAsync(item, connectAndSaveButton);
127 | } else if (item.getType() == Device.DEVICE_TYPE_SAVED_REMOTE){
128 | ADBCommands.remoteConnectToDeviceAsync(item, connectAndSaveButton);
129 | } else if (item.getType() == Device.DEVICE_TYPE_REMOTE){
130 | main.saveConnection(item);
131 | }
132 | }
133 | });
134 |
135 | deleteAndDisconnectButton.setOnAction(new EventHandler() {
136 | @Override
137 | public void handle(ActionEvent event) {
138 | Device item = getItem();
139 | if (item.getType() == Device.DEVICE_TYPE_REMOTE) {
140 | ADBCommands.disconnectDeviceAsync(item);
141 | } else if (item.getType() == Device.DEVICE_TYPE_SAVED_REMOTE){
142 | main.deleteConnection(item);
143 | }
144 | }
145 | });
146 | }
147 | }
--------------------------------------------------------------------------------
/ADBWiFiConnectGUI/src/main/java/dk/appdictive/adbwificonnect/Main.java:
--------------------------------------------------------------------------------
1 | package dk.appdictive.adbwificonnect;
2 |
3 | import javafx.application.Application;
4 | import javafx.application.Platform;
5 | import javafx.beans.value.ChangeListener;
6 | import javafx.beans.value.ObservableValue;
7 | import javafx.collections.FXCollections;
8 | import javafx.collections.ObservableList;
9 | import javafx.event.ActionEvent;
10 | import javafx.event.EventHandler;
11 | import javafx.fxml.FXML;
12 | import javafx.fxml.FXMLLoader;
13 | import javafx.fxml.Initializable;
14 | import javafx.scene.Parent;
15 | import javafx.scene.Scene;
16 | import javafx.scene.control.*;
17 | import javafx.scene.image.Image;
18 | import javafx.stage.Stage;
19 | import javafx.stage.WindowEvent;
20 | import javafx.util.Callback;
21 | import org.apache.log4j.Logger;
22 |
23 | import java.net.URL;
24 | import java.util.*;
25 | import java.util.prefs.BackingStoreException;
26 | import java.util.prefs.Preferences;
27 |
28 | public class Main extends Application implements Initializable {
29 |
30 | private static final String PREF_JAR_LOCATION = "JAR_LOCATION", PREF_ADB_LOCATION = "ADB_LOCATION", PREF_SAVED_CONNECTIONS = "SAVED_CONNECTIONS", PREFS_ID = "dk/appdictive/adbconnect";
31 |
32 | @FXML
33 | private TextArea outputTextArea;
34 | @FXML
35 | private CheckMenuItem menuItemDebug;
36 | @FXML
37 | private ListView listView;
38 | @FXML
39 | private ListView listViewSaved;
40 | ObservableList observableList = FXCollections.observableArrayList();
41 | ObservableList observableListSavedConnections = FXCollections.observableArrayList();
42 | private boolean isWindowActive = true;
43 | private Preferences prefs;
44 | private Logger log = Logger.getLogger(Main.class.getName());
45 | private OnScreenConsoleOutputDelegate onScreenConsoleOutputDelegate;
46 | public static String adbPath;
47 | private String lastADBDevicesOutput;
48 |
49 | @Override
50 | public void start(Stage primaryStage) throws Exception {
51 | URL resource = getClass().getResource("/main.fxml");
52 | FXMLLoader loader = new FXMLLoader(resource);
53 | loader.setController(this);
54 | Parent root = loader.load();
55 |
56 | primaryStage.getIcons().addAll(
57 | new Image(Main.class.getResourceAsStream("/icons/ic_adbremoteconnect.png")),
58 | new Image(Main.class.getResourceAsStream("/icons/ic_adbremoteconnect@2x.png")));
59 | primaryStage.setTitle("ADB WiFi Connect");
60 | Scene scene = new Scene(root, 700, 640);
61 | scene.getStylesheets().add("/stylesheet.css");
62 | primaryStage.iconifiedProperty().addListener(new ChangeListener() {
63 | @Override
64 | public void changed(ObservableValue extends Boolean> observable, Boolean oldValue, Boolean newValue) {
65 | if (newValue) {
66 | // not showing...
67 | isWindowActive = false;
68 | log.debug("Window not showing");
69 | } else {
70 | // showing ...
71 | isWindowActive = true;
72 | startDeviceListUpdateThread();
73 | log.debug("Window showing");
74 | }
75 | }
76 | });
77 | primaryStage.setOnCloseRequest(new EventHandler() {
78 | @Override
79 | public void handle(WindowEvent event) {
80 | isWindowActive = false;
81 | Platform.exit();
82 | System.exit(0);
83 | }
84 | });
85 | primaryStage.setScene(scene);
86 | primaryStage.show();
87 | }
88 |
89 | public static void main(String[] args) {
90 | launch(args);
91 | }
92 |
93 | private void setupLogAppender() {
94 | onScreenConsoleOutputDelegate = new OnScreenConsoleOutputDelegate(outputTextArea);
95 | Logger.getRootLogger().addAppender(onScreenConsoleOutputDelegate);
96 | // Logger.getRootLogger().addAppender(new AlertOnErrorsDelegate());
97 | }
98 |
99 | private void initializeSavedData() {
100 | // Retrieve the user preference node for the package
101 | Preferences systemRoot = Preferences.userRoot();
102 | prefs = systemRoot.node(PREFS_ID);
103 |
104 | String jarLocation = prefs.get(PREF_JAR_LOCATION, null);
105 | if (jarLocation != null) {
106 | log.info("For launching outside of the IDE, find the runnable jar file here: \n" + jarLocation + "\n");
107 | }
108 |
109 | adbPath = prefs.get(PREF_ADB_LOCATION, "adb");
110 | if (adbPath == null) adbPath = "adb";
111 | log.debug("ADB path: " + adbPath);
112 |
113 | String savedData = prefs.get(PREF_SAVED_CONNECTIONS, null);
114 |
115 | if (savedData != null) {
116 | Device[] deserializeArray = SerializeHelper.deserializeArray(savedData);
117 | if (deserializeArray != null) {
118 | observableListSavedConnections.addAll(new ArrayList<>(Arrays.asList(deserializeArray)));
119 | }
120 |
121 | if (observableListSavedConnections.size() == 0) {
122 | writeWelcome(false);
123 | } else {
124 | writeWelcome(true);
125 | }
126 | }
127 | }
128 |
129 | private void writeWelcome(boolean hasSavedConnections) {
130 | if (!hasSavedConnections) {
131 | log.info("Welcome to ADB WiFi Connect!\n\n" +
132 | "Please plug in an Android device by USB cable, make sure it is on the same WiFi as your computer and then click CONNECT to establish a remote connection to the device. A new connection will show up on the list. Click SAVE on the remote connection to add it to the list of saved connections and next time a remote connection is needed, simply click CONNECT on the saved connection.\n" +
133 | "\n" +
134 | "Happy developing! :)");
135 | } else {
136 | log.info("Welcome back!\n\n" +
137 | "Please click CONNECT on a saved connection to reconnect to that, or plug in a new device with USB to make a new remote connection.\n" +
138 | "\n" +
139 | "Happy developing! :)\n");
140 | }
141 |
142 |
143 | }
144 |
145 | //run from background thread
146 | private void updateListOfDevices(String[] adbDevicesListOutput) {
147 | ArrayList currentDevices = new ArrayList<>();
148 | for (String adbDeviceLine : adbDevicesListOutput) {
149 | if (adbDeviceLine.contains("List") || adbDeviceLine.contains("daemon") || adbDeviceLine.trim().equals("")) {
150 | //ignore line
151 | } else {
152 | //is a device line so check for either IP or get device adb ID
153 | Device currentDevice = new Device();
154 | if (adbDeviceLine.contains("offline")) {
155 | currentDevice.setType(Device.DEVICE_TYPE_OFFLINE);
156 | currentDevice.setName(adbDeviceLine.replace("offline", "").trim());
157 | } else {
158 | String ipFromText = IPHelper.getIPFromText(adbDeviceLine);
159 | if (ipFromText == null) {
160 | currentDevice.setSerialID(adbDeviceLine.replace("device", "").trim());
161 | currentDevice.setRemoteIP(ADBCommands.getDeviceIP(currentDevice));
162 | currentDevice.setType(Device.DEVICE_TYPE_USB);
163 | } else {
164 | currentDevice.setRemoteIP(ipFromText);
165 | currentDevice.setSerialID(ADBCommands.getDeviceSerialNo(currentDevice));
166 | currentDevice.setType(Device.DEVICE_TYPE_REMOTE);
167 | }
168 | currentDevice.setName(ADBCommands.getDeviceName(currentDevice));
169 | }
170 |
171 | currentDevices.add(currentDevice);
172 | }
173 | }
174 | updateData(currentDevices);
175 | }
176 |
177 | private void startDeviceListUpdateThread() {
178 | Runnable r = new Runnable() {
179 | public void run() {
180 | log.debug("Running update of adb devices with window active: " + isWindowActive);
181 | String output = ADBCommands.runCommand(Main.adbPath + " devices");
182 | log.debug(output);
183 | if (!output.equals(lastADBDevicesOutput)) {
184 | updateListOfDevices(output.split("\n"));
185 | lastADBDevicesOutput = output;
186 | }
187 |
188 | try {
189 | Thread.sleep(3000);
190 | if (isWindowActive) {
191 | new Thread(this).start();
192 | }
193 | } catch (InterruptedException e) {
194 | e.printStackTrace();
195 | log.error(e.getMessage());
196 | }
197 |
198 | }
199 | };
200 |
201 | log.debug("Starting update thread for list of ADB devices");
202 | new Thread(r).start();
203 | }
204 |
205 | public void updateData(List devices) {
206 | Platform.runLater(new Runnable() {
207 | @Override
208 | public void run() {
209 | // Update UI here.
210 | observableList.clear();
211 | observableList.addAll(devices);
212 | //TODO update list of saved devices (in case there's an overlap)
213 | listViewSaved.refresh();
214 | }
215 | });
216 | }
217 |
218 | private void updateSavedConnectionsList() {
219 | //refresh list of current connections since list of saved connections have changed data
220 | listView.refresh();
221 |
222 | //saved the data to remember for future launches
223 | prefs.put(PREF_SAVED_CONNECTIONS, SerializeHelper.serializeArray(observableListSavedConnections.toArray(new Device[observableListSavedConnections.size()])));
224 | try {
225 | prefs.flush();
226 | } catch (BackingStoreException e) {
227 | e.printStackTrace();
228 | }
229 | }
230 |
231 | public boolean hasRemoteIPSaved(String remoteIP) {
232 | for (Device savedDevice : observableListSavedConnections) {
233 | if (remoteIP.equals(savedDevice.getRemoteIP())) {
234 | return true;
235 | }
236 | }
237 | return false;
238 | }
239 |
240 | public boolean isCurrentlyConnectedToRemoteIP(String remoteIP) {
241 | for (Device currentConnectedDevice : observableList) {
242 | if (currentConnectedDevice.type == Device.DEVICE_TYPE_REMOTE && remoteIP.equals(currentConnectedDevice.getRemoteIP())) {
243 | return true;
244 | }
245 | }
246 | return false;
247 | }
248 |
249 | public void saveConnection(Device device) {
250 | Platform.runLater(new Runnable() {
251 | @Override
252 | public void run() {
253 | for (Device savedDevice : observableListSavedConnections) {
254 | if (device.getRemoteIP().equals(savedDevice.getRemoteIP())) {
255 | observableListSavedConnections.remove(savedDevice);
256 | break;
257 | }
258 | }
259 |
260 | Device newSavedConnection = new Device();
261 | newSavedConnection.setName(device.getName());
262 | newSavedConnection.setRemoteIP(device.getRemoteIP());
263 | newSavedConnection.setSerialID(device.getSerialID());
264 | newSavedConnection.setType(Device.DEVICE_TYPE_SAVED_REMOTE);
265 | observableListSavedConnections.add(0, newSavedConnection);
266 |
267 | updateSavedConnectionsList();
268 | }
269 | });
270 | }
271 |
272 | public void deleteConnection(Device device) {
273 | Platform.runLater(new Runnable() {
274 | @Override
275 | public void run() {
276 | for (Device savedDevice : observableListSavedConnections) {
277 | if (device.getRemoteIP().equals(savedDevice.getRemoteIP())) {
278 | observableListSavedConnections.remove(savedDevice);
279 | updateSavedConnectionsList();
280 | return;
281 | }
282 | }
283 | }
284 | });
285 | }
286 |
287 | public void setupListView() {
288 | listView.setSelectionModel(new TableSelectionModel() {
289 | @Override
290 | public boolean isSelected(int row, TableColumnBase column) {
291 | return false;
292 | }
293 |
294 | @Override
295 | public void select(int row, TableColumnBase column) {
296 |
297 | }
298 |
299 | @Override
300 | public void clearAndSelect(int row, TableColumnBase column) {
301 |
302 | }
303 |
304 | @Override
305 | public void clearSelection(int row, TableColumnBase column) {
306 |
307 | }
308 |
309 | @Override
310 | public void selectLeftCell() {
311 |
312 | }
313 |
314 | @Override
315 | public void selectRightCell() {
316 |
317 | }
318 |
319 | @Override
320 | public void selectAboveCell() {
321 |
322 | }
323 |
324 | @Override
325 | public void selectBelowCell() {
326 |
327 | }
328 |
329 | @Override
330 | public void selectRange(int minRow, TableColumnBase minColumn, int maxRow, TableColumnBase maxColumn) {
331 |
332 | }
333 |
334 | @Override
335 | protected int getItemCount() {
336 | return 0;
337 | }
338 |
339 | @Override
340 | protected Object getModelItem(int index) {
341 | return null;
342 | }
343 |
344 | @Override
345 | protected void focus(int index) {
346 |
347 | }
348 |
349 | @Override
350 | protected int getFocusedIndex() {
351 | return 0;
352 | }
353 | });
354 | listView.setItems(observableList);
355 | listView.setCellFactory(new Callback, ListCell>() {
356 | @Override
357 | public ListCell call(ListView listView) {
358 | return new ListViewCell(Main.this);
359 | }
360 | });
361 |
362 | listViewSaved.setSelectionModel(new TableSelectionModel() {
363 | @Override
364 | public boolean isSelected(int row, TableColumnBase column) {
365 | return false;
366 | }
367 |
368 | @Override
369 | public void select(int row, TableColumnBase column) {
370 |
371 | }
372 |
373 | @Override
374 | public void clearAndSelect(int row, TableColumnBase column) {
375 |
376 | }
377 |
378 | @Override
379 | public void clearSelection(int row, TableColumnBase column) {
380 |
381 | }
382 |
383 | @Override
384 | public void selectLeftCell() {
385 |
386 | }
387 |
388 | @Override
389 | public void selectRightCell() {
390 |
391 | }
392 |
393 | @Override
394 | public void selectAboveCell() {
395 |
396 | }
397 |
398 | @Override
399 | public void selectBelowCell() {
400 |
401 | }
402 |
403 | @Override
404 | public void selectRange(int minRow, TableColumnBase minColumn, int maxRow, TableColumnBase maxColumn) {
405 |
406 | }
407 |
408 | @Override
409 | protected int getItemCount() {
410 | return 0;
411 | }
412 |
413 | @Override
414 | protected Object getModelItem(int index) {
415 | return null;
416 | }
417 |
418 | @Override
419 | protected void focus(int index) {
420 |
421 | }
422 |
423 | @Override
424 | protected int getFocusedIndex() {
425 | return 0;
426 | }
427 | });
428 | listViewSaved.setItems(observableListSavedConnections);
429 | listViewSaved.setCellFactory(new Callback, ListCell>() {
430 | @Override
431 | public ListCell call(ListView listView) {
432 | return new ListViewCell(Main.this);
433 | }
434 | });
435 | }
436 |
437 | @Override
438 | public void initialize(URL location, ResourceBundle resources) {
439 | assert listView != null : "fx:id=\"listView\" was not injected: check your FXML file.";
440 | setupListView();
441 | setupLogAppender();
442 | initializeSavedData();
443 | startDeviceListUpdateThread();
444 |
445 | menuItemDebug.setOnAction(new EventHandler() {
446 | @Override
447 | public void handle(ActionEvent actionEvent) {
448 | onScreenConsoleOutputDelegate.setShowDebug(menuItemDebug.isSelected());
449 | }
450 | });
451 | }
452 |
453 |
454 | }
455 |
--------------------------------------------------------------------------------
/ADBWiFiConnectGUI/src/main/java/dk/appdictive/adbwificonnect/OnScreenConsoleOutputDelegate.java:
--------------------------------------------------------------------------------
1 | package dk.appdictive.adbwificonnect;
2 |
3 | import javafx.scene.control.TextArea;
4 | import org.apache.log4j.AppenderSkeleton;
5 | import org.apache.log4j.spi.LoggingEvent;
6 |
7 | /**
8 | * Created by tobalr on 3/1/17.
9 | */
10 | public class OnScreenConsoleOutputDelegate extends AppenderSkeleton {
11 | public static final int MAX_LOG_LENGTH = 5000;
12 | private TextArea outputTextArea;
13 | private boolean showDebug = false;
14 | String fullLog = "", noDebugLog = "";
15 |
16 | public OnScreenConsoleOutputDelegate(TextArea outputTextArea) {
17 | this.outputTextArea = outputTextArea;
18 | }
19 |
20 | @Override
21 | protected void append(LoggingEvent loggingEvent) {
22 | String message = String.format("[%s] %s", loggingEvent.getLevel(), loggingEvent.getRenderedMessage());
23 |
24 | if (loggingEvent.getLevel().equals(org.apache.log4j.Level.DEBUG)) {
25 | if (showDebug) addToLogOutput(message);
26 | } else {
27 | addToLogOutput(message);
28 | noDebugLog = noDebugLog.substring(Math.max(0, noDebugLog.length() - MAX_LOG_LENGTH), noDebugLog.length());
29 | noDebugLog += message + "\n";
30 | }
31 |
32 | fullLog = fullLog.substring(Math.max(0, fullLog.length() - MAX_LOG_LENGTH), fullLog.length());
33 | fullLog += message + "\n";
34 | }
35 |
36 |
37 | @Override
38 | public void close() {
39 | addToLogOutput("--Closing--");
40 | }
41 |
42 | @Override
43 | public boolean requiresLayout() {
44 | return false;
45 | }
46 |
47 | private void addToLogOutput(String message) {
48 | int length = outputTextArea.getText().length();
49 | outputTextArea.deleteText(0, Math.max(0, length - MAX_LOG_LENGTH));
50 | outputTextArea.appendText(message + "\n");
51 | }
52 |
53 | public void setShowDebug(boolean showDebug) {
54 | this.showDebug = showDebug;
55 | if (showDebug) {
56 | outputTextArea.setText(fullLog);
57 | } else {
58 | outputTextArea.setText(noDebugLog);
59 | }
60 |
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/ADBWiFiConnectGUI/src/main/java/dk/appdictive/adbwificonnect/SerializeHelper.java:
--------------------------------------------------------------------------------
1 | package dk.appdictive.adbwificonnect;
2 |
3 | import java.io.*;
4 | import java.util.Base64;
5 |
6 | /**
7 | * Created by JesperLR on 21-May-17.
8 | */
9 | public class SerializeHelper {
10 |
11 | public static String serializeArray(Device[] array) {
12 | // serialize
13 | ByteArrayOutputStream out = new ByteArrayOutputStream();
14 | try {
15 | new ObjectOutputStream(out).writeObject(array);
16 | } catch (IOException e) {
17 | e.printStackTrace();
18 | }
19 |
20 | // your string
21 | String serializedArray = new String(Base64.getEncoder().encode(out.toByteArray()));
22 | return serializedArray;
23 | }
24 |
25 | public static Device[] deserializeArray(String serializedArray) {
26 | // deserialize
27 | try {
28 | ByteArrayInputStream in = new ByteArrayInputStream(Base64.getDecoder().decode(serializedArray.getBytes()));
29 | return (Device[]) new ObjectInputStream(in).readObject();
30 | } catch (IOException e) {
31 | e.printStackTrace();
32 | } catch (ClassNotFoundException e) {
33 | e.printStackTrace();
34 | } catch (IllegalArgumentException e) {
35 | e.printStackTrace();
36 | } catch (ClassCastException cce) {
37 | cce.printStackTrace();
38 | }
39 | return null;
40 | }
41 |
42 | }
43 |
--------------------------------------------------------------------------------
/ADBWiFiConnectGUI/src/main/resources/icons/ic_adbremoteconnect.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/appdictive/ADBWiFiConnect/cca0aa79753c1f5a8e050300149a85b802722c0b/ADBWiFiConnectGUI/src/main/resources/icons/ic_adbremoteconnect.png
--------------------------------------------------------------------------------
/ADBWiFiConnectGUI/src/main/resources/icons/ic_adbremoteconnect@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/appdictive/ADBWiFiConnect/cca0aa79753c1f5a8e050300149a85b802722c0b/ADBWiFiConnectGUI/src/main/resources/icons/ic_adbremoteconnect@2x.png
--------------------------------------------------------------------------------
/ADBWiFiConnectGUI/src/main/resources/list_cell_item.fxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
20 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/ADBWiFiConnectGUI/src/main/resources/main.fxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
20 |
21 |
22 |
23 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
--------------------------------------------------------------------------------
/ADBWiFiConnectGUI/src/main/resources/stylesheet.css:
--------------------------------------------------------------------------------
1 | .button-raised-primary{
2 | -fx-padding: 0.5em 0.57em;
3 | -fx-font-size: 12px;
4 | -jfx-button-type: FLAT;
5 | -fx-background-color: #00897b;
6 | -fx-text-fill: WHITE;
7 | }
8 |
9 | .button-raised-secondary{
10 | -fx-padding: 0.5em 0.57em;
11 | -fx-font-size: 12px;
12 | -jfx-button-type: FLAT;
13 | }
14 |
15 | .label-header{
16 | -fx-font-weight: bold;
17 | }
--------------------------------------------------------------------------------
/ADBWiFiConnect_screen1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/appdictive/ADBWiFiConnect/cca0aa79753c1f5a8e050300149a85b802722c0b/ADBWiFiConnect_screen1.png
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ADB WiFi Connect
2 | ====================
3 |
4 | A simple quality of life project, making it easier to remote connect your daily developer phone so it isn't necessary to have the device connected via USB.
5 |
6 |
7 | Usage
8 | ====================
9 |
10 | To use in Android Studio (or other IntelliJ IDE) get the plugin here: https://plugins.jetbrains.com/plugin/9717-adb-wifi-connect.
11 |
12 | ADB WiFi Connect enables you to ADB connect to your Android devices over WiFi to run and debug your Android apps without needing a USB cable (except for initial connect).
13 | The window shows you a live updated list of Android devices connected to the computer - including their Android version name and SDK levels.
14 | For each USB connected Android device you can connect to it over WiFi and then save the connection for future use so next time you won't even need the cable at all!
15 | After establishing connection over WiFi you can unplug the USB cable and continue developing and debugging wirelessly.
16 |
17 | 
18 |
19 | License
20 | ====================
21 |
22 | MIT License
23 |
24 | Copyright (c) 2016 Appdictive ApS
25 |
26 | Permission is hereby granted, free of charge, to any person obtaining a copy
27 | of this software and associated documentation files (the "Software"), to deal
28 | in the Software without restriction, including without limitation the rights
29 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
30 | copies of the Software, and to permit persons to whom the Software is
31 | furnished to do so, subject to the following conditions:
32 |
33 | The above copyright notice and this permission notice shall be included in all
34 | copies or substantial portions of the Software.
35 |
36 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
37 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
38 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
39 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
40 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
41 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
42 | SOFTWARE.
43 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | repositories {
3 | mavenCentral()
4 | }
5 | }
6 |
7 | plugins {
8 | id "org.jetbrains.intellij" version "0.0.25"
9 | }
10 |
11 | apply plugin: 'org.jetbrains.intellij'
12 | apply plugin: 'java'
13 |
14 | group 'com.github.appdictive'
15 | version '1.7'
16 |
17 | sourceCompatibility = 1.6
18 |
19 | repositories {
20 | mavenCentral()
21 | }
22 |
23 | intellij {
24 | version '14.1.5'
25 | pluginName 'ADBWiFiConnect'
26 | plugins 'android'
27 | updateSinceUntilBuild false
28 | }
29 |
30 | dependencies {
31 | compile project(':ADBWiFiConnectGUI')
32 | }
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/appdictive/ADBWiFiConnect/cca0aa79753c1f5a8e050300149a85b802722c0b/gradle.properties
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/appdictive/ADBWiFiConnect/cca0aa79753c1f5a8e050300149a85b802722c0b/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Tue Dec 15 00:42:48 CET 2015
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.7-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >&-
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >&-
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | rootProject.name = 'ADBWiFiConnect'
2 | include 'ADBWiFiConnectGUI'
3 |
4 |
--------------------------------------------------------------------------------
/src/main/java/dk/appdictive/adbwificonnect/plugin/OSValidator.java:
--------------------------------------------------------------------------------
1 | package dk.appdictive.adbwificonnect.plugin;
2 |
3 | /**
4 | * Author: Domenico Monaco, Yong Mook Kim
5 | *
6 | * Source: https://gist.github.com/kiuz/816e24aa787c2d102dd0
7 | *
8 | * License: GNU v2 2014
9 | *
10 | * Fork / Learned: http://www.mkyong.com/java/how-to-detect-os-in-java-systemgetpropertyosname/
11 | *
12 | */
13 |
14 | public class OSValidator {
15 |
16 | private static String OS = System.getProperty("os.name").toLowerCase();
17 |
18 | public static boolean isWindows() {
19 | return (OS.indexOf("win") >= 0);
20 | }
21 |
22 | public static boolean isMac() {
23 | return (OS.indexOf("mac") >= 0);
24 | }
25 |
26 | public static boolean isUnix() {
27 | return (OS.indexOf("nix") >= 0 || OS.indexOf("nux") >= 0 || OS.indexOf("aix") > 0 );
28 | }
29 |
30 | public static boolean isSolaris() {
31 | return (OS.indexOf("sunos") >= 0);
32 | }
33 |
34 | }
--------------------------------------------------------------------------------
/src/main/java/dk/appdictive/adbwificonnect/plugin/RemoteConnect.java:
--------------------------------------------------------------------------------
1 | package dk.appdictive.adbwificonnect.plugin;
2 |
3 | import com.intellij.notification.Notification;
4 | import com.intellij.notification.NotificationGroup;
5 | import com.intellij.notification.NotificationType;
6 | import com.intellij.notification.Notifications;
7 | import com.intellij.openapi.actionSystem.AnAction;
8 | import com.intellij.openapi.actionSystem.AnActionEvent;
9 | import com.intellij.openapi.application.ApplicationManager;
10 | import com.intellij.openapi.application.PathManager;
11 | import com.intellij.openapi.project.Project;
12 | import org.jetbrains.android.sdk.AndroidSdkUtils;
13 |
14 | import java.io.File;
15 | import java.util.prefs.BackingStoreException;
16 | import java.util.prefs.Preferences;
17 |
18 |
19 | /**
20 | * Created by JesperLR on 29-10-2016.
21 | */
22 | public class RemoteConnect extends AnAction {
23 |
24 | private static final String PREF_JAR_LOCATION = "JAR_LOCATION", PREF_ADB_LOCATION = "ADB_LOCATION", PREFS_ID = "dk/appdictive/adbconnect";
25 | private Preferences prefs;
26 |
27 | private static final String WIFI_CONNECT_TITLE = "ADB WiFi Connect";
28 | private static final NotificationGroup NOTIFICATION_GROUP =
29 | NotificationGroup.balloonGroup(WIFI_CONNECT_TITLE);
30 |
31 |
32 | @Override
33 | public void actionPerformed(AnActionEvent e) {
34 | // Messages.showMessageDialog(e.getProject(), "isAndroidSdkAvailable: " + AndroidSdkUtils.isAndroidSdkAvailable() + " AndroidSDKPath: " + AndroidSdkUtils.getAdb(e.getProject()).getAbsolutePath(), "Information", Messages.getInformationIcon());
35 | if (isADBInstalled() && getAdbPath(e.getProject()) != null) {
36 | launchADBWiFiConnect(e);
37 | } else {
38 | showNotification("adb not found in your environment, please check Android SDK installation and setup, and confirm that adb is available from commandline.", NotificationType.ERROR);
39 | }
40 | }
41 |
42 | private void launchADBWiFiConnect(AnActionEvent e) {
43 | String pluginsPath = PathManager.getPluginsPath();
44 | String path = "\"" + pluginsPath + File.separator + "ADBWiFiConnect" + File.separator + "lib" + File.separator + "ADBWiFiConnectGUI.jar" + "\"";
45 |
46 | // Retrieve the user preference node for the package
47 | Preferences systemRoot = Preferences.userRoot();
48 | prefs = systemRoot.node(PREFS_ID);
49 |
50 | prefs.put(PREF_JAR_LOCATION, path);
51 | String adbPath = getAdbPath(e.getProject());
52 | prefs.put(PREF_ADB_LOCATION, adbPath);
53 | try {
54 | prefs.flush();
55 | } catch (BackingStoreException ex) {
56 | ex.printStackTrace();
57 | }
58 |
59 | if (OSValidator.isMac() || OSValidator.isUnix()) {
60 | String[] commandtest = new String[] {
61 | "/bin/sh",
62 | "-c",
63 | "cd / && " + "java -jar " + path+""
64 | };
65 |
66 | try {
67 | Runtime.getRuntime().exec(commandtest, null);
68 | } catch (Exception e1) {
69 | e1.printStackTrace();
70 | }
71 | } else if (OSValidator.isWindows()) {
72 | String[] commandtest = new String[] {
73 | "cmd.exe",
74 | "/c",
75 | "cd / && " + "javaw -jar " + path+""
76 | };
77 |
78 | try {
79 | Runtime.getRuntime().exec(commandtest, null);
80 | } catch (Exception e1) {
81 | e1.printStackTrace();
82 | }
83 | }
84 | }
85 |
86 | public boolean isADBInstalled() {
87 | return AndroidSdkUtils.isAndroidSdkAvailable();
88 | }
89 |
90 | public static void showNotification(final String message,
91 | final NotificationType type) {
92 | ApplicationManager.getApplication().invokeLater(new Runnable() {
93 | @Override public void run() {
94 | Notification notification =
95 | NOTIFICATION_GROUP.createNotification(WIFI_CONNECT_TITLE, message, type, null);
96 | Notifications.Bus.notify(notification);
97 | }
98 | });
99 | }
100 |
101 | private String getAdbPath(Project project) {
102 | String adbPath = "";
103 | File adbFile = AndroidSdkUtils.getAdb(project);
104 | if (adbFile != null) {
105 | adbPath = adbFile.getAbsolutePath();
106 | }
107 | return adbPath;
108 | }
109 |
110 |
111 |
112 | }
113 |
114 |
--------------------------------------------------------------------------------
/src/main/resources/META-INF/plugin.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | dk.appdictive.adbwificonnect
4 | ADB WiFi Connect
5 | 1.7
6 | Appdictive
7 |
8 |
10 | The window shows you a live updated list of Android devices connected to the computer - including their Android version name and SDK levels.
11 | For each USB connected Android device you can connect to it over WiFi and then save the connection for future use so next time you won't even need the cable at all!
12 | After establishing connection over WiFi you can unplug the USB cable and continue developing and debugging wirelessly.
13 | ]]>
14 |
15 |
19 |
20 |
21 |
22 |
23 |
24 |
26 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 | org.jetbrains.android
46 |
47 |
48 | Add your actions here
49 |
50 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
--------------------------------------------------------------------------------
/src/main/resources/icons/ic_adbremoteconnect.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/appdictive/ADBWiFiConnect/cca0aa79753c1f5a8e050300149a85b802722c0b/src/main/resources/icons/ic_adbremoteconnect.png
--------------------------------------------------------------------------------
/src/main/resources/icons/ic_adbremoteconnect@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/appdictive/ADBWiFiConnect/cca0aa79753c1f5a8e050300149a85b802722c0b/src/main/resources/icons/ic_adbremoteconnect@2x.png
--------------------------------------------------------------------------------