diff --git a/README.md b/README.md
index 9a0f47a..c0d50b8 100644
--- a/README.md
+++ b/README.md
@@ -41,9 +41,9 @@ To use JNLP, please follow this article: [How can I configure the Exception Site
## Building and running from source
-This project requires at least Java 7 and Maven 3.2.5.
+This project requires at least Java 8 and Maven 3.2.5.
-After cloning the project, run `mvn package`.
+After cloning the project, run `mvn install`.
The resulting artifacts will be created in the `target` subdirectory.
@@ -52,6 +52,11 @@ the current version.
For example, `java -jar target/androidscreencast-0.0.7s-executable.jar`.
+Additionally OS-packages would be created with ADB executables bundled:
+* `androidscreencast-VERSION-windows.zip`
+* `androidscreencast-VERSION-linux.tar.gz`
+* `androidscreencast-VERSION-macosx.tar.gz`
+
# Requirements
Currently AndroidScreencast works directly with `adb input` program through `ddmlib` and abuse functionality of:
@@ -63,7 +68,7 @@ Regarding this point, to use AndroidScreencast you need Smartphone running on An
So, right now AndroidScreencast support all Android versions equal or greater than Android 4.1.1.
-Also, to run AndroidScreencast you will need adb installed (or you can use bundled in [androidscreencast.7z][latest_release] adb).
+Also, to run AndroidScreencast you will need *adb* installed (or you can use bundled in OS bundles adb).
[Android_4_1_1_Input]: http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.1.1_r1/com/android/commands/input/Input.java#Input
diff --git a/adb/linux/adb b/adb/linux/adb
new file mode 100644
index 0000000..3c28311
Binary files /dev/null and b/adb/linux/adb differ
diff --git a/adb/linux/fastboot b/adb/linux/fastboot
new file mode 100644
index 0000000..b147d23
Binary files /dev/null and b/adb/linux/fastboot differ
diff --git a/adb/macosx/adb b/adb/macosx/adb
new file mode 100644
index 0000000..738344f
Binary files /dev/null and b/adb/macosx/adb differ
diff --git a/adb/macosx/fastboot b/adb/macosx/fastboot
new file mode 100644
index 0000000..d918163
Binary files /dev/null and b/adb/macosx/fastboot differ
diff --git a/adb/windows/AdbWinApi.dll b/adb/windows/AdbWinApi.dll
new file mode 100644
index 0000000..7abe26c
Binary files /dev/null and b/adb/windows/AdbWinApi.dll differ
diff --git a/adb/windows/AdbWinUsbApi.dll b/adb/windows/AdbWinUsbApi.dll
new file mode 100644
index 0000000..e7a6de1
Binary files /dev/null and b/adb/windows/AdbWinUsbApi.dll differ
diff --git a/adb/windows/adb.exe b/adb/windows/adb.exe
new file mode 100644
index 0000000..ca474cd
Binary files /dev/null and b/adb/windows/adb.exe differ
diff --git a/adb/windows/fastboot.exe b/adb/windows/fastboot.exe
new file mode 100644
index 0000000..c28d87a
Binary files /dev/null and b/adb/windows/fastboot.exe differ
diff --git a/app.properties b/app.properties
index 0b4cb24..2d7c1f7 100644
--- a/app.properties
+++ b/app.properties
@@ -1,3 +1,3 @@
-adb.path=adb.exe
+adb.path=adb/windows/adb.exe
default.window.width=1024
default.window.height=768
\ No newline at end of file
diff --git a/lib/AdbWinApi.dll b/lib/AdbWinApi.dll
deleted file mode 100644
index b5586eb..0000000
Binary files a/lib/AdbWinApi.dll and /dev/null differ
diff --git a/lib/AdbWinUsbApi.dll b/lib/AdbWinUsbApi.dll
deleted file mode 100644
index 0c9e00b..0000000
Binary files a/lib/AdbWinUsbApi.dll and /dev/null differ
diff --git a/lib/adb.exe b/lib/adb.exe
deleted file mode 100644
index 24b5a95..0000000
Binary files a/lib/adb.exe and /dev/null differ
diff --git a/lib/fastboot.exe b/lib/fastboot.exe
deleted file mode 100644
index 0e47b3d..0000000
Binary files a/lib/fastboot.exe and /dev/null differ
diff --git a/pom.xml b/pom.xml
index 1e8ac5e..fafee14 100644
--- a/pom.xml
+++ b/pom.xml
@@ -3,54 +3,69 @@
4.0.0com.github.xsavikxandroidscreencast
- 0.0.7s
+ 0.0.8sAndroid Screencast
- 4.2.6.RELEASE
- 25.1.0
- 1.2.17
- com.github.xsavikx.androidscreencast.Main
- 1.7
+ 4.3.1.RELEASE
+ 25.2.0
+ 1.2.17
+ com.github.xsavikx.androidscreencast.Main
+ 1.8UTF-8
+ ${project.basedir}/adb
+ ${adb.folder}/linux
+ ${adb.folder}/windows
+ ${adb.folder}/macosxcom.android.tools.ddmsddmlib
- ${ddmlib-version}
+ ${ddmlib.version}log4jlog4j
- ${log4j-version}
+ ${log4j.version}org.springframeworkspring-core
- ${spring-version}
+ ${spring.version}org.springframeworkspring-beans
- ${spring-version}
+ ${spring.version}org.springframeworkspring-context
- ${spring-version}
+ ${spring.version}maven-compiler-plugin
- 3.5.1
+ 3.6.0
-
- ${jdk-version}
+
+ ${jdk.version}
+
+
+
+ org.apache.maven.plugins
+ maven-jar-plugin
+ 3.0.2
+
+
+
+ ${main.class}
+
+
-
org.apache.maven.pluginsmaven-shade-plugin
@@ -67,25 +82,33 @@
- ${main-class}
+ ${main.class}
-
org.apache.maven.plugins
- maven-jar-plugin
- 2.6
+ maven-assembly-plugin
+ 3.0.0
-
-
- ${main-class}
-
-
+
+ src/assembly/windows.xml
+ src/assembly/linux.xml
+ src/assembly/macosx.xml
+
+
+
+ make-assembly
+ verify
+
+ single
+
+
+
diff --git a/src/assembly/linux.xml b/src/assembly/linux.xml
new file mode 100644
index 0000000..d5e64ea
--- /dev/null
+++ b/src/assembly/linux.xml
@@ -0,0 +1,30 @@
+
+ linux
+
+ tar.gz
+
+
+
+ ${project.basedir}
+
+
+ README*
+ LICENSE*
+ NOTICE*
+
+
+
+ ${project.build.directory}
+
+
+ androidscreencast*executable.jar
+
+
+
+ ${adb.folder.linux}
+
+
+
+
\ No newline at end of file
diff --git a/src/assembly/macosx.xml b/src/assembly/macosx.xml
new file mode 100644
index 0000000..9fed631
--- /dev/null
+++ b/src/assembly/macosx.xml
@@ -0,0 +1,30 @@
+
+ macosx
+
+ tar.gz
+
+
+
+ ${project.basedir}
+
+
+ README*
+ LICENSE*
+ NOTICE*
+
+
+
+ ${project.build.directory}
+
+
+ androidscreencast*executable.jar
+
+
+
+ ${adb.folder.macosx}
+
+
+
+
\ No newline at end of file
diff --git a/src/assembly/windows.xml b/src/assembly/windows.xml
new file mode 100644
index 0000000..8890e82
--- /dev/null
+++ b/src/assembly/windows.xml
@@ -0,0 +1,30 @@
+
+ windows
+
+ zip
+
+
+
+ ${project.basedir}
+
+
+ README*
+ LICENSE*
+ NOTICE*
+
+
+
+ ${project.build.directory}
+
+
+ androidscreencast*executable.jar
+
+
+
+ ${adb.folder.windows}
+
+
+
+
\ No newline at end of file
diff --git a/src/main/java/com/github/xsavikx/androidscreencast/Main.java b/src/main/java/com/github/xsavikx/androidscreencast/Main.java
index 6b8477a..32a10bb 100644
--- a/src/main/java/com/github/xsavikx/androidscreencast/Main.java
+++ b/src/main/java/com/github/xsavikx/androidscreencast/Main.java
@@ -12,12 +12,14 @@ public class Main {
public static void main(String args[]) {
LOGGER.debug("main(String[] args=" + Arrays.toString(args) + ") - start");
- Application application = ApplicationContextProvider.getApplicationContext()
- .getBean(AndroidScreencastApplication.class);
- application.init();
- application.start();
-
- LOGGER.debug("main(String[] args=" + Arrays.toString(args) + ") - end");
+ Application application;
+ try {
+ application = ApplicationContextProvider.getBean(AndroidScreencastApplication.class);
+ application.init();
+ application.start();
+ } finally {
+ LOGGER.debug("main(String[] args=" + Arrays.toString(args) + ") - end");
+ }
}
}
diff --git a/src/main/java/com/github/xsavikx/androidscreencast/api/AndroidDeviceImpl.java b/src/main/java/com/github/xsavikx/androidscreencast/api/AndroidDeviceImpl.java
index b283333..d339c19 100644
--- a/src/main/java/com/github/xsavikx/androidscreencast/api/AndroidDeviceImpl.java
+++ b/src/main/java/com/github/xsavikx/androidscreencast/api/AndroidDeviceImpl.java
@@ -5,6 +5,7 @@
import com.android.ddmlib.SyncService.ISyncProgressMonitor;
import com.github.xsavikx.androidscreencast.api.file.FileInfo;
import com.github.xsavikx.androidscreencast.api.injector.OutputStreamShellOutputReceiver;
+import com.github.xsavikx.androidscreencast.exception.ExecuteCommandException;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@@ -18,13 +19,9 @@
@Component
public class AndroidDeviceImpl implements AndroidDevice {
private static final Logger logger = Logger.getLogger(AndroidDeviceImpl.class);
- @Autowired(required = false)
- private IDevice device;
-
- public AndroidDeviceImpl() {
-
- }
+ private final IDevice device;
+ @Autowired(required = false)
public AndroidDeviceImpl(IDevice device) {
this.device = device;
}
@@ -46,7 +43,7 @@ public String executeCommand(String cmd) {
} catch (Exception ex) {
logger.error("executeCommand(String)", ex);
- throw new RuntimeException(ex);
+ throw new ExecuteCommandException(cmd);
}
}
@@ -64,15 +61,12 @@ public List list(String path) {
String[] data = entry.split(" ");
if (data.length < 4)
continue;
- /*
- * for(int j=0; j
- * The close method of FilterOutputStream calls its flush method, and then calls the close
+ * The stop method of FilterOutputStream calls its flush method, and then calls the stop
* method of its underlying output stream.
*
* @throws IOException if an I/O error occurs.
diff --git a/src/main/java/com/github/xsavikx/androidscreencast/api/recording/QuickTimeOutputStream.java b/src/main/java/com/github/xsavikx/androidscreencast/api/recording/QuickTimeOutputStream.java
index 313833f..fc27c29 100644
--- a/src/main/java/com/github/xsavikx/androidscreencast/api/recording/QuickTimeOutputStream.java
+++ b/src/main/java/com/github/xsavikx/androidscreencast/api/recording/QuickTimeOutputStream.java
@@ -1246,7 +1246,7 @@ public void writeFrame(BufferedImage image, int duration) throws IOException {
* add JPG files if you have chosen the JPEG video format.
*
* If you add all frames from files or from input streams, then you have to explicitly set the dimension of the video track before you call finish()
- * or close().
+ * or stop().
*
* @param file The file which holds the image data.
* @param duration The duration of the frame in time scale units.
@@ -1267,7 +1267,7 @@ public void writeFrame(File file, int duration) throws IOException {
* to only add JPG files if you have chosen the JPEG video format.
*
* If you add all frames from files or from input streams, then you have to explicitly set the dimension of the video track before you call finish()
- * or close().
+ * or stop().
*
* @param in The input stream which holds the image data.
* @param duration The duration of the frame in time scale units.
diff --git a/src/main/java/com/github/xsavikx/androidscreencast/app/AndroidScreencastApplication.java b/src/main/java/com/github/xsavikx/androidscreencast/app/AndroidScreencastApplication.java
index bd9dfdc..7aee5f2 100644
--- a/src/main/java/com/github/xsavikx/androidscreencast/app/AndroidScreencastApplication.java
+++ b/src/main/java/com/github/xsavikx/androidscreencast/app/AndroidScreencastApplication.java
@@ -11,15 +11,16 @@
import org.springframework.stereotype.Component;
import javax.swing.*;
+import java.awt.*;
@Component
public class AndroidScreencastApplication extends SwingApplication {
private static final Logger LOGGER = Logger.getLogger(AndroidScreencastApplication.class);
-
private final Environment environment;
private final JFrameMain jFrameMain;
private final Injector injector;
private final IDevice iDevice;
+ private transient boolean isStopped = false;
@Autowired
public AndroidScreencastApplication(Injector injector, IDevice iDevice, JFrameMain jFrameMain, Environment environment) {
@@ -30,37 +31,48 @@ public AndroidScreencastApplication(Injector injector, IDevice iDevice, JFrameMa
}
@Override
- public void close() {
- LOGGER.debug("close() - start");
-
- if (injector != null)
- injector.close();
-
- if (iDevice != null) {
- synchronized (iDevice) {
- if (hasFilledAdbPath())
- AndroidDebugBridge.disconnectBridge();
- AndroidDebugBridge.terminate();
+ public void stop() {
+ try {
+ LOGGER.debug("stop() - start");
+ if (isStopped) {
+ LOGGER.debug("Application is already stopped.");
+ return;
+ }
+ if (injector != null)
+ injector.stop();
+
+ if (iDevice != null) {
+ synchronized (iDevice) {
+ if (hasFilledAdbPath())
+ AndroidDebugBridge.disconnectBridge();
+ AndroidDebugBridge.terminate();
+ }
}
+ for (Frame frame : Frame.getFrames()) {
+ frame.dispose();
+ }
+ isStopped = true;
+ } finally {
+ LOGGER.debug("stop() - end");
}
- LOGGER.debug("close() - end");
}
@Override
public void start() {
LOGGER.debug("start() - start");
- SwingUtilities.invokeLater(new Runnable() {
- @Override
- public void run() {
- // Start showing the iDevice screen
- jFrameMain.setTitle("" + iDevice);
+ if (iDevice == null) {
+ LOGGER.warn("No valid device was chosen. Please try to chose correct one.");
+ stop();
+ }
+ SwingUtilities.invokeLater(() -> {
+ // Start showing the iDevice screen
+ jFrameMain.setTitle("" + iDevice);
- // Show window
- jFrameMain.setVisible(true);
+ // Show window
+ jFrameMain.setVisible(true);
- jFrameMain.launchInjector();
- }
+ jFrameMain.launchInjector();
});
LOGGER.debug("start() - end");
}
diff --git a/src/main/java/com/github/xsavikx/androidscreencast/app/Application.java b/src/main/java/com/github/xsavikx/androidscreencast/app/Application.java
index b82c8d9..feb0248 100644
--- a/src/main/java/com/github/xsavikx/androidscreencast/app/Application.java
+++ b/src/main/java/com/github/xsavikx/androidscreencast/app/Application.java
@@ -2,7 +2,7 @@
public interface Application {
- void close();
+ void stop();
void handleException(Thread thread, Throwable ex);
diff --git a/src/main/java/com/github/xsavikx/androidscreencast/app/DeviceChooserApplication.java b/src/main/java/com/github/xsavikx/androidscreencast/app/DeviceChooserApplication.java
index 6382ba3..9346f39 100644
--- a/src/main/java/com/github/xsavikx/androidscreencast/app/DeviceChooserApplication.java
+++ b/src/main/java/com/github/xsavikx/androidscreencast/app/DeviceChooserApplication.java
@@ -3,6 +3,8 @@
import com.android.ddmlib.AndroidDebugBridge;
import com.android.ddmlib.IDevice;
import com.github.xsavikx.androidscreencast.constant.Constants;
+import com.github.xsavikx.androidscreencast.exception.NoDeviceChosenException;
+import com.github.xsavikx.androidscreencast.exception.WaitDeviceListTimeoutException;
import com.github.xsavikx.androidscreencast.ui.JDialogDeviceList;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
@@ -13,15 +15,19 @@
public class DeviceChooserApplication extends SwingApplication {
private static final Logger LOGGER = Logger.getLogger(DeviceChooserApplication.class);
- @Autowired
- private Environment env;
- @Autowired
- private AndroidDebugBridge bridge;
+ private final Environment env;
+ private final AndroidDebugBridge bridge;
private IDevice device;
+ @Autowired
+ public DeviceChooserApplication(Environment env, AndroidDebugBridge bridge) {
+ this.env = env;
+ this.bridge = bridge;
+ }
+
@Override
- public void close() {
+ public void stop() {
// ignore
}
@@ -29,7 +35,6 @@ public void close() {
public void start() {
LOGGER.debug("start() - start");
initialize();
-
LOGGER.debug("start() - end");
}
@@ -38,10 +43,10 @@ public void start() {
protected boolean isNativeLook() {
LOGGER.debug("isNativeLook() - start");
- boolean returnboolean = env.getProperty(Constants.APP_NATIVE_LOOK_PROPERTY, Boolean.class,
+ boolean nativeLook = env.getProperty(Constants.APP_NATIVE_LOOK_PROPERTY, Boolean.class,
Constants.DEFAULT_APP_NATIVE_LOOK);
LOGGER.debug("isNativeLook() - end");
- return returnboolean;
+ return nativeLook;
}
private void waitDeviceList(AndroidDebugBridge bridge) {
@@ -58,7 +63,7 @@ private void waitDeviceList(AndroidDebugBridge bridge) {
}
// let's not wait > 10 sec.
if (count > 300) {
- throw new RuntimeException("Timeout getting device list!");
+ throw new WaitDeviceListTimeoutException();
}
}
@@ -79,14 +84,14 @@ private void initialize() {
jd.setVisible(true);
device = jd.getDevice();
+ if (device == null) {
+ return;
+ }
}
- if (device == null) {
- System.exit(0);
- LOGGER.debug("initialize() - end");
- return;
+ if (device == null) {
+ throw new NoDeviceChosenException();
}
-
LOGGER.debug("initialize() - end");
}
diff --git a/src/main/java/com/github/xsavikx/androidscreencast/app/GUIApplication.java b/src/main/java/com/github/xsavikx/androidscreencast/app/GUIApplication.java
index 5f22a4e..19e6fc7 100644
--- a/src/main/java/com/github/xsavikx/androidscreencast/app/GUIApplication.java
+++ b/src/main/java/com/github/xsavikx/androidscreencast/app/GUIApplication.java
@@ -1,25 +1,15 @@
package com.github.xsavikx.androidscreencast.app;
-import java.lang.Thread.UncaughtExceptionHandler;
-
public abstract class GUIApplication implements Application {
public GUIApplication() {
- Runtime.getRuntime().addShutdownHook(new Thread() {
- @Override
- public void run() {
- close();
- }
- });
- Thread.setDefaultUncaughtExceptionHandler(new UncaughtExceptionHandler() {
- @Override
- public void uncaughtException(Thread arg0, Throwable ex) {
- try {
- handleException(arg0, ex);
- } catch (Exception ex2) {
- // ignored
- ex2.printStackTrace();
- }
+ Runtime.getRuntime().addShutdownHook(new Thread(GUIApplication.this::stop));
+ Thread.setDefaultUncaughtExceptionHandler((thread, ex) -> {
+ try {
+ handleException(thread, ex);
+ } catch (Exception ex2) {
+ // ignored
+ ex2.printStackTrace();
}
});
}
diff --git a/src/main/java/com/github/xsavikx/androidscreencast/app/SwingApplication.java b/src/main/java/com/github/xsavikx/androidscreencast/app/SwingApplication.java
index 85dc733..e0a76be 100644
--- a/src/main/java/com/github/xsavikx/androidscreencast/app/SwingApplication.java
+++ b/src/main/java/com/github/xsavikx/androidscreencast/app/SwingApplication.java
@@ -32,13 +32,7 @@ public void handleException(Thread thread, Throwable ex) {
if (jd != null && jd.isVisible())
return;
jd = new JDialogError(ex);
- SwingUtilities.invokeLater(new Runnable() {
-
- @Override
- public void run() {
- jd.setVisible(true);
- }
- });
+ SwingUtilities.invokeLater(() -> jd.setVisible(true));
} catch (Exception ex2) {
// ignored
}
diff --git a/src/main/java/com/github/xsavikx/androidscreencast/exception/AndroidScreenCastRuntimeException.java b/src/main/java/com/github/xsavikx/androidscreencast/exception/AndroidScreenCastRuntimeException.java
new file mode 100644
index 0000000..155a9f9
--- /dev/null
+++ b/src/main/java/com/github/xsavikx/androidscreencast/exception/AndroidScreenCastRuntimeException.java
@@ -0,0 +1,34 @@
+package com.github.xsavikx.androidscreencast.exception;
+
+public class AndroidScreenCastRuntimeException extends RuntimeException {
+ private String additionalInformation;
+
+ public AndroidScreenCastRuntimeException() {
+ }
+
+ public AndroidScreenCastRuntimeException(String message) {
+ super(message);
+ }
+
+
+ public AndroidScreenCastRuntimeException(String message, String additionalInformation) {
+ super(message);
+ this.additionalInformation = additionalInformation;
+ }
+
+ public AndroidScreenCastRuntimeException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public AndroidScreenCastRuntimeException(Throwable cause) {
+ super(cause);
+ }
+
+ public AndroidScreenCastRuntimeException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
+ super(message, cause, enableSuppression, writableStackTrace);
+ }
+
+ public String getAdditionalInformation() {
+ return additionalInformation;
+ }
+}
diff --git a/src/main/java/com/github/xsavikx/androidscreencast/exception/ExecuteCommandException.java b/src/main/java/com/github/xsavikx/androidscreencast/exception/ExecuteCommandException.java
new file mode 100644
index 0000000..6a2861b
--- /dev/null
+++ b/src/main/java/com/github/xsavikx/androidscreencast/exception/ExecuteCommandException.java
@@ -0,0 +1,7 @@
+package com.github.xsavikx.androidscreencast.exception;
+
+public class ExecuteCommandException extends AndroidScreenCastRuntimeException {
+ public ExecuteCommandException(String command) {
+ super(String.format("Cannot execute command '%s'.", command));
+ }
+}
diff --git a/src/main/java/com/github/xsavikx/androidscreencast/exception/NoDeviceChosenException.java b/src/main/java/com/github/xsavikx/androidscreencast/exception/NoDeviceChosenException.java
new file mode 100644
index 0000000..53a492d
--- /dev/null
+++ b/src/main/java/com/github/xsavikx/androidscreencast/exception/NoDeviceChosenException.java
@@ -0,0 +1,7 @@
+package com.github.xsavikx.androidscreencast.exception;
+
+public class NoDeviceChosenException extends AndroidScreenCastRuntimeException {
+ public NoDeviceChosenException() {
+ super("No device was chosen or connected via ADB.", "Try to choose correct ADB path or reconnect your device.");
+ }
+}
diff --git a/src/main/java/com/github/xsavikx/androidscreencast/exception/WaitDeviceListTimeoutException.java b/src/main/java/com/github/xsavikx/androidscreencast/exception/WaitDeviceListTimeoutException.java
new file mode 100644
index 0000000..fa45499
--- /dev/null
+++ b/src/main/java/com/github/xsavikx/androidscreencast/exception/WaitDeviceListTimeoutException.java
@@ -0,0 +1,7 @@
+package com.github.xsavikx.androidscreencast.exception;
+
+public class WaitDeviceListTimeoutException extends AndroidScreenCastRuntimeException {
+ public WaitDeviceListTimeoutException() {
+ super("Cannot initialize devices list.", "Try to choose correct ADB path or reconnect your device.");
+ }
+}
diff --git a/src/main/java/com/github/xsavikx/androidscreencast/spring/config/ApplicationConfiguration.java b/src/main/java/com/github/xsavikx/androidscreencast/spring/config/ApplicationConfiguration.java
index 06fd945..83d539a 100644
--- a/src/main/java/com/github/xsavikx/androidscreencast/spring/config/ApplicationConfiguration.java
+++ b/src/main/java/com/github/xsavikx/androidscreencast/spring/config/ApplicationConfiguration.java
@@ -9,18 +9,17 @@
import org.springframework.context.annotation.*;
import org.springframework.core.env.Environment;
+import javax.annotation.PreDestroy;
+
@Configuration
@ComponentScan(basePackages = "com.github.xsavikx.androidscreencast")
@PropertySources(value = {
@PropertySource(value = "file:${user.dir}/app.properties", ignoreResourceNotFound = true)
})
-
public class ApplicationConfiguration {
- @Autowired
- private Environment env;
@Bean
- public AndroidDebugBridge initAndroidDebugBridge() {
+ public AndroidDebugBridge initAndroidDebugBridge(Environment env) {
AndroidDebugBridge.initIfNeeded(false);
if (env.containsProperty(Constants.ADB_PATH_PROPERTY)) {
return AndroidDebugBridge.createBridge(env.getProperty(Constants.ADB_PATH_PROPERTY), false);
@@ -28,6 +27,12 @@ public AndroidDebugBridge initAndroidDebugBridge() {
return AndroidDebugBridge.createBridge();
}
+ @PreDestroy
+ public void preDestroy() {
+ AndroidDebugBridge.disconnectBridge();
+ AndroidDebugBridge.terminate();
+ }
+
@Bean
public DefaultListableBeanFactory initBeanFactory() {
return new DefaultListableBeanFactory();
@@ -38,7 +43,7 @@ public DefaultListableBeanFactory initBeanFactory() {
public IDevice initDevice(DeviceChooserApplication application) {
application.init();
application.start();
- application.close();
+ application.stop();
return application.getDevice();
}
diff --git a/src/main/java/com/github/xsavikx/androidscreencast/spring/config/ApplicationContextProvider.java b/src/main/java/com/github/xsavikx/androidscreencast/spring/config/ApplicationContextProvider.java
index a983374..68c0c1c 100644
--- a/src/main/java/com/github/xsavikx/androidscreencast/spring/config/ApplicationContextProvider.java
+++ b/src/main/java/com/github/xsavikx/androidscreencast/spring/config/ApplicationContextProvider.java
@@ -23,4 +23,8 @@ public void setApplicationContext(ApplicationContext applicationContext) throws
ApplicationContextProvider.applicationContext = applicationContext;
}
+ public static T getBean(Class clazz) throws BeansException {
+ return getApplicationContext().getBean(clazz);
+ }
+
}
diff --git a/src/main/java/com/github/xsavikx/androidscreencast/ui/JDialogDeviceList.java b/src/main/java/com/github/xsavikx/androidscreencast/ui/JDialogDeviceList.java
index e1f3e28..46f9ebc 100644
--- a/src/main/java/com/github/xsavikx/androidscreencast/ui/JDialogDeviceList.java
+++ b/src/main/java/com/github/xsavikx/androidscreencast/ui/JDialogDeviceList.java
@@ -17,7 +17,7 @@ public class JDialogDeviceList extends JDialog implements ActionListener {
private JTextField jtfHost = new JTextField(DEFAULT_HOST);
private JFormattedTextField jftfPort = new JFormattedTextField(DEFAULT_PORT);
- private JList jlDevices = new JList();
+ private JList jlDevices = new JList<>();
private JPanel jpAgent = new JPanel();
private JPanel jpButtons = new JPanel();
private JButton jbOk = new JButton("OK");
@@ -28,6 +28,7 @@ public class JDialogDeviceList extends JDialog implements ActionListener {
public JDialogDeviceList(IDevice[] devices) {
super();
+ setDefaultCloseOperation(DISPOSE_ON_CLOSE);
setModal(true);
this.devices = devices;
initialize();
@@ -35,9 +36,9 @@ public JDialogDeviceList(IDevice[] devices) {
@Override
public void actionPerformed(ActionEvent arg0) {
- cancelled = arg0.getSource() == jbQuit;
-
- setVisible(false);
+ if (arg0.getSource() == jbQuit) {
+ this.dispose();
+ }
}
public IDevice getDevice() {
diff --git a/src/main/java/com/github/xsavikx/androidscreencast/ui/JDialogError.java b/src/main/java/com/github/xsavikx/androidscreencast/ui/JDialogError.java
index e73bdac..6e755cc 100644
--- a/src/main/java/com/github/xsavikx/androidscreencast/ui/JDialogError.java
+++ b/src/main/java/com/github/xsavikx/androidscreencast/ui/JDialogError.java
@@ -1,26 +1,79 @@
package com.github.xsavikx.androidscreencast.ui;
+import com.github.xsavikx.androidscreencast.exception.AndroidScreenCastRuntimeException;
+
import javax.swing.*;
import java.awt.*;
+import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
public class JDialogError extends JDialog {
- private static final long serialVersionUID = -2562084286663149628L;
+ private JLabel errorDialogLabel;
+ private JScrollPane scrollPane;
+ private JTextArea errorDescription;
public JDialogError(Throwable ex) {
- getRootPane().setLayout(new BorderLayout());
- JTextArea l = new JTextArea();
- StringWriter w = new StringWriter();
- if (ex.getClass() == RuntimeException.class && ex.getCause() != null)
- ex = ex.getCause();
- ex.printStackTrace(new PrintWriter(w));
- l.setText(w.toString());
- getRootPane().add(l, BorderLayout.CENTER);
+ setDefaultCloseOperation(DISPOSE_ON_CLOSE);
+ initComponents(ex);
+ }
+
+ private void initComponents(Throwable ex) {
+ errorDialogLabel = new JLabel();
+ scrollPane = new JScrollPane();
+ errorDescription = new JTextArea();
+ errorDescription.setLineWrap(true);
+ errorDescription.setWrapStyleWord(true);
+
+
+ Container contentPane = getContentPane();
+ contentPane.setLayout(new BorderLayout(5, 5));
+
+
+ errorDialogLabel.setText(ex.getClass().getSimpleName());
+ errorDialogLabel.setLabelFor(errorDescription);
+ errorDialogLabel.setHorizontalAlignment(SwingConstants.CENTER);
+ contentPane.add(errorDialogLabel, BorderLayout.NORTH);
+ setErrorDetails(ex);
+
+ scrollPane.setViewportView(errorDescription);
+ contentPane.add(scrollPane, BorderLayout.CENTER);
pack();
+ Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
+ setSize((int) screenSize.getWidth() >> 1, (int) screenSize.getHeight() >> 1);
setLocationRelativeTo(null);
setAlwaysOnTop(true);
}
+ private void setErrorDetails(Throwable ex) {
+ errorDialogLabel.setText(ex.getClass().getSimpleName());
+ if (ex.getClass() == RuntimeException.class && ex.getCause() != null)
+ ex = ex.getCause();
+ try (StringWriter stringWriter = new StringWriter();) {
+ AndroidScreenCastRuntimeException realCause = getCause(ex);
+ if (realCause != null) {
+ errorDialogLabel.setText(realCause.getClass().getSimpleName());
+ stringWriter.append(realCause.getMessage()).append('\n').append('\n');
+ stringWriter.append(realCause.getAdditionalInformation());
+ } else {
+ stringWriter.append(ex.getMessage()).append('\n').append('\n');
+ ex.printStackTrace(new PrintWriter(stringWriter));
+ }
+ errorDescription.setText(stringWriter.toString());
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private AndroidScreenCastRuntimeException getCause(Throwable ex) {
+ Throwable cause = ex.getCause();
+ while (cause != null) {
+ if (cause instanceof AndroidScreenCastRuntimeException) {
+ return (AndroidScreenCastRuntimeException) cause;
+ }
+ cause = cause.getCause();
+ }
+ return null;
+ }
}
diff --git a/src/main/java/com/github/xsavikx/androidscreencast/ui/JDialogExecuteKeyEvent.java b/src/main/java/com/github/xsavikx/androidscreencast/ui/JDialogExecuteKeyEvent.java
index 3f3191b..d4eb5c5 100644
--- a/src/main/java/com/github/xsavikx/androidscreencast/ui/JDialogExecuteKeyEvent.java
+++ b/src/main/java/com/github/xsavikx/androidscreencast/ui/JDialogExecuteKeyEvent.java
@@ -8,11 +8,10 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
+import javax.annotation.PostConstruct;
import javax.swing.*;
import javax.swing.border.TitledBorder;
import java.awt.*;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
@Component
public class JDialogExecuteKeyEvent extends JDialog {
@@ -31,13 +30,16 @@ public class JDialogExecuteKeyEvent extends JDialog {
private static final String NO_COMMAND_CHOSEN_WARNING_MESSAGE = "Please, select command from the list";
private static final String NO_COMMAND_CHOSEN_WARNING_DIALOG_TITLE = "Warning";
+ private final CommandExecutor commandExecutor;
+
@Autowired
- private CommandExecutor commandExecutor;
+ public JDialogExecuteKeyEvent(CommandExecutor commandExecutor) {
+ this.commandExecutor = commandExecutor;
+ }
+
- /**
- * Create the dialog.
- */
- public JDialogExecuteKeyEvent() {
+ @PostConstruct
+ private void initialize() {
setResizable(false);
setTitle("Execute key event");
setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
@@ -47,33 +49,20 @@ public JDialogExecuteKeyEvent() {
JButton executeCommandButton = new JButton(EXECUTE_BUTTON_TEXT);
executeCommandButton.setSize(new Dimension(BUTTON_WIDTH, BUTTON_HEIGHT));
- executeCommandButton.addActionListener(new ActionListener() {
- @Override
- public void actionPerformed(ActionEvent e) {
- int rowIndex = commandListTable.getSelectedRow();
- if (rowIndex > 0) {
- final String title = (String) commandList.getValueAt(rowIndex, TITLE_COLUMN_INDEX);
- SwingUtilities.invokeLater(new Runnable() {
- @Override
- public void run() {
- commandExecutor.execute(AdbInputCommandFactory.getKeyCommand(InputKeyEvent.valueOf(title),
- useLongPress.getState()));
- }
- });
- closeDialog();
- } else {
- JOptionPane.showMessageDialog(null, NO_COMMAND_CHOSEN_WARNING_MESSAGE, NO_COMMAND_CHOSEN_WARNING_DIALOG_TITLE,
- JOptionPane.WARNING_MESSAGE);
- }
- }
- });
- JButton cancelButton = new JButton(CANCEL_BUTTON_TEXT);
- cancelButton.addActionListener(new ActionListener() {
- @Override
- public void actionPerformed(ActionEvent e) {
+ executeCommandButton.addActionListener(actionEvent -> {
+ int rowIndex = commandListTable.getSelectedRow();
+ if (rowIndex > 0) {
+ final String title = (String) commandList.getValueAt(rowIndex, TITLE_COLUMN_INDEX);
+ SwingUtilities.invokeLater(() -> commandExecutor.execute(AdbInputCommandFactory.getKeyCommand(InputKeyEvent.valueOf(title),
+ useLongPress.getState())));
closeDialog();
+ } else {
+ JOptionPane.showMessageDialog(null, NO_COMMAND_CHOSEN_WARNING_MESSAGE, NO_COMMAND_CHOSEN_WARNING_DIALOG_TITLE,
+ JOptionPane.WARNING_MESSAGE);
}
});
+ JButton cancelButton = new JButton(CANCEL_BUTTON_TEXT);
+ cancelButton.addActionListener(actionEvent -> closeDialog());
JScrollPane listScrollPane = new JScrollPane(commandListTable, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
listScrollPane.setPreferredSize(new Dimension(WIDTH, HEIGHT));
@@ -91,18 +80,6 @@ public void actionPerformed(ActionEvent e) {
setLocationRelativeTo(null);
}
- /**
- * Launch the application.
- */
- public static void main(String[] args) {
- SwingUtilities.invokeLater(new Runnable() {
- @Override
- public void run() {
- new JDialogExecuteKeyEvent().setVisible(true);
- }
- });
- }
-
private void closeDialog() {
setVisible(false);
}
diff --git a/src/main/java/com/github/xsavikx/androidscreencast/ui/JDialogUrl.java b/src/main/java/com/github/xsavikx/androidscreencast/ui/JDialogUrl.java
deleted file mode 100644
index f677f21..0000000
--- a/src/main/java/com/github/xsavikx/androidscreencast/ui/JDialogUrl.java
+++ /dev/null
@@ -1,55 +0,0 @@
-package com.github.xsavikx.androidscreencast.ui;
-
-import javax.swing.*;
-import java.awt.*;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-
-public class JDialogUrl extends JDialog {
-
- private static final long serialVersionUID = -331017582679776599L;
- private JTextField jtfUrl = new JTextField();
- private JButton jbOk = new JButton("Ok");
- private boolean result = false;
-
- public JDialogUrl() {
- setModal(true);
- setTitle("Open url");
-
- setLayout(new BorderLayout());
- add(jbOk, BorderLayout.SOUTH);
- add(jtfUrl, BorderLayout.CENTER);
- jtfUrl.setColumns(50);
-
- jbOk.addActionListener(new ActionListener() {
-
- @Override
- public void actionPerformed(ActionEvent arg0) {
- setResult(true);
- JDialogUrl.this.setVisible(false);
- }
- });
-
- jbOk.setDefaultCapable(true);
- getRootPane().setDefaultButton(jbOk);
- pack();
- setLocationRelativeTo(null);
-
- }
-
- public JTextField getJtfUrl() {
- return jtfUrl;
- }
-
- public void setJtfUrl(JTextField jtfUrl) {
- this.jtfUrl = jtfUrl;
- }
-
- public boolean isResult() {
- return result;
- }
-
- public void setResult(boolean result) {
- this.result = result;
- }
-}
diff --git a/src/main/java/com/github/xsavikx/androidscreencast/ui/JFrameMain.java b/src/main/java/com/github/xsavikx/androidscreencast/ui/JFrameMain.java
index cf935ef..7494a05 100644
--- a/src/main/java/com/github/xsavikx/androidscreencast/ui/JFrameMain.java
+++ b/src/main/java/com/github/xsavikx/androidscreencast/ui/JFrameMain.java
@@ -3,61 +3,52 @@
import com.github.xsavikx.androidscreencast.api.AndroidDevice;
import com.github.xsavikx.androidscreencast.api.injector.Injector;
import com.github.xsavikx.androidscreencast.api.injector.InputKeyEvent;
-import com.github.xsavikx.androidscreencast.api.injector.ScreenCaptureThread.ScreenCaptureListener;
+import com.github.xsavikx.androidscreencast.app.AndroidScreencastApplication;
import com.github.xsavikx.androidscreencast.constant.Constants;
import com.github.xsavikx.androidscreencast.spring.config.ApplicationContextProvider;
import com.github.xsavikx.androidscreencast.ui.explorer.JFrameExplorer;
import com.github.xsavikx.androidscreencast.ui.interaction.KeyEventDispatcherFactory;
import com.github.xsavikx.androidscreencast.ui.interaction.KeyboardActionListenerFactory;
-import com.github.xsavikx.androidscreencast.ui.interaction.MouseActionAdapterFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;
+import javax.annotation.PostConstruct;
import javax.swing.*;
import javax.swing.filechooser.FileNameExtensionFilter;
import java.awt.*;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
-import java.awt.image.BufferedImage;
@Component
public class JFrameMain extends JFrame {
-
private static final long serialVersionUID = -2085909236767692371L;
- private JPanelScreen jp = new JPanelScreen();
+ private final JPanelScreen jp;
+ private final AndroidDevice androidDevice;
+ private final MouseAdapter ma;
+ private final Injector injector;
+ private final Environment env;
+ private transient boolean isDisposed = false;
private JToolBar jtb = new JToolBar();
private JToolBar jtbHardkeys = new JToolBar();
- // private JToggleButton jtbRecord = new JToggleButton("Record");
-
- // private JButton jbOpenUrl = new JButton("Open Url");
private JScrollPane jsp;
private JButton jbExplorer = new JButton("Explore");
private JButton jbRestartClient = new JButton("Restart client");
private JButton jbExecuteKeyEvent = new JButton("Execute keycode");
-
private JButton jbKbHome = new JButton("Home");
private JButton jbKbMenu = new JButton("Menu");
private JButton jbKbBack = new JButton("Back");
private JButton jbKbSearch = new JButton("Search");
-
private JButton jbKbPhoneOn = new JButton("Call");
-
private JButton jbKbPhoneOff = new JButton("End call");
- private AndroidDevice androidDevice;
- private Injector injector;
- private Environment env;
private Dimension oldImageDimension;
@Autowired
- public JFrameMain(Environment env, Injector injector, AndroidDevice androidDevice) {
+ public JFrameMain(JPanelScreen jp, Environment env, Injector injector, AndroidDevice androidDevice, MouseAdapter ma) {
+ this.jp = jp;
this.injector = injector;
this.env = env;
this.androidDevice = androidDevice;
- initialize();
- KeyboardFocusManager.getCurrentKeyboardFocusManager()
- .addKeyEventDispatcher(KeyEventDispatcherFactory.getKeyEventDispatcher(this));
+ this.ma = ma;
}
private void setPrefferedWindowSize() {
@@ -70,12 +61,23 @@ private void setPrefferedWindowSize() {
pack();
}
- public void initialize() {
+ @Override
+ public void dispose() {
+ if (isDisposed) {
+ return;
+ }
+ isDisposed = true;
+ super.dispose();
+ ApplicationContextProvider.getBean(AndroidScreencastApplication.class).stop();
+ }
+ @PostConstruct
+ public void initialize() {
+ setDefaultCloseOperation(DISPOSE_ON_CLOSE);
+ KeyboardFocusManager.getCurrentKeyboardFocusManager()
+ .addKeyEventDispatcher(KeyEventDispatcherFactory.getKeyEventDispatcher(this));
jtb.setFocusable(false);
jbExplorer.setFocusable(false);
- // jtbRecord.setFocusable(false);
- // jbOpenUrl.setFocusable(false);
jbKbHome.setFocusable(false);
jbKbMenu.setFocusable(false);
jbKbBack.setFocusable(false);
@@ -99,9 +101,7 @@ public void initialize() {
jtbHardkeys.add(jbKbPhoneOn);
jtbHardkeys.add(jbKbPhoneOff);
- // setIconImage(Toolkit.getDefaultToolkit().getImage(
- // getClass().getResource("icon.png")));
- setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
+ setDefaultCloseOperation(DISPOSE_ON_CLOSE);
setLayout(new BorderLayout());
add(jtb, BorderLayout.NORTH);
add(jtbHardkeys, BorderLayout.SOUTH);
@@ -111,79 +111,38 @@ public void initialize() {
pack();
setLocationRelativeTo(null);
setPrefferedWindowSize();
- MouseAdapter ma = MouseActionAdapterFactory.getInstance(jp, injector);
jp.addMouseMotionListener(ma);
jp.addMouseListener(ma);
jp.addMouseWheelListener(ma);
- // jtbRecord.addActionListener(new ActionListener() {
- //
- // @Override
- // public void actionPerformed(ActionEvent arg0) {
- // if (jtbRecord.isSelected()) {
- // startRecording();
- // } else {
- // stopRecording();
- // }
- // }
- //
- // });
- // jtb.add(jtbRecord);
-
- jbExplorer.addActionListener(new ActionListener() {
-
- @Override
- public void actionPerformed(ActionEvent arg0) {
- JFrameExplorer jf = ApplicationContextProvider.getApplicationContext().getBean(JFrameExplorer.class);
- jf.setIconImage(getIconImage());
- jf.launch();
- jf.setVisible(true);
- }
+ jbExplorer.addActionListener(actionEvent -> {
+ JFrameExplorer jf = ApplicationContextProvider.getBean(JFrameExplorer.class);
+ jf.setIconImage(getIconImage());
+ jf.launch();
+ jf.setVisible(true);
});
jtb.add(jbExplorer);
jtb.add(jbRestartClient);
- jbExecuteKeyEvent.addActionListener(new ActionListener() {
-
- @Override
- public void actionPerformed(ActionEvent e) {
- JDialogExecuteKeyEvent jdExecuteKeyEvent = ApplicationContextProvider.getApplicationContext()
- .getBean(JDialogExecuteKeyEvent.class);
- jdExecuteKeyEvent.setVisible(true);
- }
+ jbExecuteKeyEvent.addActionListener(actionEvent -> {
+ JDialogExecuteKeyEvent jdExecuteKeyEvent = ApplicationContextProvider
+ .getBean(JDialogExecuteKeyEvent.class);
+ jdExecuteKeyEvent.setVisible(true);
});
jtb.add(jbExecuteKeyEvent);
-
- // jbOpenUrl.addActionListener(new ActionListener() {
- // @Override
- // public void actionPerformed(ActionEvent arg0) {
- // JDialogUrl jdUrl = new JDialogUrl();
- // jdUrl.setVisible(true);
- // if (!jdUrl.isResult())
- // return;
- // String url = jdUrl.getJtfUrl().getText();
- // androidDevice.openUrl(url);
- // }
- // });
- // jtb.add(jbOpenUrl);
-
}
public void launchInjector() {
- injector.screencapture.setListener(new ScreenCaptureListener() {
-
- @Override
- public void handleNewImage(Dimension size, BufferedImage image, boolean landscape) {
- if (oldImageDimension == null || !size.equals(oldImageDimension)) {
- jsp.setPreferredSize(size);
- JFrameMain.this.pack();
- oldImageDimension = size;
- }
- jp.handleNewImage(size, image);
+ injector.screenCaptureThread.setListener((size, image, landscape) -> {
+ if (oldImageDimension == null || !size.equals(oldImageDimension)) {
+ jsp.setPreferredSize(size);
+ JFrameMain.this.pack();
+ oldImageDimension = size;
}
+ jp.handleNewImage(size, image);
});
injector.start();
}
@@ -194,12 +153,12 @@ private void startRecording() {
jFileChooser.setFileFilter(filter);
int returnVal = jFileChooser.showSaveDialog(this);
if (returnVal == JFileChooser.APPROVE_OPTION) {
- injector.screencapture.startRecording(jFileChooser.getSelectedFile());
+ injector.screenCaptureThread.startRecording(jFileChooser.getSelectedFile());
}
}
private void stopRecording() {
- injector.screencapture.stopRecording();
+ injector.screenCaptureThread.stopRecording();
}
}
diff --git a/src/main/java/com/github/xsavikx/androidscreencast/ui/JPanelScreen.java b/src/main/java/com/github/xsavikx/androidscreencast/ui/JPanelScreen.java
index a761196..d6362a6 100644
--- a/src/main/java/com/github/xsavikx/androidscreencast/ui/JPanelScreen.java
+++ b/src/main/java/com/github/xsavikx/androidscreencast/ui/JPanelScreen.java
@@ -1,11 +1,13 @@
package com.github.xsavikx.androidscreencast.ui;
+import org.springframework.stereotype.Component;
+
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
+@Component
public class JPanelScreen extends JPanel {
-
private static final long serialVersionUID = -2034873107028503004L;
private float coef = 1;
private double origX;
diff --git a/src/main/java/com/github/xsavikx/androidscreencast/ui/JSplashScreen.java b/src/main/java/com/github/xsavikx/androidscreencast/ui/JSplashScreen.java
deleted file mode 100644
index 29cb6f2..0000000
--- a/src/main/java/com/github/xsavikx/androidscreencast/ui/JSplashScreen.java
+++ /dev/null
@@ -1,30 +0,0 @@
-package com.github.xsavikx.androidscreencast.ui;
-
-import javax.swing.*;
-import java.awt.*;
-
-public class JSplashScreen extends JWindow {
-
- private static final long serialVersionUID = -4537199368044671301L;
- private JLabel label;
-
- public JSplashScreen(String text) {
- label = new JLabel("Loading...", SwingConstants.CENTER);
- initialize();
- setText(text);
- }
-
- private void initialize() {
- setLayout(new BorderLayout());
- label.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
- // createLineBorder(Color.BLACK));
- add(label, BorderLayout.CENTER);
- }
-
- public void setText(String text) {
- label.setText(text);
- pack();
- setLocationRelativeTo(null);
- }
-
-}
diff --git a/src/main/java/com/github/xsavikx/androidscreencast/ui/MultiLineLabelUI.java b/src/main/java/com/github/xsavikx/androidscreencast/ui/MultiLineLabelUI.java
deleted file mode 100644
index 75f064f..0000000
--- a/src/main/java/com/github/xsavikx/androidscreencast/ui/MultiLineLabelUI.java
+++ /dev/null
@@ -1,277 +0,0 @@
-package com.github.xsavikx.androidscreencast.ui;
-
-import javax.swing.*;
-import javax.swing.plaf.basic.BasicGraphicsUtils;
-import javax.swing.plaf.basic.BasicLabelUI;
-import java.awt.*;
-import java.util.StringTokenizer;
-
-public class MultiLineLabelUI extends BasicLabelUI {
- static final int LEADING = SwingConstants.LEADING;
- static final int TRAILING = SwingConstants.TRAILING;
- static final int LEFT = SwingConstants.LEFT;
- static final int RIGHT = SwingConstants.RIGHT;
- static final int TOP = SwingConstants.TOP;
- static final int CENTER = SwingConstants.CENTER;
-
- static {
- labelUI = new MultiLineLabelUI();
- }
-
- protected String str;
- protected String[] strs;
-
- public static Dimension computeMultiLineDimension(FontMetrics fm, String[] strs) {
- int i, c, width = 0;
- for (i = 0, c = strs.length; i < c; i++)
- width = Math.max(width, SwingUtilities.computeStringWidth(fm, strs[i]));
- return new Dimension(width, fm.getHeight() * strs.length);
- }
-
- /**
- * Compute and return the location of the icons origin, the location of origin of the text baseline, and a possibly clipped version of the compound
- * labels string. Locations are computed relative to the viewR rectangle. This layoutCompoundLabel() does not know how to handle LEADING/TRAILING
- * values in horizontalTextPosition (they will default to RIGHT) and in horizontalAlignment (they will default to CENTER). Use the other version of
- * layoutCompoundLabel() instead.
- */
- public static String layoutCompoundLabel(FontMetrics fm, String[] text, Icon icon, int verticalAlignment,
- int horizontalAlignment, int verticalTextPosition, int horizontalTextPosition, Rectangle viewR, Rectangle iconR,
- Rectangle textR, int textIconGap) {
- /*
- * Initialize the icon bounds rectangle iconR.
- */
-
- if (icon != null) {
- iconR.width = icon.getIconWidth();
- iconR.height = icon.getIconHeight();
- } else {
- iconR.width = iconR.height = 0;
- }
-
- /*
- * Initialize the text bounds rectangle textR. If a null or and empty String was specified we substitute "" here and use 0,0,0,0 for textR.
- */
-
- // Fix for textIsEmpty sent by Paulo Santos
- boolean textIsEmpty = (text == null) || (text.length == 0)
- || (text.length == 1 && ((text[0] == null) || text[0].equals("")));
-
- String rettext = "";
- if (textIsEmpty) {
- textR.width = textR.height = 0;
- } else {
- Dimension dim = computeMultiLineDimension(fm, text);
- textR.width = dim.width;
- textR.height = dim.height;
- }
-
- /*
- * Unless both text and icon are non-null, we effectively ignore the value of textIconGap. The code that follows uses the value of gap instead of
- * textIconGap.
- */
-
- int gap = (textIsEmpty || (icon == null)) ? 0 : textIconGap;
-
- if (!textIsEmpty) {
-
- /*
- * If the label text string is too wide to fit within the available space "..." and as many characters as will fit will be displayed instead.
- */
-
- int availTextWidth;
-
- if (horizontalTextPosition == CENTER) {
- availTextWidth = viewR.width;
- } else {
- availTextWidth = viewR.width - (iconR.width + gap);
- }
-
- if (textR.width > availTextWidth && text.length == 1) {
- String clipString = "...";
- int totalWidth = SwingUtilities.computeStringWidth(fm, clipString);
- int nChars;
- for (nChars = 0; nChars < text[0].length(); nChars++) {
- totalWidth += fm.charWidth(text[0].charAt(nChars));
- if (totalWidth > availTextWidth) {
- break;
- }
- }
- rettext = text[0].substring(0, nChars) + clipString;
- textR.width = SwingUtilities.computeStringWidth(fm, rettext);
- }
- }
-
- /*
- * Compute textR.x,y given the verticalTextPosition and horizontalTextPosition properties
- */
-
- if (verticalTextPosition == TOP) {
- if (horizontalTextPosition != CENTER) {
- textR.y = 0;
- } else {
- textR.y = -(textR.height + gap);
- }
- } else if (verticalTextPosition == CENTER) {
- textR.y = (iconR.height / 2) - (textR.height / 2);
- } else { // (verticalTextPosition == BOTTOM)
- if (horizontalTextPosition != CENTER) {
- textR.y = iconR.height - textR.height;
- } else {
- textR.y = (iconR.height + gap);
- }
- }
-
- if (horizontalTextPosition == LEFT) {
- textR.x = -(textR.width + gap);
- } else if (horizontalTextPosition == CENTER) {
- textR.x = (iconR.width / 2) - (textR.width / 2);
- } else { // (horizontalTextPosition == RIGHT)
- textR.x = (iconR.width + gap);
- }
-
- /*
- * labelR is the rectangle that contains iconR and textR. Move it to its proper position given the labelAlignment properties.
- *
- * To avoid actually allocating a Rectangle, Rectangle.union has been inlined below.
- */
- int labelR_x = Math.min(iconR.x, textR.x);
- int labelR_width = Math.max(iconR.x + iconR.width, textR.x + textR.width) - labelR_x;
- int labelR_y = Math.min(iconR.y, textR.y);
- int labelR_height = Math.max(iconR.y + iconR.height, textR.y + textR.height) - labelR_y;
-
- int dx, dy;
-
- if (verticalAlignment == TOP) {
- dy = viewR.y - labelR_y;
- } else if (verticalAlignment == CENTER) {
- dy = (viewR.y + (viewR.height / 2)) - (labelR_y + (labelR_height / 2));
- } else { // (verticalAlignment == BOTTOM)
- dy = (viewR.y + viewR.height) - (labelR_y + labelR_height);
- }
-
- if (horizontalAlignment == LEFT) {
- dx = viewR.x - labelR_x;
- } else if (horizontalAlignment == RIGHT) {
- dx = (viewR.x + viewR.width) - (labelR_x + labelR_width);
- } else { // (horizontalAlignment == CENTER)
- dx = (viewR.x + (viewR.width / 2)) - (labelR_x + (labelR_width / 2));
- }
-
- /*
- * Translate textR and glypyR by dx,dy.
- */
-
- textR.x += dx;
- textR.y += dy;
-
- iconR.x += dx;
- iconR.y += dy;
-
- return rettext;
- }
-
- /**
- * Compute and return the location of the icons origin, the location of origin of the text baseline, and a possibly clipped version of the compound
- * labels string. Locations are computed relative to the viewR rectangle. The JComponents orientation (LEADING/TRAILING) will also be taken into
- * account and translated into LEFT/RIGHT values accordingly.
- */
- public static String layoutCompoundLabel(JComponent c, FontMetrics fm, String[] text, Icon icon,
- int verticalAlignment, int horizontalAlignment, int verticalTextPosition, int horizontalTextPosition,
- Rectangle viewR, Rectangle iconR, Rectangle textR, int textIconGap) {
- boolean orientationIsLeftToRight = true;
- int hAlign = horizontalAlignment;
- int hTextPos = horizontalTextPosition;
-
- if (c != null) {
- if (!(c.getComponentOrientation().isLeftToRight())) {
- orientationIsLeftToRight = false;
- }
- }
-
- // Translate LEADING/TRAILING values in horizontalAlignment
- // to LEFT/RIGHT values depending on the components orientation
- switch (horizontalAlignment) {
- case LEADING:
- hAlign = (orientationIsLeftToRight) ? LEFT : RIGHT;
- break;
- case TRAILING:
- hAlign = (orientationIsLeftToRight) ? RIGHT : LEFT;
- break;
- }
-
- // Translate LEADING/TRAILING values in horizontalTextPosition
- // to LEFT/RIGHT values depending on the components orientation
- switch (horizontalTextPosition) {
- case LEADING:
- hTextPos = (orientationIsLeftToRight) ? LEFT : RIGHT;
- break;
- case TRAILING:
- hTextPos = (orientationIsLeftToRight) ? RIGHT : LEFT;
- break;
- }
-
- return layoutCompoundLabel(fm, text, icon, verticalAlignment, hAlign, verticalTextPosition, hTextPos, viewR, iconR,
- textR, textIconGap);
- }
-
- protected void drawString(Graphics g, String s, int accChar, int textX, int textY) {
- if (s.indexOf('\n') == -1)
- BasicGraphicsUtils.drawString(g, s, accChar, textX, textY);
- else {
- String[] strs = splitStringByLines(s);
- int height = g.getFontMetrics().getHeight();
- // Only the first line can have the accel char
- BasicGraphicsUtils.drawString(g, strs[0], accChar, textX, textY);
- for (int i = 1; i < strs.length; i++)
- g.drawString(strs[i], textX, textY + (height * i));
- }
- }
-
- @Override
- protected String layoutCL(JLabel label, FontMetrics fontMetrics, String text, Icon icon, Rectangle viewR,
- Rectangle iconR, Rectangle textR) {
- String s = layoutCompoundLabel(label, fontMetrics, splitStringByLines(text), icon, label.getVerticalAlignment(),
- label.getHorizontalAlignment(), label.getVerticalTextPosition(), label.getHorizontalTextPosition(), viewR,
- iconR, textR, label.getIconTextGap());
-
- if (s.equals(""))
- return text;
- return s;
- }
-
- @Override
- protected void paintDisabledText(JLabel l, Graphics g, String s, int textX, int textY) {
- int accChar = l.getDisplayedMnemonic();
- g.setColor(l.getBackground());
- drawString(g, s, accChar, textX, textY);
- }
-
- @Override
- protected void paintEnabledText(JLabel l, Graphics g, String s, int textX, int textY) {
- int accChar = l.getDisplayedMnemonic();
- g.setColor(l.getForeground());
- drawString(g, s, accChar, textX, textY);
- }
-
- public String[] splitStringByLines(String str) {
- if (str.equals(this.str))
- return strs;
-
- this.str = str;
-
- int lines = 1;
- int i, c;
- for (i = 0, c = str.length(); i < c; i++) {
- if (str.charAt(i) == '\n')
- lines++;
- }
- strs = new String[lines];
- StringTokenizer st = new StringTokenizer(str, "\n");
-
- int line = 0;
- while (st.hasMoreTokens())
- strs[line++] = st.nextToken();
-
- return strs;
- }
-}
diff --git a/src/main/java/com/github/xsavikx/androidscreencast/ui/explorer/JFrameExplorer.java b/src/main/java/com/github/xsavikx/androidscreencast/ui/explorer/JFrameExplorer.java
index 399442f..361edf5 100644
--- a/src/main/java/com/github/xsavikx/androidscreencast/ui/explorer/JFrameExplorer.java
+++ b/src/main/java/com/github/xsavikx/androidscreencast/ui/explorer/JFrameExplorer.java
@@ -6,8 +6,6 @@
import org.springframework.stereotype.Component;
import javax.swing.*;
-import javax.swing.event.TreeSelectionEvent;
-import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreePath;
@@ -24,37 +22,34 @@
public class JFrameExplorer extends JFrame {
private static final long serialVersionUID = -5209265873286028854L;
+ private final AndroidDevice androidDevice;
private JTree jt;
private JSplitPane jSplitPane;
- @Autowired
- private AndroidDevice androidDevice;
private JList