· KLDP.org · KLDP.net · KLDP Wiki · KLDP BBS ·
Android Mirroring

Android mirroring °ü·Ã ÇÁ·Î±×·¥ ºÐ¼®


1. ȯ°æ

  • Ubuntu 16.04
  • °¶·°½Ã s4
  • USB ¿¬°á½Ã PTP ¸ðµå·Î ¼³Á¤

  • Kernel Upgrade ½Ã
    • cd /home/tcheun/rtl8812AU_8821AU_linux
    • make
    • sudo make install
    • sudo modprobe 8812au

  • ¡°Screen mirroring¡± is a tech-industry term used to describe a form of wireless device-to-device communication software.
  • ¡°Screen mirroring¡± is a way to make your smart phone, tablet and computer screens appear on other screens.

  • Display android device screen on the other device
  • remotely control my Android device from my Linux desktop

  • 2016.9.22 kernel version upgrade
  • wifi ÀÇ ¹®Á¦
  • 4.4.0-38 dpt 4.4.0-36 À¸·Î grub.cfg º¯°æ

1.1. Technology


  • technology behind screen mirroring
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
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
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. °ü·Ã ¼ÒÇÁÆ®¿þ¾î

  • KDE connect
  • SideSync samsung

  • 2016-9-9
    • KDE connect
  • google cast remote api
  • screen mirroring technologies
  • cast receiver

  • https://developers.google.com/cast/docs/remote

  • º¸³»´Â ÂÊ°ú ¹Þ´Â ÂÊ¿¡ °¢°¢ ÇÁ·Î±×·¥ÀÌ ÀÖ¾î¾ß ÇÑ´Ù.
  • ¾Èµå·ÎÀÌµå µð¹ÙÀ̽º°¡ °³¹ßÀÚ ¸ðµå¿©¾ß ÇÏ´Â °ÍÀº adbd °¡ º¸³»´Â ÂÊ¿¡¼­ ¼öÇàµÇ¾î¾ß Çϱ⠶§¹®ÀÌ´Ù.

  • cast sender ¿Í reseiver À» °è¼Ó followup ÇÏ´Â °Í°ú androidatscreen À» ¼öÁ¤ÇÏ´Â ÀÛ¾÷À» º´ÇàÇÑ´Ù?

  • adb shell
  • ddmlib
    • A ddmlib jar that provides APIs for talking with Dalvik VM (both on Android phones and emulators).

2.1. Hardware


  • Set-top boxes
    • Apple TV - Airplay
    • Roku
    • Amazon Fire TV - android: miracast iOS: Allcast

  • Dongles
    • Chromecast
    • Miracast

  • TVs
    • Samsung's AllShare system

3. adbcontrol

  • http://marian.schedenig.name/2014/07/03/remote-control-your-android-phone-through-adb/

  • adb shell command ¸¦ »ç¿ëÇÏ¿© ÇÊ¿äÇÑ ÀÛ¾÷À» ÇÏ´Â method °¡ AdbHelper.java ¿¡ ¼³Á¤µÇ¾î ÀÖ´Ù.

  • private void executeShellCommand(String cmd)
    • executeShellCommand(cmd, null);
  • private void executeShellCommand(String cmd, OutputStream out)
    • executeCommand("shell " + cmd, out);

  • private void executeCommand(String cmd, OutputStream out)
    • adb ½ÇÇà

3.1. AdbControl.java

  • config.properties ÆÄÀÏÀ» Àаí, ŸÀÌƲÀÌ AdbControl ÀÎ À©µµ¿ì¸¦ Ãâ·Â
  • phoneImageFilePath = /mnt/sdcard/adbcontrol_screenshot.png ´Â ¼öÁ¤ÇÏÁö ¸»°Í.

  • ¿¬°áÇÏÁö ¾ÊÀº »óÅ¿¡¼­ ¼öÇà
  • AdbControlPanel$2.run(AdbControlPanel.java:89)
  • AdbControlPanel.access$0(AdbControlPanel.java:245)
  • AdbControlPanel.makeScreenshot(AdbControlPanel.java:248)
  • AdbControlPanel.loadImage(AdbControlPanel.java:255)
  • javax.imageio.ImageIO.read(ImageIO.java:1301)

  • AdbControl frame = new AdbControl(configFile);
    • AdbControlPanel panel = new AdbControlPanel(config);
    • panel.setAdbHelper(new AdbHelper(config));
    • getContentPane().add(panel, BorderLayout.CENTER);
      • startUpdateThread();
        • makeScreenshot();
          • adbHelper.screenshot(imageFile);
          • loadImage(imageFile);

        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());
        }

  • config.properties ÀÇ localImageFilePath ¿¡ screenshot ÀúÀå?

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();
        }

  • repaint ¿¡¼­ ÀúÀåµÈ À̹ÌÁö¸¦ È­¸é¿¡ Ãâ·Â?

3.2. È­¸é¿¡ Ãâ·Â


  • AdbControl.java

    • public class AdbControl extends JFrame
    • public static void main(String[] args)
                        AdbControl frame = new AdbControl(configFile);
                        frame.setVisible(true);
    • public AdbControl(File configFile) throws IOException
                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);
    • JFrame size ¸¦ 360, 5040 À¸·Î °íÁ¤

  • AdbControlPanel.java
    • public class AdbControlPanel extends JPanel
      • public AdbControlPanel(Config config)
        • addComponentListener(new ComponentAdapter()
          • public void componentResized(ComponentEvent e)
            • startUpdateThread();
        • addMouseListener(this);
        • addKeyListener(this);

    • protected void startUpdateThread()
      • public void run()
        • makeScreenshot();
      • protected void paintComponent(Graphics g)
        • super.paintComponent(g);
          • g.drawImage(image, 0, 0, (int) scaledWidth, (int) scaledHeight, null);
        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


  • AdbControlPanel.java

  • public class AdbControlPanel extends JPanel implements MouseListener, KeyListener
    • protected Thread updateThread;
    • public AdbControlPanel(Config config)
      • addComponentListener(new ComponentAdapter()
        • public void componentHidden(ComponentEvent e)
          • stopUpdateThread();
        • public void componentResized(ComponentEvent e)
          • startUpdateThread();
    • protected void stopUpdateThread()
    • protected void startUpdateThread()
      • updateThread = new Thread()
      • public void run()
                                        while(!Thread.interrupted())
                                        {
                                                makeScreenshot();

                                                try
                                                {
                                                        Thread.sleep(config.getScreenshotDelay());
                                                }
                                                catch(InterruptedException ex)
                                                {
                                                        break;
                                                }
                                        }

      • updateThread.start();

  • componentlistener ¿¡ ÀÇÇØ componentResized ¸é startUpdateThread ¼öÇà
    • startUpdateThread ¿¡¼­ updateThread °¡ null À̸é updateThread ½º·¹µå¸¦ »ý¼ºÇÏ°í, updateThread.start(); ¿¡ ÀÇÇØ run¿¡ ÇØ´çÇÏ´Â thread °¡ ¼öÇàµÈ´Ù.
      • while loop ·Î Thread.interrupted() ¸¦ °è¼Ó ¼öÇàÇÑ´Ù.
      • ¾ÕÀÇ interrupt ÀÇÇÑ interrupted status °¡ clear µÇ±â Àü¿¡ ´ÙÀ½ interrupt °¡ ¼öÇàµÇ¸é, false ¸¦ ¸®ÅÏÇÏ°í, makeScreenshot À» ¼öÇàÇÑ´Ù.
      • config.getScreenshotDelay() ¸¸Å­ thread ´Â sleep ÇÑ ÈÄ ±ú¾î³ª¸é loop ¸¦ µ·´Ù.
  • Thread.interrupted()
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).
  • Thread.sleep
  • updateThread.start();

3.4. misc

  • repaint ¿¡ ÀÇÇØ paintComponent °¡ ¼öÇàµÊ.
  • ÀÌ´Â Æгο¡ À̹ÌÁö¸¦ Ãà¼Ò½ÃÄÑ Ãâ·ÂÇÏ´Â °ÍÀ¸·Î º¸À̴µ¥...
  • µû·Î Ãâ·ÂµÇ´Â À̹ÌÁö´Â ¾îµð¼­ Ãâ·ÂÇϴ°¡? super.paintComponent(g); ?
  • ³»°¡ Çò°¥¸®°í Àִ°¡?
  • vysor ³ª airdroid °¡ µ¹°í ÀÖ¾ú³ª?

3.5. ant


tcheun@tcheun-system:~/download/adbcontrol$ ls
build  build.xml  config.properties  epl-v10.html src

  • ant
  • ant run

  • build.xml

<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">
        
    </target>

    <target name="compile">
        <mkdir dir="${classes.dir}"/>
        <javac srcdir="${src.dir}" destdir="${classes.dir}"/>
    </target>

    <target name="jar" depends="compile">
        <mkdir dir="${jar.dir}"/>
        <jar destfile="${jar.dir}/${ant.project.name}.jar" basedir="${classes.dir}">
            <manifest>
                <attribute name="Main-Class" value="${main-class}"/>
            </manifest>
        </jar>
    </target>

    <target name="run" depends="jar">
        <java jar="${jar.dir}/${ant.project.name}.jar" fork="true"/>
    </target>

    <target name="clean-build" depends="clean,jar"/>

    <target name="main" depends="clean,run"/>

</project>

4. droidAtScreen

  • http://droid-at-screen.org/

  • export PATH=/home/tcheun/apache-maven-3.3.9/bin:$PATH
  • cd my-app/
  • mvn package
  • cd target/
  • java -jar droidAtScreen-1.2.jar

  • ddmlib ¿Í chimpchat À» »ç¿ëÇϱâ À§ÇØ maven À» ¹ö¸®°í ant ·Î 2016.10.3
  • gradle ¼³Ä¡
    • gradle: /usr/bin/gradle /usr/share/gradle
      • plug-in, dependency, reposiroty
      • cache:
    • export PATH=/usr/share/gradle/bin:$PATH

  • gradle ·Î ÀÌÀüÇϸ鼭 ¹®Á¦µéÀ» ÇØ°á(³ªÁß¿¡ ¼­¼úÇÒ ¼ö ÀÖÀ»±î?) 2016.10.8
  • log4j2 ·ÎÀÇ ÀÌÀü°ü·Ã ¹®Á¦µé.

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 interface AndroidDeviceListener
    • Invoked when a new device is detected. ¾î¶»°Ô?
      • void connected(AndroidDevice dev);
    • Invoked when a device goes offline. ¾î¶»°Ô?
      • void disconnected(AndroidDevice dev);

  • AndroidDeviceManager.java
    • Invoked by ADB, when a new device is attached.
    • public void deviceConnected(IDevice dev)
      • app.connected(new AndroidDevice(dev));

  • ddmlib.AndroidDebugBridge.IDeviceChangeListener
  • public class AndroidDeviceManager extends Thread implements AndroidDebugBridge.IDeviceChangeListener, AndroidDebugBridge.IDebugBridgeChangeListener
    • public void initManager()
      • AndroidDebugBridge.addDeviceChangeListener(this);
    • public void deviceConnected(IDevice dev)
      • app.connected(new AndroidDevice(dev));

        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

  • app.parseArgs(args); ÇöÀç args ¸¦ ÀÌ¿ëÇÏ´Â °ÍÀº ¾øÀ½. Â÷ÈÄ °¡´É¼º
  • app.initProperties(); /app.properties ¿¡ ¼³Á¤µÈ °ªµéÀ» Settings Ŭ·¡½º¿¡ ÀúÀåÇÏ°í »ç¿ëÇÑ´Ù.
    • settings = new Settings(); Settings.java
    • settings.dump();
  • app.initCommands(); /src/main/java/com/ribomation/droidAtScreen/cmd ÀÇ Å¬·¡½ºµé
    • Command.setApplication(this);
  • app.initGUI
    • appFrame = new ApplicationFrame(this);
    • appFrame.initGUI(); ApplicationFrame window »ý¼º
  • app.initAndroid();
    • deviceManager = new AndroidDeviceManager(this);
    • deviceManager.initManager();
    • timer = new Timer("Screenshot Retrievers");
  • app.run();
    • getAppFrame().setVisible(true); À§ÀÇ initGUI ¿¡¼­ »ý¼ºÇÑ ApplicationFrame window µð½ºÇ÷¹ÀÌ

        @Override^M
        public ApplicationFrame getAppFrame() {^M
                return appFrame;^M
        }^M
  • app.postStart
    • getDeviceManager().createBridge(); AndroidDeviceManager
    • public void createBridge()
      • AndroidDebugBridge.createBridge(getAdbExecutable().getCanonicalPath(), true);
      • ¿©±â¿¡¼­ adb ¸¦ start ½ÃÅ°°í, bridge ¿Í socket À¸·Î ¿¬°á½ÃÅ´.

  • ¿©±â¼­ ADB ÀÇ À§Ä¡¹× executable Àΰ¡¸¦ Á¡°ËÇÏÁö¸¸, init Àº initAndroid ¿¡¼­ ÇÔ. adb¿Í »ó°ü¾øÀÌ init ÇÒ ¼ö ÀÖÀ¸¹Ç·Î ¿ø·¡´ë·Î.
  • initAndroid ¿¡¼­ deviceManager.initManager(); ¸¦ comment ·Î ¹Ù²Ù°í, ÀÌ°÷¿¡¼­ getDeviceManager().initManager(); ¹Ù²ÙÁö ¾ÊÀ½.

  • ÀÌÈÄ´Â AndroidDebugBridge.IDeviceChangeListener ¿Í AndroidDebugBridge.IDebugBridgeChangeListener ¿¡ ÀÇÇØ ¼öÇàµÊ.
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 class AndroidDeviceManager extends Thread implements AndroidDebugBridge.IDeviceChangeListener, AndroidDebugBridge.IDebugBridgeChangeListener
    • public void deviceConnected(IDevice dev)
    • Invoked by ADB, when a new device is attached.
      • app.connected(new AndroidDevice(dev)); DroidAtScreenApplicationÀÇ connected ¼öÇà

        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

  • DeviceFrame »ý¼º
  • frame.setVisible DeviceFrame µð½ºÇ÷¹ÀÌ

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

  • DeviceFrame
    • Frame holder for the device image.
public class DeviceFrame extends JFrame implements Comparable<DeviceFrame> {^M
        private final static RenderingHints HINTS = new RenderingHints(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);^
  • deviceTableModel
    • public class DeviceTableModel extends AbstractTableModel
    • private final DeviceTableModel deviceTableModel = new DeviceTableModel();


  • µð¹ÙÀ̽º¿Í ¿¬°áÇÏÁö ¾ÊÀº »óÅ¿¡¼­ ¼öÇà
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:

  • app.initAndroid
        private void initAndroid() {^M
                log.debug("initAndroid");^M
                deviceManager = new AndroidDeviceManager(this);^M
                deviceManager.initManager();^M
                timer = new Timer("Screenshot Retrievers");^M
        }^M

  • AndroidDebugBridge.init(false);^
    • public class AndroidDeviceManager extends Thread implements AndroidDebugBridge.IDeviceChangeListener, AndroidDebugBridge.IDebugBridgeChangeListener

        public void initManager() {^M
                AndroidDebugBridge.init(false);^M
                Runtime.getRuntime().addShutdownHook(this);^M
                AndroidDebugBridge.addDebugBridgeChangeListener(this);^M
                AndroidDebugBridge.addDeviceChangeListener(this);^M
        }^M

  • AndroidDebugBridge adb = AndroidDebugBridge.createBridge();
        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:
  • À§ÀÇ initManager ¿¡¼­ ¼öÇà

  • ADB changed
  • public void bridgeChanged(AndroidDebugBridge adb)

  • import com.ribomation.droidAtScreen.dev.AndroidDeviceListener;
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
  • There are a number of situations in software engineering when it is important for disparate groups of programmers to agree to a "contract" that spells out how their software interacts. Each group should be able to write their code without any knowledge of how the other group's code is written. Generally speaking, interfaces are such contracts.

  • public class DroidAtScreenApplication implements Application, AndroidDeviceListener
    • interface AndroidDeviceListener ÀÇ connected ¿Í disconnected °¡»ó ¸Þ¼ÒµåÀÇ ±¸ÇöÀº DroidAtScreenApplication Ŭ·¡½º¿¡¼­ ÇÑ´Ù.

        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

  • public interface Application
    • ApplicationFrame getAppFrame();
    • Settings getSettings();
    • Info getInfo();
    • AndroidDeviceManager getDeviceManager();
    • void addAndroidDeviceListener(AndroidDeviceListener listener);
    • void updateDeviceFramePositionsOnScreen(DeviceFrame newFrame);
    • List<DeviceFrame> getDevices();
    • void connected(AndroidDevice dev);
    • void disconnected(AndroidDevice dev);
    • DeviceTableModel getDeviceTableModel();
    • void disconnectAll();
    • java.util.Timer getTimer();

  • dev/AndroidDeviceListener.java
  • public interface AndroidDeviceListener
    • void connected(AndroidDevice dev);
    • void disconnected(AndroidDevice dev);^

  • public DeviceFrame(Application app, final AndroidDevice device)

4.3. Settings.java


  • Properties
  • DroidAtScreenApplication.java
    • import java.util.Properties;

    • private void initProperties()
      • InputStream is = this.getClass().getResourceAsStream("/app.properties");
      • appProperties = new Properties();
      • appProperties.load(is);
      • settings = new Settings();
      • settings.dump();

  • app.properties ¿¡ ÀúÀåµÈ ³»¿ëÀº Properties ¿ÀºêÁ§Æ®¿¡ ÀúÀåµÇ°í, getInfo ¿¡ ÀÇÇØ ²ôÁý¾î³½´Ù.
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()));

  • Settings.java
    • import java.beans.PropertyChangeListener;
    • import java.beans.PropertyChangeSupport;
    • import java.util.prefs.Preferences;

    • public Settings()
      • applicationPreferences = Preferences.userNodeForPackage(Settings.class);
      • propSupport = new PropertyChangeSupport(this);

    • public void setAdbExecutable(File value)
    • public void setAskBeforeQuit(boolean value)
    • public void setImageFormat(String value)
    • public void setImageDirectory(File value)
    • public void setAskBeforeScreenshot(boolean value)
    • public void setPreferredScale(int value)
    • public void setHideEmulators(boolean value)
    • public void setUpsideDown(boolean value)
    • public void setLandscape(boolean value)
    • public void setAutoShow(boolean value)

    • private void set(String name, String value)
    • private void set(String name, int value)
    • private void set(String name, boolean value)
      • boolean old = applicationPreferences.getBoolean(name, false);
      • applicationPreferences.putBoolean(name, value);
      • savePreferences();
      • propSupport.firePropertyChange(name, old, value);

RemovePropertiesCommand.java:			app.getSettings().destroyPreferences();

4.4. gui/ApplicationFrame.java


  • /src/main/java/com/ribomation/droidAtScreen/gui/GuiUtil.java
  • public class GuiUtil
        public static ImageIcon loadIcon(String name) {^M
                return loadImage(name, "png");^M
        }^M

  • public class ApplicationFrame extends JFrame
    • private Application app;
    • private StatusBar statusBar; gui/StatusBar.java
    • private final String[] TOOLBAR = { "ImageDirectory", "-", "AdbRestart", "AdbReloadDevices", "-", "Help", "About", "-", "Quit" }; ¸ðµç string ¿¡ ´ëÇØ cmd/stringCommand.java

    • public ApplicationFrame(Application app) throws HeadlessException
      • this.app = app;

    • public void initGUI()
      • setIconImage(GuiUtil.loadIcon("device").getImage());
      • setTitle(app.getInfo().getName() + ", Version " + app.getInfo().getVersion());
      • setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
      • addWindowListener(new WindowAdapter()
      • setJMenuBar(createMenubar());
      • add(GuiUtil.createToolbar(TOOLBAR), BorderLayout.NORTH);
      • add(createDevicesTable(), BorderLayout.CENTER);
      • add(statusBar = new StatusBar(app), BorderLayout.SOUTH);^

      • /src/main/resources/img
  • GuiUtil class ÀÇ function loadIcon Àº ImageIcon object ¸¦ ¸®ÅÏÇÑ´Ù?
  • ImageIcon object ÀÇ getImage function ¿¡ ÀÇÇØ image °¡ ¸®ÅϵȴÙ?
  • loadImage ¿¡ ÀÇÇؼ­´Â ImageIcon object °¡ ¸®ÅϵȴÙ?


  • swing class ImageIcon
  • An implementation of the Icon interface that paints Icons from Images. Images that are created from a URL, filename or byte array are preloaded using MediaTracker to monitor the loaded state of the image.

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


  • private void initProperties()
    • InputStream is = this.getClass().getResourceAsStream("/app.properties");
    • /my-app/target/classes/app.properties

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

  • DroidAtScreenApplication.java
        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);

  • private final AndroidDevice device;

4.6. AndroidDevice.java


  • public class AndroidDevice implements Comparable<AndroidDevice>

        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


  • DeviceFrame.java
  • class Retriever extends TimerTask
    • ScreenImage image = device.getScreenImage();
    • boolean fresh = canvas.getScreenshot() == null;
    • canvas.setScreenshot(image);
    • app.updateDeviceFramePositionsOnScreen(null);

  • AndroidDevice.java
  • public ScreenImage getScreenImage()
    • RawImage rawImage = target.getScreenshot();
    • return new ScreenImage(rawImage);

  • ScreenImage.java
  • public class ScreenImage
        public ScreenImage(RawImage rawImage) {^M
                this.rawImage = rawImage;^M
        }^M

  • DeviceFrame.java
  • private ImageCanvas canvas;
  • public DeviceFrame(Application app, final AndroidDevice device)
    • canvas = new ImageCanvas();
    • canvasScrollable = new JScrollPane(canvas);
    • add(canvasScrollable, BorderLayout.CENTER);
  • class ImageCanvas extends JComponent
    • private ScreenImage image;
    • public ImageCanvas()
    • public void setSkin(Skin skin)
    • public void setScreenshot(ScreenImage image)
      • this.image = image;
      • repaint();
    • public ScreenImage getScreenshot()
    • protected void paintComponent(Graphics g)
    • BufferedImage toLandscape(BufferedImage img)
    • BufferedImage rotate(int quadrants, BufferedImage img)
    • public Dimension getPreferredSize()
    • public Dimension getMinimumSize()

  • main ¿¡¼­ app.initGUI(); ¸¦ call
    • appFrame = new ApplicationFrame(this);
    • appFrame.initGUI(); ApplicationFrame Àº º°µµ·Î µ¿ÀÛ
      • listener ºÐ¼® ÇÊ¿ä
    • device listener ¿¡ ÀÇÇØ connected method ¼öÇà
      • DeviceFrame frame = new DeviceFrame(DroidAtScreenApplication.this, dev);
      • DeviceFrame ¿ÀºêÁ§Æ® »ý¼º. µð¹ÙÀ̽º°¡ ¿¬°á µÉ ¶§¸¶´Ù, »õ·Î¿î DeviceFrame ¿ÀºêÁ§Æ® ¸¦ »ý¼ºÇÑ´Ù.
      • DeviceFrame ¿¡¼­ ImageCanvas(); ¿ÀºêÁ§Æ® canvas¸¦ ¸¸µé°í,
      • À̸¦ JScrollPane(canvas); À¸·Î °¨½Î canvasScrollable ¿ÀºêÁ§Æ®¸¦ ¸¸µç´Ù.
      • DeviceFrame ¿¡ add(canvasScrollable, BorderLayout.CENTER); ÇÑ´Ù.

      • ImageCanvas Ŭ·¡½º¿¡ private ¿ÀºêÁ§Æ® ScreenImage À» »ç¿ëÇÏ¿© È­¸éÀ» Ãâ·ÂÇÑ´Ù.

4.8. ÀÔ·Â


  • AndroidDevice.java
  • input tap
        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

  • DeviceFrame.java
                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 Å©±â¿Í À§Ä¡ º¯°æ


  • android device ÀÇ ppi ¿Í µð½ºÇ÷¹ÀÌ ÇÒ ±â±âÀÇ ppi ÀÇ ºñÀ²·Î Á¤ÇÑ´Ù.(?)

5. AndroidScreenMoniror


5.1. 2.5

5.2. 3.0


  • https://adakoda.github.io/android-screen-monitor/

  • cd /home/tcheun/android-screen-monitor-master/build
  • ant

  • AndroidScreenMonitor().initialize();
    • mMainFrame = new MainFrame(mArgs);
      • initialize(args); - MainFrame.java
        • initializeFrame();
        • initializePanel();
          • mPanel = new MainPanel();
          • add(mPanel);
        • initializeMenu();
          • mPopupMenu = new JPopupMenu();
        • initializeActionMap();
        • setImage(null);
          • mPanel.setFBImage(fbImage);
            • mFBImage = fbImage; - MainPanel Ŭ·¡½ºÀÇ private ¿ÀºêÁ§Æ® (FBImage.java)
            • repaint(); - MainPanel ÀÇ method paintComponent(Graphics g) ¼öÇà
          • updateSize();
    • mMainFrame.selectDevice();
      • SelectDeviceDialog dialog = new SelectDeviceDialog(this, true, list); - MainFrame.java
        • mDevice = mDevicesselectedIndex;
        • setImage(null);
      • mChimpDevice = new AdbChimpDevice(mDevice);
      • startMonitor();

    • public class MonitorThread extends Thread
      • public void run()
        • final FBImage fbImage = getDeviceImage();
        • setImage(fbImage);
      • private FBImage getDeviceImage() throws IOException
        • tmpRawImage = mDevice.getScreenshot();
        • return fbImage;
  • MainFrame ¿¡¼­ MainPanel À» ¸¸µé°í ¿©±âÀÇ private ¿ÀºêÁ§Æ® FBImage ¼³Á¤

  • AndroidScreenMonitor.java
  • public static void main(String[] args)
    • argument ¸¦ ó¸®ÇÒ ºÎºÐ(³ªÁß¿¡ È®Àå?)
    • new AndroidScreenMonitor().initialize();
  • public void initialize()
    • mMainFrame.selectDevice();
        public void initialize() {^M
                mMainFrame = new MainFrame(mArgs);^M
                mMainFrame.setLocationRelativeTo(null);^M
                mMainFrame.setVisible(true);^M
                mMainFrame.selectDevice();^M
        }^M
  • MainFrame À» µð½ºÇ÷¹ÀÌ ÇÏ°í, selectDevice ´ÙÀ̾î·Î±×¸¦ µð½ºÇ÷¹ÀÌÇÑ´Ù.

5.3. MainFrame.java


  • MainFrame.java
  • public MainFrame(String[] args)
    • initialize(args);
  • private void initialize(String[] args)
    • mADB = new ADB();
    • mADB.initialize()
                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); À©µµ¿ì µð½ºÇ÷¹ÀÌ(¿Ö ŸÀ̵éÀÌ ¾øÁö?)

  • public void selectDevice()
    • mDevices = mADB.getDevices();
    • mChimpDevice = new AdbChimpDevice(mDevice); version 2.5 ¿¡´Â ¾øÀ½.
    • mBuildDevice = mChimpDevice.getProperty("build.device"); version 2.5 ¿¡´Â ¾øÀ½.
    • startMonitor();

  • ADB.java
  • public class ADB
    • public boolean initialize()
    • adb path Á¡°Ë¹× ¼³Á¤
      • AndroidDebugBridge.init(false);
      • mAndroidDebugBridge = AndroidDebugBridge.createBridge(adbLocation,true);

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


  • AndroidScreenMonitor.java
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

  • main
    • new AndroidScreenMonitor().initialize();
      • mMainFrame = new MainFrame(mArgs);
        • initialize(args);
          • ¸¹Àº ÀÛ¾÷
          • setImage(null);
            • mPanel.setFBImage(fbImage);

  • public class MainPanel extends JPanel
    • public void setFBImage(FBImage fbImage)
      • mFBImage = fbImage;
      • repaint();
        • protected void paintComponent(Graphics g)
          • super.paintComponent(g);
          • ¿©±â¿¡¼­ Ãʱâ ŸÀÌƲ ¾ø´Â À©µµ¿ì µð½ºÇ÷¹ÀÌ



  • public void setImage(FBImage fbImage)

5.5. Thread


  • MainFrame.java
  • private MonitorThread mMonitorThread;

  • public class MonitorThread extends Thread
    • final FBImage fbImage = getDeviceImage();
    • private FBImage getDeviceImage() throws IOException
      • tmpRawImage = mDevice.getScreenshot();

  • import com.android.ddmlib.IDevice;
  • private IDevice mDevice;

                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


  • AndroidScreenMonitor.java
  • public class AndroidScreenMonitor
    • public static void main(String[] args)
      • new AndroidScreenMonitor().initialize();
        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

  • MainFrame.java
  • public class MainFrame extends JFrame
    • public MainFrame(String[] args)
      • initialize(args);
    • private void initialize(String[] args)
        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

    • initializeFrame()
        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

    • initializePanel()
        private void initializePanel() {^M
                mPanel = new MainPanel();^M
                add(mPanel);^M
        }^M

    • public class MainPanel extends JPanel
      • private FBImage mFBImage;
      • public MainPanel()
      • protected void paintComponent(Graphics g)
      • public void setFBImage(FBImage fbImage)
        • mFBImage = fbImage;
        • repaint();
      • public FBImage getFBImage()
    • public void setFrameBuffer(int fbType)
    • public void saveImage()
      • FBImage inImage = mPanel.getFBImage();
      • ÆÄÀÏ·Î º¸°ü
    • public void setImage(FBImage fbImage)
      • mPanel.setFBImage(fbImage);
      • updateSize();

    • public class MonitorThread extends 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
      • private FBImage getDeviceImage() throws IOException
        • tmpRawImage = mDevice.getScreenshot();
        • fbImage = new FBImage(imageWidth, imageHeight, BufferedImage.TYPE_INT_RGB, rawImage.width, rawImage.height);
        • return fbImage;

5.7. Painting


5.8. AdbChimpDevice


  • import com.android.chimpchat.adb.AdbChimpDevice;
  • private AdbChimpDevice mChimpDevice;
  • mChimpDevice = new AdbChimpDevice(mDevice);
  • mBuildDevice = mChimpDevice.getProperty("build.device");
  • mChimpDevice.getManager().touchUp(real.x, real.y);
  • mChimpDevice.getManager().press("KEYCODE_DPAD_CENTER");
  • mChimpDevice.getManager().touchDown(real.x, real.y);
  • mChimpDevice.getManager().touchMove(real.x, real.y);
  • mChimpDevice.getManager().press("KEYCODE_DEL");

  • adb init
  • adb bridge
  • adb getdevice
  • chimpchat init?
  • adb ¸¦ ÅëÇØ device ¸¦ get ÇÑ ÈÄ, ÀÌ µð¹ÙÀ̽º¿¡ ´ëÇØ chimpdevice Ŭ·¡½º¸¦ ¸¸µç´Ù.

    AndroidDebugBridge.addDebugBridgeChangeListener(this);
    AndroidDebugBridge.addDeviceChangeListener(this);
    AndroidDebugBridge.addClientChangeListener(this);

  • grep Chimp /src/com/adakoda/android/asm/*
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.
  • ¾Èµå·ÎÀÌµå µð¹ÙÀ̽º¿¡ ÀÔ·ÂÀ» adb shell À» ÀÌ¿ëÇÏ¿© Çϸé, ¸¹Àº ´Ü°è¸¦ °ÅÄ£´Ù.
  • chimpchat Àº ÀԷ¸¸À» À§ÇÑ µµ±¸ÀÌ´Ù.?
  • monkeyrunner ´Â python¿¡ Ưȭ?

  • Monkeyrunner
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.

  • MonkeyRunnerBackend.java
 Interface between MonkeyRunner common code and the MonkeyRunner backend.  The backend is responsible for communicating between the host and the device.

  • adb ¸¦ »ç¿ëÇÒ °æ¿ì ÀÔÃâ·ÂÀº adb shell À» »ç¿ëÇØ¾ß ÇÑ´Ù?

5.10. ÀÚÀ¯°Ô½ÃÆÇ¿¡ ¿Ã¸± ±Û Á¤¸®


»îÀÇ ¿©À¯°¡ »ý°Ü ¸®´ª½º¸¦ ´Ù½Ã º¸°í ÀÖÀ¾´Ï´Ù. ³Ê¹« »ý¼ÒÇÑ ´Ü¾îµéÀÌ ¸¹±º¿ä.
µ¥½ºÅ©Å¾ ¸®´ª½º°¡ ¾î¶² »óȲÀÎÁö¸¦ º¸´Ï, »ý°¢º¸´Ù ³Ê¹« ÀúÁ¶ÇØ º¸ÀÔ´Ï´Ù.
¹Ý¸é smartphone ÀÇ ¾àÁøÀÌ ´«¿¡ ¶ç´Â±º¿ä.
ÀϹÝÀο¡°Ô µ¥½ºÅ©Å¾Àº Á¡Á¡ »ç¿ëÀÇ Çʿ伺ÀÌ ¾ø¾îÁú °Í °°¾Æ º¸ÀÔ´Ï´Ù.
Àüö¿¡¼­, ¹ö½º¿¡¼­, ±æ°Å¸®¿¡¼­ ¸ðµç »ç¶÷ÀÌ smartphone À» µé¿©´Ù º¸°í ÀÖÀ¾´Ï´Ù.

¸®´ª½º µ¥½ºÆ®Å¾À» smartphone ÀÇ º¸Á¶ÀåÄ¡·Î »ç¿ëÇÏ´Â °ÍÀº ¾î¶³±î?
»çÁøµéÀÇ ÀúÀå
Å« È­¸é¿¡¼­ °ÔÀÓ, ¹Ìµð¾î Ç÷¹ÀÌ
°³ÀÎÀÎÁõÀÌ ÇÊ¿äÇÑ ¾îÇÃ
  • º¸Á¶ ÀúÀåÀåÄ¡
  • Å« È­¸é
  • smartphone ÀÇ °³ÀÎÀÎÁõ(Çѱ¹È¯°æ)

  • ¿¬°á
    • USB
    • wifi
  • ÀÔ·Â
    • µ¥½ºÅ©Å¾¿¡¼­ smartphone control
    • smartphone app ¿¡ ÀÔ·Â
  • µ¥½ºÅ©Å¾ ½ºÅ©¸°¿¡ Ãâ·Â
    • ³·Àº fps
    • ³ôÀº fps
    • Å×½ºÅ©Å¾ ½ºÅ©¸°¿¡ smartphone È­¸é Å©±â ¼³Á¤ ¹× Á¶Á¤

  • µð¹ÙÀ̽º emulator
  • emulator ¿¬°á, µð¹ÙÀ̽º ¿¬°á: usb, wifi
  • touch screen, ÀϹݽºÅ©¸°

  • adb reload
  • device reload
  • device select

  • sync: ÆÄÀÏ
    • Àüü
    • ÀϺÎ
    • sync °ü·Ã ÂüÁ¶
  • sync ¸ÞÀÏ, Ä«Åå
  • ÀüÈ­°ü·Ã
  • ¸ÞÀÏ°ü·Ã
  • sns °ü·Ã
  • Backup ÀÇ °³³ä

7. Design


  • ÇÁ·Î±×·¥ ½ÇÇà ¿É¼Ç
    • emulator ¿¬°á
    • device ¿¬°á
      • usb ·Î ¿¬°á
      • wifi ·Î ¿¬°á
    • Çϳª¸¸ ¿¬°á, ¿©·¯°³ ¿¬°á

  • adb ½ÇÇàÆÄÀÏÀÌ Àִ°¡?

  • device °¡ connected µÇ¾úÀ»¶§ ¾î¶² ÀÛ¾÷µéÀ» ÇØ¾ß Çϴ°¡?
    • ÀÌ¹Ì ¿¬°áµÈ device °¡ Àִ°¡?
    • device ¸¦ º¯°æÇÒ °ÍÀΰ¡?

    • 1°³¸¸ ¿¬°áÇÒ ¼ö ÀÖµµ·Ï Çϸé, ÇöÀç device ¸¦ disconnect ÇÑ ÈÄ »õ·Î¿î device ¿¬°áÇϵµ·Ï message
    • usb ÀÎ °æ¿ì´Â °¡´ÉÇÏÁö¸¸, emulator À̳ª wifi ÀÎ °æ¿ì´Â?
    • emulator ³ª wifi ´Â ³ªÁß¿¡ »ý°¢ÇÏ°í, ÇöÀç´Â device ¸¦ usb ·Î ¿¬°áÇÏ´Â °Í¿¡¸¸ ÁýÁßÇÏÀÚ.

    • 1°³ÀÇ ±â±â¸¸ ¿¬°áÇÑ´Ù.
    • usb ·Î ¿¬°áÇÑ´Ù.
  • connected ¿¡¼­ ÇÒ ÀÏ
    • ù ¹ø° µð¹ÙÀ̽ºÀÎ °æ¿ì
      • µð¹ÙÀ̽º ¿¬°á ¸Þ½ÃÁö
    • ÀÌÈÄÀÇ µð¹ÙÀ̽º
      • µð¹ÙÀ̽º¸¦ º¯°æÇÒ Áö Áú¹®?

  • device control
  • device view control



sponsored by andamiro
sponsored by cdnetworks
sponsored by HP

Valid XHTML 1.0! Valid CSS! powered by MoniWiki
last modified 2016-10-26 11:03:52
Processing time 0.0477 sec