Android Mirroring
Android mirroring °ü·Ã ÇÁ·Î±×·¥ ºÐ¼®
1. ȯ°æ ¶
1.1. Technology ¶
The video of the screen is captured from the 1st client (window) and the whole stream is transferred bit by bit to some sort of server ( apache/nginx/node) . This is then transferred to the second client (window) to stream in. For real time streaming one can use a websocket server ( tcp connections ), which is the fastest . Also p2p protocols have been developed eliminating the need for a server ( middle-man ) . These enable real time bidirectional communication !!! . 1.2. Chromecast vs. AirPlay ¶
AirPlay on the Apple TV is a hybrid of the classic set-top box and streaming from your device: when you first power on an Apple TV, you're greeted with a friendly iOS-powered user interface with easy-to-understand menus and navigation, and you can control the entire thing from the bundled traditional remote without ever touching a smartphone. But open up an AirPlay app on your iOS device, and it's just two taps to wipe all that away and stream video directly from your iPhone or iPad, with all the playback controls remaining on your touchscreen. It's the best of both worlds: a fully-functional set top box and a complete local streaming solution.
Chromecast is focused entirely on the streaming side of the equation. There's no UI or remote outside of your device; everything is handled by the applications that tap into Google's streaming technology and tell the Chromecast what to do. That part of the UI is a lot like AirPlay: you hit a button in an app like Netflix or Pandora that supports Chromecast, and you're streaming away.
2. °ü·Ã ¼ÒÇÁÆ®¿þ¾î ¶
3. adbcontrol ¶
3.1. AdbControl.java ¶
public void screenshot(File target) { String fileName = config.getPhoneImageFilePath(); executeShellCommand(MessageFormat.format("screencap -p {0}", fileName), new ByteArrayOutputStream()); executeCommand(MessageFormat.format("pull {0} {1}", fileName, target.getAbsolutePath()), new ByteArrayOutputStream()); }
adb shell screencap -p /sdcard/screen.png adb pull /sdcard/screen.png adb shell rm /sdcard/screen.png private void loadImage(File file) { try { image = ImageIO.read(file); } catch(IOException ex) { ex.printStackTrace(); return; } repaint(); }
3.2. ȸ鿡 Ãâ·Â ¶AdbControl frame = new AdbControl(configFile); frame.setVisible(true); setDefaultCloseOperation(EXIT_ON_CLOSE); setTitle("ADB Control"); setSize(720 / 2, 1080 / 2); AdbControlPanel panel = new AdbControlPanel(config); panel.setAdbHelper(new AdbHelper(config)); getContentPane().add(panel, BorderLayout.CENTER);
private void makeScreenshot() { adbHelper.screenshot(imageFile); loadImage(imageFile); } private void loadImage(File file) { try { image = ImageIO.read(file); } catch(IOException ex) { ex.printStackTrace(); return; } repaint(); } protected void paintComponent(Graphics g) { super.paintComponent(g); if(image != null) { screenWidth = image.getWidth(); screenHeight = image.getHeight(); int width = getWidth(); int height = getHeight(); double ratioX = (double) width / (double) screenWidth; double ratioY = (double) height / (double) screenHeight; ratio = Math.min(1, Math.min(ratioX, ratioY)); double scaledWidth = (double) screenWidth * ratio; double scaledHeight = (double) screenHeight * ratio; g.drawImage(image, 0, 0, (int) scaledWidth, (int) scaledHeight, null); } } 3.3. thread ¶
while(!Thread.interrupted()) { makeScreenshot(); try { Thread.sleep(config.getScreenshotDelay()); } catch(InterruptedException ex) { break; } }
If this method were to be called twice in succession, the second call would return false (unless the current thread were interrupted again, after the first call had cleared its interrupted status and before the second call had examined it).
3.4. misc ¶
3.5. ant ¶tcheun@tcheun-system:~/download/adbcontrol$ ls build build.xml config.properties epl-v10.html src
<project name="adbcontrol" basedir="." default="main"> <property name="src.dir" value="src"/> <property name="build.dir" value="build"/> <property name="classes.dir" value="${build.dir}/classes"/> <property name="jar.dir" value="${build.dir}/jar"/> <property name="main-class" value="name.schedenig.adbcontrol.AdbControl"/> <target name="clean"> 4. droidAtScreen ¶
4.1. DroidAtScreenApplication.java ¶import com.ribomation.droidAtScreen.cmd.AdbExePathCommand;^M import com.ribomation.droidAtScreen.cmd.Command;^M import com.ribomation.droidAtScreen.dev.AndroidDevice;^M import com.ribomation.droidAtScreen.dev.AndroidDeviceListener;^M import com.ribomation.droidAtScreen.dev.AndroidDeviceManager;^M import com.ribomation.droidAtScreen.gui.ApplicationFrame;^M import com.ribomation.droidAtScreen.gui.DeviceFrame;^M import com.ribomation.droidAtScreen.gui.DeviceTableModel;^M public class DroidAtScreenApplication implements Application, AndroidDeviceListener
public static void main(String[] args) {^M DroidAtScreenApplication app = new DroidAtScreenApplication();^M app.parseArgs(args);^M app.initProperties();^M app.initCommands();^M app.initGUI();^M app.initAndroid();^M app.run();^M app.postStart();^M }^M
@Override^M public ApplicationFrame getAppFrame() {^M return appFrame;^M }^M
2016-09-01 19:32:08,483 INFO AndroidDeviceManager - ADB changed 2016-09-01 19:32:08,484 INFO AndroidDeviceManager - Connected to ADB via /127.0.0.1:5037
public void connected(final AndroidDevice dev) {^M log.debug("connected: dev=" + dev);^M ^M SwingUtilities.invokeLater(new Runnable() {^M @Override^M public void run() {^M getAppFrame().getStatusBar().message("Connected to " + dev.getName());^M ^M DeviceFrame frame = new DeviceFrame(DroidAtScreenApplication.this, dev);^M deviceTableModel.add(frame);^M fireDeviceConnected(dev);^M ^M frame.setVisible(!getSettings().isHideEmulators() || !dev.isEmulator());^M ^M updateDeviceFramePositionsOnScreen(frame);^M }^M });^M }^M 2016-09-08 12:52:35,078 INFO AndroidDeviceManager - Device connected: 5d027563 2016-09-08 12:52:35,079 DEBUG DroidAtScreenApplication - connected: dev=5d027563 (device) 2016-09-08 12:52:35,100 DEBUG DeviceFrame:5d027563 - DeviceFrame(device=5d027563 (device)) 2016-09-08 12:52:35,172 DEBUG DeviceFrame:5d027563 - getPreferredSize: screen=java.awt.Dimension[width=1855,height=1056], canvas=java.awt.Dimension[width=200,height=300], frame=java.awt.Dimension[width=251,height=348] 2016-09-08 12:52:35,172 DEBUG DeviceFrame:5d027563 - getPreferredSize: frame2=java.awt.Dimension[width=210,height=330] 2016-09-08 12:52:35,174 DEBUG DroidAtScreenApplication - devices size: count=1 2016-09-08 12:52:35,335 DEBUG AndroidDeviceManager - Device changed: 5d027563, mask=CHANGE_BUILD_INFO 2016-09-08 12:52:44,998 DEBUG DeviceFrame:5d027563 - Got screenshot RawImage[1080x1920, 8294400 bytes, bits/px=32], elapsed 9871 ms 2016-09-08 12:52:44,999 DEBUG DeviceFrame:5d027563 - Image width 1080, Image hight 1920 ms 2016-09-08 12:52:45,235 DEBUG DeviceFrame:SHV-E330K - getPreferredSize: screen=java.awt.Dimension[width=1855,height=1056], canvas=java.awt.Dimension[width=1080,height=1920], frame=java.awt.Dimension[width=1121,height=1938] 2016-09-08 12:52:45,235 DEBUG DeviceFrame:SHV-E330K - getPreferredSize: frame2=java.awt.Dimension[width=1121,height=950] 2016-09-08 12:52:45,238 DEBUG DroidAtScreenApplication - devices size: count=1
public class DeviceFrame extends JFrame implements Comparable<DeviceFrame> {^M private final static RenderingHints HINTS = new RenderingHints(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);^
tcheun@tcheun-system:~/my-app/target$ java -jar droidAtScreen-1.2.jar 2016-09-01 19:32:02,732 DEBUG DroidAtScreenApplication - parseArgs: [] 2016-09-01 19:32:02,733 DEBUG DroidAtScreenApplication - initProperties 2016-09-01 19:32:02,806 DEBUG Settings - --- Application Settings --- 2016-09-01 19:32:03,133 DEBUG Settings - adbExecutable: /home/tcheun/Android/Sdk/platform-tools/adb 2016-09-01 19:32:03,133 DEBUG DroidAtScreenApplication - initCommands 2016-09-01 19:32:03,166 DEBUG DroidAtScreenApplication - initGUI 2016-09-01 19:32:04,617 DEBUG DroidAtScreenApplication - initAndroid 2016-09-01 19:32:04,722 DEBUG DroidAtScreenApplication - run 2016-09-01 19:32:04,737 DEBUG DroidAtScreenApplication - postStart 2016-09-01 19:32:08,483 INFO AndroidDeviceManager - ADB changed 2016-09-01 19:32:08,484 INFO AndroidDeviceManager - Connected to ADB via /127.0.0.1:5037 1. Initialize the adb interface and get a handle to the bridge:
private void initAndroid() {^M log.debug("initAndroid");^M deviceManager = new AndroidDeviceManager(this);^M deviceManager.initManager();^M timer = new Timer("Screenshot Retrievers");^M }^M
public void initManager() {^M AndroidDebugBridge.init(false);^M Runtime.getRuntime().addShutdownHook(this);^M AndroidDebugBridge.addDebugBridgeChangeListener(this);^M AndroidDebugBridge.addDeviceChangeListener(this);^M }^M private void postStart() {^M log.debug("postStart");^M ^M File adbExePath = getSettings().getAdbExecutable();^M if (adbExePath == null) {^M adbExePath = isExe("ANDROID_HOME");^M log.debug("postStart: adbExePath=" + adbExePath); }^M if (adbExePath == null) {^M adbExePath = isExe("ANDROID_SDK_HOME");^M }^M if (adbExePath == null) {^M Command.find(AdbExePathCommand.class).execute();^M } else {^M getSettings().setAdbExecutable(adbExePath);^M getDeviceManager().setAdbExecutable(adbExePath);^M getDeviceManager().createBridge();^M }^M }^M public void createBridge() {^M if (getAdbExecutable() == null) {^M throw new IllegalArgumentException("Need to set the ADB exe path first, before starting the bridge.");^M }^M ^M try {^M AndroidDebugBridge.createBridge(getAdbExecutable().getCanonicalPath(), true);^M log.info("Connected to ADB via " + getSocketAddress());^M } catch (IOException e) {^M throw new RuntimeException("Failed to created the absolute path to the ADB executable: " + getAdbExecutable());^M }^M }^M 2. Set up a listener (an implementation of the IDeviceChangeListener interface) for device changes and add it:
public interface AndroidDeviceListener {^M ^M /**^M * Invoked when a new device is detected.^M * ^M * @param dev^M * the new device^M */^M void connected(AndroidDevice dev);^M ^M /**^M * Invoked when a device goes offline.^M * ^M * @param dev^M * the defunct device^M */^M void disconnected(AndroidDevice dev);^M }^M
public void connected(final AndroidDevice dev) {^M log.debug("connected: dev=" + dev);^M ^M SwingUtilities.invokeLater(new Runnable() {^M @Override^M public void run() {^M getAppFrame().getStatusBar().message("Connected to " + dev.getName());^M ^M DeviceFrame frame = new DeviceFrame(DroidAtScreenApplication.this, dev);^M deviceTableModel.add(frame);^M fireDeviceConnected(dev);^M ^M frame.setVisible(!getSettings().isHideEmulators() || !dev.isEmulator());^M ^M updateDeviceFramePositionsOnScreen(frame);^M }^M });^M }^M 4.2. Application.java ¶import com.ribomation.droidAtScreen.dev.AndroidDevice;^M import com.ribomation.droidAtScreen.dev.AndroidDeviceListener;^M import com.ribomation.droidAtScreen.dev.AndroidDeviceManager;^M import com.ribomation.droidAtScreen.gui.ApplicationFrame;^M import com.ribomation.droidAtScreen.gui.DeviceFrame;^M import com.ribomation.droidAtScreen.gui.DeviceTableModel;^M
4.3. Settings.java ¶
ApplicationFrame.java: setTitle(app.getInfo().getName() + ", Version " + app.getInfo().getVersion()); StatusBar.java: message(app.getInfo().getName() + ", V" + app.getInfo().getVersion()); AboutCommand.java: Info info = app.getInfo(); HelpCommand.java: return new URI(app.getInfo().getHelpUri()); HomeCommand.java: return new URI(app.getInfo().getAppUri()); MailCommand.java: return new URI(app.getInfo().getMailUri()); ScreenshotCommand.java: return new File(cfg.getImageDirectory(), String.format("%s-%d.%s", app.getInfo().getName().toLowerCase(), cfg.nextInt(), cfg.getImageFormat().toLowerCase()));
RemovePropertiesCommand.java: app.getSettings().destroyPreferences(); 4.4. gui/ApplicationFrame.java ¶public static ImageIcon loadIcon(String name) {^M return loadImage(name, "png");^M }^M
1.Ŭ·¡½º¸¦ ¼³°èÇÒ ¶§, ¸â¹öº¯¼ö Áß ¸ðµç ÀνºÅϽº¿¡ °øÅëÀûÀ¸·Î »ç¿ëÇؾßÇÏ´Â °Í¿¡ staticÀ» ºÙÀδÙ. - ÀνºÅϽº¸¦ »ý¼ºÇϸé, °¢ ÀνºÅϽºµéÀº ¼·Î µ¶¸³ÀûÀ̱⠶§¹®¿¡ ¼·Î ´Ù¸¥ °ªÀ» À¯ÁöÇÑ´Ù. °æ¿ì¿¡ µû¶ó¼´Â °¢ ÀνºÅϽºµéÀÌ °øÅëÀûÀ¸·Î °°Àº °ªÀÌ À¯ÁöµÇ¾î¾ß ÇÏ´Â °æ¿ì staticÀ» ºÙÀδÙ. 2. staticÀÌ ºÙÀº ¸â¹öº¯¼ö´Â ÀνºÅϽº¸¦ »ý¼ºÇÏÁö ¾Ê¾Æµµ »ç¿ëÇÒ ¼ö ÀÖ´Ù. - staticÀÌ ºÙÀº ¸â¹öº¯¼ö(Ŭ·¡½ºº¯¼ö)´Â Ŭ·¡½º°¡ ¸Þ¸ð¸®¿¡ ¿Ã¶ó°¥¶§ ÀÌ¹Ì ÀÚµ¿ÀûÀ¸·Î »ý¼ºµÇ±â ¶§¹®ÀÌ´Ù. 3. staticÀÌ ºÙÀº ¸Þ¼µå(ÇÔ¼ö)¿¡¼´Â ÀνºÅϽº º¯¼ö¸¦ »ç¿ëÇÒ ¼ö ¾ø´Ù. - staticÀÌ ºÙÀº ¸Þ¼µå´Â ÀνºÅϽº »ý¼º ¾øÀÌ È£Ãâ°¡´ÉÇÑ ¹Ý¸é, ÀνºÅϽº º¯¼ö´Â ÀνºÅϽº¸¦ »ý¼ºÇؾ߸¸ Á¸ÀçÇϱ⠶§¹®¿¡... staticÀÌ ºÙÀº ¸Þ¼µå(Ŭ·¡½º¸Þ¼µå)¸¦ È£ÃâÇÒ ¶§ ÀνºÅϽº°¡ »ý¼ºµÇ¾îÀÖÀ»¼öµµ ±×·¸Áö ¾ÊÀ» ¼öµµ ÀÖ¾î¼ staticÀÌ ºÙÀº ¸Þ¼µå¿¡¼ ÀνºÅϽºº¯¼öÀÇ »ç¿ëÀ» Çã¿ëÇÏÁö ¾Ê´Â´Ù. (¹Ý´ë·Î, ÀνºÅϽºº¯¼ö³ª ÀνºÅϽº¸Þ¼µå¿¡¼´Â staticÀÌ ºÙÀº ¸â¹öµéÀ» »ç¿ëÇÏ´Â °ÍÀÌ ¾ðÁ¦³ª °¡´ÉÇÏ´Ù. ÀνºÅϽºº¯¼ö°¡ Á¸ÀçÇÑ´Ù´Â °ÍÀº staticÀÌ ºÙÀº º¯¼ö°¡ ÀÌ¹Ì ¸Þ¸ð¸®¿¡ Á¸ÀçÇÑ´Ù´Â °ÍÀ» ÀǹÌÇϱ⠶§¹®ÀÌ´Ù.) 4. ¸Þ¼µå ³»¿¡¼ ÀνºÅϽº º¯¼ö¸¦ »ç¿ëÇÏÁö ¾Ê´Â´Ù¸é, staticÀ» ºÙÀÌ´Â °ÍÀ» °í·ÁÇÑ´Ù. - ¸Þ¼µåÀÇ ÀÛ¾÷³»¿ëÁß¿¡¼ ÀνºÅϽº º¯¼ö¸¦ ÇÊ¿ä·Î ÇÑ´Ù¸é, staticÀ» ºÙÀÏ ¼ö ¾ø´Ù. ¹Ý´ë·Î ÀνºÅϽºº¯¼ö¸¦ ÇÊ¿ä·Î ÇÏÁö ¾Ê´Â´Ù¸é, °¡´ÉÇϸé staticÀ» ºÙÀÌ´Â °ÍÀÌ ÁÁ´Ù. ¸Þ¼µå È£Ãâ½Ã°£ÀÌ Âª¾ÆÁö±â ¶§¹®¿¡ È¿À²ÀÌ ³ô¾ÆÁø´Ù. (staticÀ» ¾ÈºÙÀÎ ¸Þ¼µå´Â ½ÇÇà½Ã È£ÃâµÇ¾î¾ßÇÒ ¸Þ¼µå¸¦ ã´Â °úÁ¤ÀÌ Ãß°¡ÀûÀ¸·Î ÇÊ¿äÇϱ⠶§¹®¿¡ ½Ã°£ÀÌ ´õ °É¸°´Ù.) 5. Ŭ·¡½º ¼³°è½Ã staticÀÇ »ç¿ëÁöħ - ¸ÕÀú Ŭ·¡½ºÀÇ ¸â¹öº¯¼öÁß ¸ðµç ÀνºÅϽº¿¡ °øÅëµÈ °ªÀ» À¯ÁöÇؾßÇÏ´Â °ÍÀÌ ÀÖ´ÂÁö »ìÆ캸°í ÀÖÀ¸¸é, staticÀ» ºÙ¿©ÁØ´Ù. - ÀÛ¼ºÇÑ ¸Þ¼µå Áß¿¡¼ ÀνºÅϽº º¯¼ö¸¦ »ç¿ëÇÏÁö ¾Ê´Â ¸Þ¼µå¿¡ ´ëÇؼ staticÀ» ºÙÀÏ °ÍÀ» °í·ÁÇÑ´Ù. ÀϹÝÀûÀ¸·Î ÀνºÅϽºº¯¼ö¿Í °ü·ÃµÈ ÀÛ¾÷À» ÇÏ´Â ¸Þ¼µå´Â ÀνºÅϽº¸Þ¼µå(staticÀÌ ¾ÈºÙÀº ¸Þ¼µå)ÀÌ°í staticº¯¼ö(Ŭ·¡½ºº¯¼ö)¿Í °ü·ÃµÈ ÀÛ¾÷À» ÇÏ´Â ¸Þ¼µå´Â Ŭ·¡½º¸Þ¼µå(staticÀÌ ºÙÀº ¸Þ¼µå)¶ó°í º¸¸é µÈ´Ù. 4.5. DeviceFrame.java ¶
app.name=Droid@Screen^M app.version=1.2^M build.date=2016-09-04^M app.uri=http://droid-at-screen.ribomation.com/^M help.uri=http://droid-at-screen.ribomation.com/user-assisted-support/^M mail.uri=mailto:jens.riboe@ribomation.se&subject=Droid@Screen%20Feedback^M
public void connected(final AndroidDevice dev) {^M log.debug("connected: dev=" + dev);^M ^M SwingUtilities.invokeLater(new Runnable() {^M @Override^M public void run() {^M getAppFrame().getStatusBar().message("Connected to " + dev.getName());^M ^M DeviceFrame frame = new DeviceFrame(DroidAtScreenApplication.this, dev);^M deviceTableModel.add(frame);^M fireDeviceConnected(dev);^M ^M frame.setVisible(!getSettings().isHideEmulators() || !dev.isEmulator());^M ^M updateDeviceFramePositionsOnScreen(frame);^M }^M });^M }^M public class DeviceFrame extends JFrame implements Comparable<DeviceFrame> {^M private final static RenderingHints HINTS = new RenderingHints(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
4.6. AndroidDevice.java ¶public String getName() {^M String name = isEmulator() ? target.getAvdName() : target.getProperty("ro.product.model");^M return name != null ? name : target.getSerialNumber();^M }^M ^M public Map<String, String> getProperties() {^M return target.getProperties();^M }^M 4.7. screenimage ¶
public ScreenImage(RawImage rawImage) {^M this.rawImage = rawImage;^M }^M
4.8. ÀÔ·Â ¶
public void tap(Point p) {^M try {^M String cmd = String.format(Locale.ENGLISH, "input tap %.3f %.3f", p.getX(), p.getY());^M log.debug("SEND: "+cmd);^M target.executeShellCommand(cmd, new IShellOutputReceiver() {^M @Override^M public void addOutput(byte[] data, int offset, int length) {^M log.debug(String.format("SHELL: %s", new String(data, offset, length)));^M }^M ^M @Override^M public void flush() { }^M ^M @Override^M public boolean isCancelled() { return false; }^M });^M } catch (Exception e) {^M log.debug("Failed to send 'input tap' command to the device", e);^M }^M }^M
canvas.addMouseListener(new MouseAdapter() {^M @Override^M public void mouseClicked(MouseEvent e) {^M Point p = e.getPoint();^M log.debug(String.format("mouse: %s", p));^M p = new Point(^M (int) (p.getX() * 100) / getScale(),^M (int) (p.getY() * 100) / getScale()^M );^M log.debug(String.format("scaled: %s", p));^M device.tap(p);^M }^M });^M 4.9. image Å©±â¿Í À§Ä¡ º¯°æ ¶
5.2. 3.0 ¶
public void initialize() {^M mMainFrame = new MainFrame(mArgs);^M mMainFrame.setLocationRelativeTo(null);^M mMainFrame.setVisible(true);^M mMainFrame.selectDevice();^M }^M
5.3. MainFrame.java ¶
parseArgs(args);^M ^M initializePrefs(); version, portrait, zoom FbType À» ÀúÀåÇÏ°í, prefVer, mPortrait, mZoom, mFbType ¸¦ ¼³Á¤ÇÑ´Ù. initializeFrame(); setTitle("Android Screen Monitor"); ¿Ö µ¿ÀÛÀ» ¾È ÇßÀ»±î? initializePanel(); initializeMenu(); ¾Æ ¿ª½Ã µ¿ÀÛÀ» ¾È ÇÑ °Í °°´Ù. initializeActionMap();^M ^M addMouseListener(mMouseListener);^M addWindowListener(mWindowListener);^M addMouseMotionListener(mMouseMotionListener);^M addKeyListener(mKeyListener);^M ^M pack();^M setImage(null); À©µµ¿ì µð½ºÇ÷¹ÀÌ(¿Ö ŸÀ̵éÀÌ ¾øÁö?)
adb path is /home/tcheun/Android/Sdk/platform-tools/adb 9¿ù 20, 2016 4:48:23 ¿ÀÀü com.android.chimpchat.ChimpManager sendMonkeyEventAndGetResponse Á¤º¸: Monkey Command: wake. 9¿ù 20, 2016 4:48:42 ¿ÀÀü com.android.chimpchat.ChimpManager sendMonkeyEventAndGetResponse Á¤º¸: Monkey Command: getvar build.device. com.android.ddmlib.AdbCommandRejectedException: device '5d027563' not found at com.android.ddmlib.AdbHelper.setDevice(AdbHelper.java:774) at com.android.ddmlib.AdbHelper.getFrameBuffer(AdbHelper.java:286) at com.android.ddmlib.Device.getScreenshot(Device.java:428) at com.adakoda.android.asm.MainFrame$MonitorThread.getDeviceImage(Unknown Source) public void startMonitor() {^M mMonitorThread = new MonitorThread();^M mMonitorThread.start();^M }^M 5.4. setImage ¶
package com.adakoda.android.asm;^M ^M import javax.swing.SwingUtilities;^M ^M public class AndroidScreenMonitor {^M ^M private MainFrame mMainFrame;^M private static String[] mArgs;^M ^M public AndroidScreenMonitor() {^M }^M ^M public void initialize() {^M mMainFrame = new MainFrame(mArgs);^M mMainFrame.setLocationRelativeTo(null);^M mMainFrame.setVisible(true);^M mMainFrame.setFocusable(true);^M mMainFrame.selectDevice();^M }^M ^M public static void main(String[] args) {^M mArgs = args;^M SwingUtilities.invokeLater(new Runnable() {^M public void run() {^M new AndroidScreenMonitor().initialize();^M }^M });^M }^M }^M 5.5. Thread ¶
public void run() {^M Thread thread = Thread.currentThread();^M if (mDevice != null) {^M try {^M while (mMonitorThread == thread) {^M final FBImage fbImage = getDeviceImage();^M SwingUtilities.invokeLater(new Runnable() {^M public void run() {^M setImage(fbImage);^M }^M });^M }^M } catch (IOException e) {^M }^M }^M }^M 5.6. point ¶
public void initialize() {^M mMainFrame = new MainFrame(mArgs);^M mMainFrame.setLocationRelativeTo(null);^M mMainFrame.setVisible(true);^M mMainFrame.setFocusable(true);^M mMainFrame.selectDevice();^M }^M
private void initialize(String[] args) {^M mADB = new ADB();^M if (!mADB.initialize(args)) {^M JOptionPane.showMessageDialog(this,^M "Could not find adb, please install Android SDK and set path to adb.",^M "Error", JOptionPane.ERROR_MESSAGE);^M }^M ^M parseArgs(args);^M ^M initializePrefs();^M initializeFrame();^M initializePanel();^M initializeMenu();^M initializeActionMap();^M ^M addMouseListener(mMouseListener);^M addWindowListener(mWindowListener);^M addMouseMotionListener(mMouseMotionListener);^M addKeyListener(mKeyListener);^M ^M pack();^M setImage(null);^M }^M
private void initializeFrame() {^M setTitle("Android Screen Monitor");^M setIconImage(Toolkit.getDefaultToolkit().getImage(^M getClass().getResource("icon.png")));^M setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);^M setResizable(false);^M }^M
private void initializePanel() {^M mPanel = new MainPanel();^M add(mPanel);^M }^M
public void run() {^M Thread thread = Thread.currentThread();^M if (mDevice != null) {^M try {^M while (mMonitorThread == thread) {^M final FBImage fbImage = getDeviceImage();^M SwingUtilities.invokeLater(new Runnable() {^M public void run() {^M setImage(fbImage);^M }^M });^M }^M } catch (IOException e) {^M }^M }^M }^M 5.7. Painting ¶
5.8. AdbChimpDevice ¶
AndroidDebugBridge.addDebugBridgeChangeListener(this); AndroidDebugBridge.addDeviceChangeListener(this); AndroidDebugBridge.addClientChangeListener(this);
MainFrame.java:import com.android.chimpchat.adb.AdbChimpDevice; MainFrame.java: private AdbChimpDevice mChimpDevice; MainFrame.java: mChimpDevice = new AdbChimpDevice(mDevice); MainFrame.java: mBuildDevice = mChimpDevice.getProperty("build.device"); MainFrame.java: mChimpDevice.getManager().touchUp(real.x, real.y); MainFrame.java: mChimpDevice.getManager().press("KEYCODE_DPAD_CENTER"); MainFrame.java: mChimpDevice.getManager().touchDown(real.x, real.y); MainFrame.java: if (mChimpDevice != null) { MainFrame.java: mChimpDevice.dispose(); MainFrame.java: mChimpDevice.getManager().touchMove(real.x, real.y); MainFrame.java: mChimpDevice.getManager().press("KEYCODE_DEL"); MainFrame.java: mChimpDevice.getManager().press("KEYCODE_DPAD_CENTER"); MainFrame.java: mChimpDevice.getManager().press("KEYCODE_SPACE"); MainFrame.java: mChimpDevice.getManager().press("KEYCODE_HOME"); MainFrame.java: mChimpDevice.getManager().press("KEYCODE_DPAD_LEFT"); MainFrame.java: mChimpDevice.getManager().press("KEYCODE_DPAD_RIGHT"); MainFrame.java: mChimpDevice.getManager().press("KEYCODE_DPAD_UP"); MainFrame.java: mChimpDevice.getManager().press("KEYCODE_DPAD_DOWN"); MainFrame.java: mChimpDevice.getManager().type(c); 5.9. chimpchat ¶The latest version of the Android SDK and tools include chimpchat, a library that facilitates the use of monkey from Java. This is equivalent to monkeyrunner, which is the bridge between monkey and the Python scripting language. While Python is an incredibly powerful and expressive scripting language and will permit you creating tests with just a few statements, there are some occasions when you don't want to introduce a new language to the project leaving your Java confort zone or you prefer to leverage the use of previously created libraries instead of writing new ones. In such cases, you can now have the same access to monkey running on the device with the help of chimpchat, as we are going to demonstrate.
The monkeyrunner tool provides an API for writing programs that control an Android device or emulator from outside of Android code. With monkeyrunner, you can write a Python program that installs an Android application or test package, runs it, sends keystrokes to it, takes screenshots of its user interface, and stores screenshots on the workstation. The monkeyrunner tool is primarily designed to test applications and devices at the functional/framework level and for running unit test suites, but you are free to use it for other purposes. The monkeyrunner tool is not related to the UI/Application Exerciser Monkey, also known as the monkey tool. The monkey tool runs in an adb shell directly on the device or emulator and generates pseudo-random streams of user and system events. In comparison, the monkeyrunner tool controls devices and emulators from a workstation by sending specific commands and events from an API.
Interface between MonkeyRunner common code and the MonkeyRunner backend. The backend is responsible for communicating between the host and the device.
5.10. ÀÚÀ¯°Ô½ÃÆÇ¿¡ ¿Ã¸± ±Û Á¤¸® ¶»îÀÇ ¿©À¯°¡ »ý°Ü ¸®´ª½º¸¦ ´Ù½Ã º¸°í ÀÖÀ¾´Ï´Ù. ³Ê¹« »ý¼ÒÇÑ ´Ü¾îµéÀÌ ¸¹±º¿ä. µ¥½ºÅ©Å¾ ¸®´ª½º°¡ ¾î¶² »óȲÀÎÁö¸¦ º¸´Ï, »ý°¢º¸´Ù ³Ê¹« ÀúÁ¶ÇØ º¸ÀÔ´Ï´Ù. ¹Ý¸é smartphone ÀÇ ¾àÁøÀÌ ´«¿¡ ¶ç´Â±º¿ä. ÀϹÝÀο¡°Ô µ¥½ºÅ©Å¾Àº Á¡Á¡ »ç¿ëÀÇ Çʿ伺ÀÌ ¾ø¾îÁú °Í °°¾Æ º¸ÀÔ´Ï´Ù. Àüö¿¡¼, ¹ö½º¿¡¼, ±æ°Å¸®¿¡¼ ¸ðµç »ç¶÷ÀÌ smartphone À» µé¿©´Ù º¸°í ÀÖÀ¾´Ï´Ù. ¸®´ª½º µ¥½ºÆ®Å¾À» smartphone ÀÇ º¸Á¶ÀåÄ¡·Î »ç¿ëÇÏ´Â °ÍÀº ¾î¶³±î? »çÁøµéÀÇ ÀúÀå Å« ȸ鿡¼ °ÔÀÓ, ¹Ìµð¾î Ç÷¹ÀÌ °³ÀÎÀÎÁõÀÌ ÇÊ¿äÇÑ ¾îÇÃ
7. Design ¶
|
Generosity and perfection are your everlasting goals. |