· 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.IDeviceChangeListenerAndroidDebugBridge.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.0746 sec