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.0 com.github.xsavikx androidscreencast - 0.0.7s + 0.0.8s Android 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.8 UTF-8 + ${project.basedir}/adb + ${adb.folder}/linux + ${adb.folder}/windows + ${adb.folder}/macosx com.android.tools.ddms ddmlib - ${ddmlib-version} + ${ddmlib.version} log4j log4j - ${log4j-version} + ${log4j.version} org.springframework spring-core - ${spring-version} + ${spring.version} org.springframework spring-beans - ${spring-version} + ${spring.version} org.springframework spring-context - ${spring-version} + ${spring.version} maven-compiler-plugin - 3.5.1 + 3.6.0 - ${jdk-version} - ${jdk-version} + ${jdk.version} + ${jdk.version} + + + + org.apache.maven.plugins + maven-jar-plugin + 3.0.2 + + + + ${main.class} + + - org.apache.maven.plugins maven-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 jListFichiers; private Map> cache = new LinkedHashMap<>(); - public JFrameExplorer() { + @Autowired + public JFrameExplorer(AndroidDevice androidDevice) { setTitle("Explorer"); setLayout(new BorderLayout()); jt = new JTree(new DefaultMutableTreeNode("Test")); + this.androidDevice = androidDevice; } public void launch() { jt.setModel(new DefaultTreeModel(new FolderTreeNode("Device", "/"))); jt.setRootVisible(true); - jt.addTreeSelectionListener(new TreeSelectionListener() { - - @Override - public void valueChanged(TreeSelectionEvent e) { - TreePath tp = e.getPath(); - if (tp == null) - return; - if (!(tp.getLastPathComponent() instanceof FolderTreeNode)) - return; - FolderTreeNode node = (FolderTreeNode) tp.getLastPathComponent(); - displayFolder(node.path); - } + jt.addTreeSelectionListener(treeSelectionEvent -> { + TreePath tp = treeSelectionEvent.getPath(); + if (tp == null) + return; + if (!(tp.getLastPathComponent() instanceof FolderTreeNode)) + return; + FolderTreeNode node = (FolderTreeNode) tp.getLastPathComponent(); + displayFolder(node.path); }); JScrollPane jsp = new JScrollPane(jt); diff --git a/src/main/java/com/github/xsavikx/androidscreencast/ui/interaction/KeyEventDispatcherImpl.java b/src/main/java/com/github/xsavikx/androidscreencast/ui/interaction/KeyEventDispatcherImpl.java index 8e3a6ea..48f0f07 100644 --- a/src/main/java/com/github/xsavikx/androidscreencast/ui/interaction/KeyEventDispatcherImpl.java +++ b/src/main/java/com/github/xsavikx/androidscreencast/ui/interaction/KeyEventDispatcherImpl.java @@ -23,14 +23,7 @@ public boolean dispatchKeyEvent(KeyEvent e) { return false; if (e.getID() == KeyEvent.KEY_TYPED) { final int code = KeyCodeConverter.getKeyCode(e); - SwingUtilities.invokeLater(new Runnable() { - - @Override - public void run() { - getCommandExecutor().execute(AdbInputCommandFactory.getKeyCommand(code)); - - } - }); + SwingUtilities.invokeLater(() -> getCommandExecutor().execute(AdbInputCommandFactory.getKeyCommand(code))); } return false; @@ -38,7 +31,7 @@ public void run() { private CommandExecutor getCommandExecutor() { if (commandExecutor == null) { - commandExecutor = ApplicationContextProvider.getApplicationContext().getBean(CommandExecutor.class); + commandExecutor = ApplicationContextProvider.getBean(CommandExecutor.class); } return commandExecutor; } diff --git a/src/main/java/com/github/xsavikx/androidscreencast/ui/interaction/KeyboardActionListener.java b/src/main/java/com/github/xsavikx/androidscreencast/ui/interaction/KeyboardActionListener.java index 403b808..591e310 100644 --- a/src/main/java/com/github/xsavikx/androidscreencast/ui/interaction/KeyboardActionListener.java +++ b/src/main/java/com/github/xsavikx/androidscreencast/ui/interaction/KeyboardActionListener.java @@ -18,18 +18,13 @@ public KeyboardActionListener(int key) { @Override public void actionPerformed(ActionEvent e) { - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - getCommandExecutor().execute(AdbInputCommandFactory.getKeyCommand(key)); - } - }); + SwingUtilities.invokeLater(() -> getCommandExecutor().execute(AdbInputCommandFactory.getKeyCommand(key))); } private CommandExecutor getCommandExecutor() { if (commandExecutor == null) { - commandExecutor = ApplicationContextProvider.getApplicationContext().getBean(CommandExecutor.class); + commandExecutor = ApplicationContextProvider.getBean(CommandExecutor.class); } return commandExecutor; } diff --git a/src/main/java/com/github/xsavikx/androidscreencast/ui/interaction/MouseActionAdapter.java b/src/main/java/com/github/xsavikx/androidscreencast/ui/interaction/MouseActionAdapter.java index 96e17b6..c5a8627 100644 --- a/src/main/java/com/github/xsavikx/androidscreencast/ui/interaction/MouseActionAdapter.java +++ b/src/main/java/com/github/xsavikx/androidscreencast/ui/interaction/MouseActionAdapter.java @@ -3,8 +3,9 @@ import com.github.xsavikx.androidscreencast.api.command.executor.CommandExecutor; import com.github.xsavikx.androidscreencast.api.command.factory.AdbInputCommandFactory; import com.github.xsavikx.androidscreencast.api.injector.Injector; -import com.github.xsavikx.androidscreencast.spring.config.ApplicationContextProvider; import com.github.xsavikx.androidscreencast.ui.JPanelScreen; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; import javax.swing.*; import java.awt.*; @@ -12,40 +13,34 @@ import java.awt.event.MouseEvent; import java.awt.event.MouseWheelEvent; +@Component public class MouseActionAdapter extends MouseAdapter { private final static long ONE_SECOND = 1000L; private final JPanelScreen jp; - private CommandExecutor commandExecutor; - private Injector injector; + private final CommandExecutor commandExecutor; + private final Injector injector; private int dragFromX = -1; private int dragFromY = -1; private long timeFromPress = -1; - public MouseActionAdapter(JPanelScreen jPanelScreen) { - this.jp = jPanelScreen; - } - - public MouseActionAdapter(JPanelScreen jPanelScreen, Injector injector) { - this(jPanelScreen); + @Autowired + public MouseActionAdapter(JPanelScreen jp, CommandExecutor commandExecutor, Injector injector) { + this.jp = jp; + this.commandExecutor = commandExecutor; this.injector = injector; } + @Override public void mouseClicked(MouseEvent e) { if (injector != null && e.getButton() == MouseEvent.BUTTON3) { - injector.screencapture.toogleOrientation(); + injector.screenCaptureThread.toogleOrientation(); e.consume(); return; } final Point p2 = jp.getRawPoint(e.getPoint()); if (p2.x > 0 && p2.y > 0) { - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - getCommandExecutor().execute(AdbInputCommandFactory.getTapCommand(p2.x, p2.y)); - - } - }); + SwingUtilities.invokeLater(() -> commandExecutor.execute(AdbInputCommandFactory.getTapCommand(p2.x, p2.y))); } } @@ -67,13 +62,7 @@ public void mouseReleased(MouseEvent e) { final int yFrom = dragFromY; final int xTo = p2.x; final int yTo = p2.y; - SwingUtilities.invokeLater(new Runnable() { - - @Override - public void run() { - getCommandExecutor().execute(AdbInputCommandFactory.getSwipeCommand(xFrom, yFrom, xTo, yTo, timeFromPress)); - } - }); + SwingUtilities.invokeLater(() -> commandExecutor.execute(AdbInputCommandFactory.getSwipeCommand(xFrom, yFrom, xTo, yTo, timeFromPress))); dragFromX = -1; dragFromY = -1; timeFromPress = -1; @@ -87,11 +76,4 @@ public void mouseWheelMoved(MouseWheelEvent arg0) { // JFrameMain.this.injector.injectTrackball(arg0.getWheelRotation() < 0 ? // -1f : 1f); } - - private CommandExecutor getCommandExecutor() { - if (commandExecutor == null) { - commandExecutor = ApplicationContextProvider.getApplicationContext().getBean(CommandExecutor.class); - } - return commandExecutor; - } } diff --git a/src/main/java/com/github/xsavikx/androidscreencast/ui/interaction/MouseActionAdapterFactory.java b/src/main/java/com/github/xsavikx/androidscreencast/ui/interaction/MouseActionAdapterFactory.java deleted file mode 100644 index 97c4aad..0000000 --- a/src/main/java/com/github/xsavikx/androidscreencast/ui/interaction/MouseActionAdapterFactory.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.github.xsavikx.androidscreencast.ui.interaction; - -import com.github.xsavikx.androidscreencast.api.injector.Injector; -import com.github.xsavikx.androidscreencast.ui.JPanelScreen; - -public final class MouseActionAdapterFactory { - public static MouseActionAdapter getInstance(JPanelScreen jPanelScreen) { - return new MouseActionAdapter(jPanelScreen); - } - - public static MouseActionAdapter getInstance(JPanelScreen jPanelScreen, Injector injector) { - return new MouseActionAdapter(jPanelScreen, injector); - } -} diff --git a/src/main/resources/log4j.properties b/src/main/resources/log4j.properties index faaeae6..d0af363 100644 --- a/src/main/resources/log4j.properties +++ b/src/main/resources/log4j.properties @@ -14,4 +14,4 @@ log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%d{HH:mm:ss} [%-5p] [%C{1}] - %m%n # Set levels for appenders log4j.appender.file.Threshold=DEBUG -log4j.appender.stdout.Threshold=DEBUG +log4j.appender.stdout.Threshold=INFO