Android Mirroring
|
Android mirroring 관련 프로그램 분석
1. 환경 ¶
1.1. Technology ¶
The video of the screen is captured from the 1st client (window) and the whole stream is transferred bit by bit to some sort of server ( apache/nginx/node) . This is then transferred to the second client (window) to stream in. For real time streaming one can use a websocket server ( tcp connections ), which is the fastest . Also p2p protocols have been developed eliminating the need for a server ( middle-man ) . These enable real time bidirectional communication !!! . 1.2. Chromecast vs. AirPlay ¶
AirPlay on the Apple TV is a hybrid of the classic set-top box and streaming from your device: when you first power on an Apple TV, you're greeted with a friendly iOS-powered user interface with easy-to-understand menus and navigation, and you can control the entire thing from the bundled traditional remote without ever touching a smartphone. But open up an AirPlay app on your iOS device, and it's just two taps to wipe all that away and stream video directly from your iPhone or iPad, with all the playback controls remaining on your touchscreen. It's the best of both worlds: a fully-functional set top box and a complete local streaming solution.
Chromecast is focused entirely on the streaming side of the equation. There's no UI or remote outside of your device; everything is handled by the applications that tap into Google's streaming technology and tell the Chromecast what to do. That part of the UI is a lot like AirPlay: you hit a button in an app like Netflix or Pandora that supports Chromecast, and you're streaming away.
2. 관련 소프트웨어 ¶
3. adbcontrol ¶
3.1. AdbControl.java ¶
public void screenshot(File target)
{
String fileName = config.getPhoneImageFilePath();
executeShellCommand(MessageFormat.format("screencap -p {0}", fileName), new ByteArrayOutputStream());
executeCommand(MessageFormat.format("pull {0} {1}", fileName, target.getAbsolutePath()), new ByteArrayOutputStream());
}
adb shell screencap -p /sdcard/screen.png adb pull /sdcard/screen.png adb shell rm /sdcard/screen.png
private void loadImage(File file)
{
try
{
image = ImageIO.read(file);
}
catch(IOException ex)
{
ex.printStackTrace();
return;
}
repaint();
}
3.2. 화면에 출력 ¶
AdbControl frame = new AdbControl(configFile);
frame.setVisible(true);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setTitle("ADB Control");
setSize(720 / 2, 1080 / 2);
AdbControlPanel panel = new AdbControlPanel(config);
panel.setAdbHelper(new AdbHelper(config));
getContentPane().add(panel, BorderLayout.CENTER);
private void makeScreenshot()
{
adbHelper.screenshot(imageFile);
loadImage(imageFile);
}
private void loadImage(File file)
{
try
{
image = ImageIO.read(file);
}
catch(IOException ex)
{
ex.printStackTrace();
return;
}
repaint();
}
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
if(image != null)
{
screenWidth = image.getWidth();
screenHeight = image.getHeight();
int width = getWidth();
int height = getHeight();
double ratioX = (double) width / (double) screenWidth;
double ratioY = (double) height / (double) screenHeight;
ratio = Math.min(1, Math.min(ratioX, ratioY));
double scaledWidth = (double) screenWidth * ratio;
double scaledHeight = (double) screenHeight * ratio;
g.drawImage(image, 0, 0, (int) scaledWidth, (int) scaledHeight, null);
}
}
3.3. thread ¶
while(!Thread.interrupted())
{
makeScreenshot();
try
{
Thread.sleep(config.getScreenshotDelay());
}
catch(InterruptedException ex)
{
break;
}
}
If this method were to be called twice in succession, the second call would return false (unless the current thread were interrupted again, after the first call had cleared its interrupted status and before the second call had examined it).
3.4. misc ¶
3.5. ant ¶tcheun@tcheun-system:~/download/adbcontrol$ ls build build.xml config.properties epl-v10.html src
<project name="adbcontrol" basedir="." default="main">
<property name="src.dir" value="src"/>
<property name="build.dir" value="build"/>
<property name="classes.dir" value="${build.dir}/classes"/>
<property name="jar.dir" value="${build.dir}/jar"/>
<property name="main-class" value="name.schedenig.adbcontrol.AdbControl"/>
<target name="clean">
4. droidAtScreen ¶
4.1. DroidAtScreenApplication.java ¶import com.ribomation.droidAtScreen.cmd.AdbExePathCommand;^M import com.ribomation.droidAtScreen.cmd.Command;^M import com.ribomation.droidAtScreen.dev.AndroidDevice;^M import com.ribomation.droidAtScreen.dev.AndroidDeviceListener;^M import com.ribomation.droidAtScreen.dev.AndroidDeviceManager;^M import com.ribomation.droidAtScreen.gui.ApplicationFrame;^M import com.ribomation.droidAtScreen.gui.DeviceFrame;^M import com.ribomation.droidAtScreen.gui.DeviceTableModel;^M public class DroidAtScreenApplication implements Application, AndroidDeviceListener
public static void main(String[] args) {^M
DroidAtScreenApplication app = new DroidAtScreenApplication();^M
app.parseArgs(args);^M
app.initProperties();^M
app.initCommands();^M
app.initGUI();^M
app.initAndroid();^M
app.run();^M
app.postStart();^M
}^M
@Override^M
public ApplicationFrame getAppFrame() {^M
return appFrame;^M
}^M
2016-09-01 19:32:08,483 INFO AndroidDeviceManager - ADB changed 2016-09-01 19:32:08,484 INFO AndroidDeviceManager - Connected to ADB via /127.0.0.1:5037
public void connected(final AndroidDevice dev) {^M
log.debug("connected: dev=" + dev);^M
^M
SwingUtilities.invokeLater(new Runnable() {^M
@Override^M
public void run() {^M
getAppFrame().getStatusBar().message("Connected to " + dev.getName());^M
^M
DeviceFrame frame = new DeviceFrame(DroidAtScreenApplication.this, dev);^M
deviceTableModel.add(frame);^M
fireDeviceConnected(dev);^M
^M
frame.setVisible(!getSettings().isHideEmulators() || !dev.isEmulator());^M
^M
updateDeviceFramePositionsOnScreen(frame);^M
}^M
});^M
}^M
2016-09-08 12:52:35,078 INFO AndroidDeviceManager - Device connected: 5d027563 2016-09-08 12:52:35,079 DEBUG DroidAtScreenApplication - connected: dev=5d027563 (device) 2016-09-08 12:52:35,100 DEBUG DeviceFrame:5d027563 - DeviceFrame(device=5d027563 (device)) 2016-09-08 12:52:35,172 DEBUG DeviceFrame:5d027563 - getPreferredSize: screen=java.awt.Dimension[width=1855,height=1056], canvas=java.awt.Dimension[width=200,height=300], frame=java.awt.Dimension[width=251,height=348] 2016-09-08 12:52:35,172 DEBUG DeviceFrame:5d027563 - getPreferredSize: frame2=java.awt.Dimension[width=210,height=330] 2016-09-08 12:52:35,174 DEBUG DroidAtScreenApplication - devices size: count=1 2016-09-08 12:52:35,335 DEBUG AndroidDeviceManager - Device changed: 5d027563, mask=CHANGE_BUILD_INFO 2016-09-08 12:52:44,998 DEBUG DeviceFrame:5d027563 - Got screenshot RawImage[1080x1920, 8294400 bytes, bits/px=32], elapsed 9871 ms 2016-09-08 12:52:44,999 DEBUG DeviceFrame:5d027563 - Image width 1080, Image hight 1920 ms 2016-09-08 12:52:45,235 DEBUG DeviceFrame:SHV-E330K - getPreferredSize: screen=java.awt.Dimension[width=1855,height=1056], canvas=java.awt.Dimension[width=1080,height=1920], frame=java.awt.Dimension[width=1121,height=1938] 2016-09-08 12:52:45,235 DEBUG DeviceFrame:SHV-E330K - getPreferredSize: frame2=java.awt.Dimension[width=1121,height=950] 2016-09-08 12:52:45,238 DEBUG DroidAtScreenApplication - devices size: count=1
public class DeviceFrame extends JFrame implements Comparable<DeviceFrame> {^M
private final static RenderingHints HINTS = new RenderingHints(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);^
tcheun@tcheun-system:~/my-app/target$ java -jar droidAtScreen-1.2.jar 2016-09-01 19:32:02,732 DEBUG DroidAtScreenApplication - parseArgs: [] 2016-09-01 19:32:02,733 DEBUG DroidAtScreenApplication - initProperties 2016-09-01 19:32:02,806 DEBUG Settings - --- Application Settings --- 2016-09-01 19:32:03,133 DEBUG Settings - adbExecutable: /home/tcheun/Android/Sdk/platform-tools/adb 2016-09-01 19:32:03,133 DEBUG DroidAtScreenApplication - initCommands 2016-09-01 19:32:03,166 DEBUG DroidAtScreenApplication - initGUI 2016-09-01 19:32:04,617 DEBUG DroidAtScreenApplication - initAndroid 2016-09-01 19:32:04,722 DEBUG DroidAtScreenApplication - run 2016-09-01 19:32:04,737 DEBUG DroidAtScreenApplication - postStart 2016-09-01 19:32:08,483 INFO AndroidDeviceManager - ADB changed 2016-09-01 19:32:08,484 INFO AndroidDeviceManager - Connected to ADB via /127.0.0.1:5037 1. Initialize the adb interface and get a handle to the bridge:
private void initAndroid() {^M
log.debug("initAndroid");^M
deviceManager = new AndroidDeviceManager(this);^M
deviceManager.initManager();^M
timer = new Timer("Screenshot Retrievers");^M
}^M
public void initManager() {^M
AndroidDebugBridge.init(false);^M
Runtime.getRuntime().addShutdownHook(this);^M
AndroidDebugBridge.addDebugBridgeChangeListener(this);^M
AndroidDebugBridge.addDeviceChangeListener(this);^M
}^M
private void postStart() {^M
log.debug("postStart");^M
^M
File adbExePath = getSettings().getAdbExecutable();^M
if (adbExePath == null) {^M
adbExePath = isExe("ANDROID_HOME");^M
log.debug("postStart: adbExePath=" + adbExePath);
}^M
if (adbExePath == null) {^M
adbExePath = isExe("ANDROID_SDK_HOME");^M
}^M
if (adbExePath == null) {^M
Command.find(AdbExePathCommand.class).execute();^M
} else {^M
getSettings().setAdbExecutable(adbExePath);^M
getDeviceManager().setAdbExecutable(adbExePath);^M
getDeviceManager().createBridge();^M
}^M
}^M
public void createBridge() {^M
if (getAdbExecutable() == null) {^M
throw new IllegalArgumentException("Need to set the ADB exe path first, before starting the bridge.");^M
}^M
^M
try {^M
AndroidDebugBridge.createBridge(getAdbExecutable().getCanonicalPath(), true);^M
log.info("Connected to ADB via " + getSocketAddress());^M
} catch (IOException e) {^M
throw new RuntimeException("Failed to created the absolute path to the ADB executable: " + getAdbExecutable());^M
}^M
}^M
2. Set up a listener (an implementation of the IDeviceChangeListener interface) for device changes and add it:
public interface AndroidDeviceListener {^M
^M
/**^M
* Invoked when a new device is detected.^M
* ^M
* @param dev^M
* the new device^M
*/^M
void connected(AndroidDevice dev);^M
^M
/**^M
* Invoked when a device goes offline.^M
* ^M
* @param dev^M
* the defunct device^M
*/^M
void disconnected(AndroidDevice dev);^M
}^M
public void connected(final AndroidDevice dev) {^M
log.debug("connected: dev=" + dev);^M
^M
SwingUtilities.invokeLater(new Runnable() {^M
@Override^M
public void run() {^M
getAppFrame().getStatusBar().message("Connected to " + dev.getName());^M
^M
DeviceFrame frame = new DeviceFrame(DroidAtScreenApplication.this, dev);^M
deviceTableModel.add(frame);^M
fireDeviceConnected(dev);^M
^M
frame.setVisible(!getSettings().isHideEmulators() || !dev.isEmulator());^M
^M
updateDeviceFramePositionsOnScreen(frame);^M
}^M
});^M
}^M
4.2. Application.java ¶import com.ribomation.droidAtScreen.dev.AndroidDevice;^M import com.ribomation.droidAtScreen.dev.AndroidDeviceListener;^M import com.ribomation.droidAtScreen.dev.AndroidDeviceManager;^M import com.ribomation.droidAtScreen.gui.ApplicationFrame;^M import com.ribomation.droidAtScreen.gui.DeviceFrame;^M import com.ribomation.droidAtScreen.gui.DeviceTableModel;^M
4.3. Settings.java ¶
ApplicationFrame.java: setTitle(app.getInfo().getName() + ", Version " + app.getInfo().getVersion());
StatusBar.java: message(app.getInfo().getName() + ", V" + app.getInfo().getVersion());
AboutCommand.java: Info info = app.getInfo();
HelpCommand.java: return new URI(app.getInfo().getHelpUri());
HomeCommand.java: return new URI(app.getInfo().getAppUri());
MailCommand.java: return new URI(app.getInfo().getMailUri());
ScreenshotCommand.java: return new File(cfg.getImageDirectory(), String.format("%s-%d.%s", app.getInfo().getName().toLowerCase(), cfg.nextInt(), cfg.getImageFormat().toLowerCase()));
RemovePropertiesCommand.java: app.getSettings().destroyPreferences(); 4.4. gui/ApplicationFrame.java ¶
public static ImageIcon loadIcon(String name) {^M
return loadImage(name, "png");^M
}^M
1.클래스를 설계할 때, 멤버변수 중 모든 인스턴스에 공통적으로 사용해야하는 것에 static을 붙인다.
- 인스턴스를 생성하면, 각 인스턴스들은 서로 독립적이기 때문에 서로 다른 값을 유지한다.
경우에 따라서는 각 인스턴스들이 공통적으로 같은 값이 유지되어야 하는 경우 static을 붙인다.
2. static이 붙은 멤버변수는 인스턴스를 생성하지 않아도 사용할 수 있다.
- static이 붙은 멤버변수(클래스변수)는 클래스가 메모리에 올라갈때 이미 자동적으로 생성되기 때문이다.
3. static이 붙은 메서드(함수)에서는 인스턴스 변수를 사용할 수 없다.
- static이 붙은 메서드는 인스턴스 생성 없이 호출가능한 반면, 인스턴스 변수는 인스턴스를 생성해야만 존재하기 때문에... static이 붙은 메서드(클래스메서드)를 호출할 때 인스턴스가 생성되어있을수도 그렇지 않을 수도 있어서 static이 붙은 메서드에서 인스턴스변수의 사용을 허용하지 않는다.
(반대로, 인스턴스변수나 인스턴스메서드에서는 static이 붙은 멤버들을 사용하는 것이 언제나 가능하다. 인스턴스변수가 존재한다는 것은 static이 붙은 변수가 이미 메모리에 존재한다는 것을 의미하기 때문이다.)
4. 메서드 내에서 인스턴스 변수를 사용하지 않는다면, static을 붙이는 것을 고려한다.
- 메서드의 작업내용중에서 인스턴스 변수를 필요로 한다면, static을 붙일 수 없다. 반대로 인스턴스변수를 필요로 하지 않는다면, 가능하면 static을 붙이는 것이 좋다. 메서드 호출시간이 짧아지기 때문에 효율이 높아진다.
(static을 안붙인 메서드는 실행시 호출되어야할 메서드를 찾는 과정이 추가적으로 필요하기 때문에 시간이 더 걸린다.)
5. 클래스 설계시 static의 사용지침
- 먼저 클래스의 멤버변수중 모든 인스턴스에 공통된 값을 유지해야하는 것이 있는지 살펴보고 있으면, static을 붙여준다.
- 작성한 메서드 중에서 인스턴스 변수를 사용하지 않는 메서드에 대해서 static을 붙일 것을 고려한다.
일반적으로 인스턴스변수와 관련된 작업을 하는 메서드는 인스턴스메서드(static이 안붙은 메서드)이고 static변수(클래스변수)와 관련된 작업을 하는 메서드는 클래스메서드(static이 붙은 메서드)라고 보면 된다.
4.5. DeviceFrame.java ¶
app.name=Droid@Screen^M app.version=1.2^M build.date=2016-09-04^M app.uri=http://droid-at-screen.ribomation.com/^M help.uri=http://droid-at-screen.ribomation.com/user-assisted-support/^M mail.uri=mailto:jens.riboe@ribomation.se&subject=Droid@Screen%20Feedback^M
public void connected(final AndroidDevice dev) {^M
log.debug("connected: dev=" + dev);^M
^M
SwingUtilities.invokeLater(new Runnable() {^M
@Override^M
public void run() {^M
getAppFrame().getStatusBar().message("Connected to " + dev.getName());^M
^M
DeviceFrame frame = new DeviceFrame(DroidAtScreenApplication.this, dev);^M
deviceTableModel.add(frame);^M
fireDeviceConnected(dev);^M
^M
frame.setVisible(!getSettings().isHideEmulators() || !dev.isEmulator());^M
^M
updateDeviceFramePositionsOnScreen(frame);^M
}^M
});^M
}^M
public class DeviceFrame extends JFrame implements Comparable<DeviceFrame> {^M
private final static RenderingHints HINTS = new RenderingHints(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
4.6. AndroidDevice.java ¶
public String getName() {^M
String name = isEmulator() ? target.getAvdName() : target.getProperty("ro.product.model");^M
return name != null ? name : target.getSerialNumber();^M
}^M
^M
public Map<String, String> getProperties() {^M
return target.getProperties();^M
}^M
4.7. screenimage ¶
public ScreenImage(RawImage rawImage) {^M
this.rawImage = rawImage;^M
}^M
4.8. 입력 ¶
public void tap(Point p) {^M
try {^M
String cmd = String.format(Locale.ENGLISH, "input tap %.3f %.3f", p.getX(), p.getY());^M
log.debug("SEND: "+cmd);^M
target.executeShellCommand(cmd, new IShellOutputReceiver() {^M
@Override^M
public void addOutput(byte[] data, int offset, int length) {^M
log.debug(String.format("SHELL: %s", new String(data, offset, length)));^M
}^M
^M
@Override^M
public void flush() { }^M
^M
@Override^M
public boolean isCancelled() { return false; }^M
});^M
} catch (Exception e) {^M
log.debug("Failed to send 'input tap' command to the device", e);^M
}^M
}^M
canvas.addMouseListener(new MouseAdapter() {^M
@Override^M
public void mouseClicked(MouseEvent e) {^M
Point p = e.getPoint();^M
log.debug(String.format("mouse: %s", p));^M
p = new Point(^M
(int) (p.getX() * 100) / getScale(),^M
(int) (p.getY() * 100) / getScale()^M
);^M
log.debug(String.format("scaled: %s", p));^M
device.tap(p);^M
}^M
});^M
5.2. 3.0 ¶
public void initialize() {^M
mMainFrame = new MainFrame(mArgs);^M
mMainFrame.setLocationRelativeTo(null);^M
mMainFrame.setVisible(true);^M
mMainFrame.selectDevice();^M
}^M
5.3. MainFrame.java ¶
parseArgs(args);^M
^M
initializePrefs();
version, portrait, zoom FbType 을 저장하고, prefVer, mPortrait, mZoom, mFbType 를 설정한다.
initializeFrame(); setTitle("Android Screen Monitor"); 왜 동작을 안 했을까?
initializePanel();
initializeMenu(); 아 역시 동작을 안 한 것 같다.
initializeActionMap();^M
^M
addMouseListener(mMouseListener);^M
addWindowListener(mWindowListener);^M
addMouseMotionListener(mMouseMotionListener);^M
addKeyListener(mKeyListener);^M
^M
pack();^M
setImage(null); 윈도우 디스플레이(왜 타이들이 없지?)
adb path is /home/tcheun/Android/Sdk/platform-tools/adb
9월 20, 2016 4:48:23 오전 com.android.chimpchat.ChimpManager sendMonkeyEventAndGetResponse
정보: Monkey Command: wake.
9월 20, 2016 4:48:42 오전 com.android.chimpchat.ChimpManager sendMonkeyEventAndGetResponse
정보: Monkey Command: getvar build.device.
com.android.ddmlib.AdbCommandRejectedException: device '5d027563' not found
at com.android.ddmlib.AdbHelper.setDevice(AdbHelper.java:774)
at com.android.ddmlib.AdbHelper.getFrameBuffer(AdbHelper.java:286)
at com.android.ddmlib.Device.getScreenshot(Device.java:428)
at com.adakoda.android.asm.MainFrame$MonitorThread.getDeviceImage(Unknown Source)
public void startMonitor() {^M
mMonitorThread = new MonitorThread();^M
mMonitorThread.start();^M
}^M
5.4. setImage ¶
package com.adakoda.android.asm;^M
^M
import javax.swing.SwingUtilities;^M
^M
public class AndroidScreenMonitor {^M
^M
private MainFrame mMainFrame;^M
private static String[] mArgs;^M
^M
public AndroidScreenMonitor() {^M
}^M
^M
public void initialize() {^M
mMainFrame = new MainFrame(mArgs);^M
mMainFrame.setLocationRelativeTo(null);^M
mMainFrame.setVisible(true);^M
mMainFrame.setFocusable(true);^M
mMainFrame.selectDevice();^M
}^M
^M
public static void main(String[] args) {^M
mArgs = args;^M
SwingUtilities.invokeLater(new Runnable() {^M
public void run() {^M
new AndroidScreenMonitor().initialize();^M
}^M
});^M
}^M
}^M
5.5. Thread ¶
public void run() {^M
Thread thread = Thread.currentThread();^M
if (mDevice != null) {^M
try {^M
while (mMonitorThread == thread) {^M
final FBImage fbImage = getDeviceImage();^M
SwingUtilities.invokeLater(new Runnable() {^M
public void run() {^M
setImage(fbImage);^M
}^M
});^M
}^M
} catch (IOException e) {^M
}^M
}^M
}^M
5.6. point ¶
public void initialize() {^M
mMainFrame = new MainFrame(mArgs);^M
mMainFrame.setLocationRelativeTo(null);^M
mMainFrame.setVisible(true);^M
mMainFrame.setFocusable(true);^M
mMainFrame.selectDevice();^M
}^M
private void initialize(String[] args) {^M
mADB = new ADB();^M
if (!mADB.initialize(args)) {^M
JOptionPane.showMessageDialog(this,^M
"Could not find adb, please install Android SDK and set path to adb.",^M
"Error", JOptionPane.ERROR_MESSAGE);^M
}^M
^M
parseArgs(args);^M
^M
initializePrefs();^M
initializeFrame();^M
initializePanel();^M
initializeMenu();^M
initializeActionMap();^M
^M
addMouseListener(mMouseListener);^M
addWindowListener(mWindowListener);^M
addMouseMotionListener(mMouseMotionListener);^M
addKeyListener(mKeyListener);^M
^M
pack();^M
setImage(null);^M
}^M
private void initializeFrame() {^M
setTitle("Android Screen Monitor");^M
setIconImage(Toolkit.getDefaultToolkit().getImage(^M
getClass().getResource("icon.png")));^M
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);^M
setResizable(false);^M
}^M
private void initializePanel() {^M
mPanel = new MainPanel();^M
add(mPanel);^M
}^M
public void run() {^M
Thread thread = Thread.currentThread();^M
if (mDevice != null) {^M
try {^M
while (mMonitorThread == thread) {^M
final FBImage fbImage = getDeviceImage();^M
SwingUtilities.invokeLater(new Runnable() {^M
public void run() {^M
setImage(fbImage);^M
}^M
});^M
}^M
} catch (IOException e) {^M
}^M
}^M
}^M
5.7. Painting ¶
5.8. AdbChimpDevice ¶
AndroidDebugBridge.addDebugBridgeChangeListener(this);
AndroidDebugBridge.addDeviceChangeListener(this);
AndroidDebugBridge.addClientChangeListener(this);
MainFrame.java:import com.android.chimpchat.adb.AdbChimpDevice;
MainFrame.java: private AdbChimpDevice mChimpDevice;
MainFrame.java: mChimpDevice = new AdbChimpDevice(mDevice);
MainFrame.java: mBuildDevice = mChimpDevice.getProperty("build.device");
MainFrame.java: mChimpDevice.getManager().touchUp(real.x, real.y);
MainFrame.java: mChimpDevice.getManager().press("KEYCODE_DPAD_CENTER");
MainFrame.java: mChimpDevice.getManager().touchDown(real.x, real.y);
MainFrame.java: if (mChimpDevice != null) {
MainFrame.java: mChimpDevice.dispose();
MainFrame.java: mChimpDevice.getManager().touchMove(real.x, real.y);
MainFrame.java: mChimpDevice.getManager().press("KEYCODE_DEL");
MainFrame.java: mChimpDevice.getManager().press("KEYCODE_DPAD_CENTER");
MainFrame.java: mChimpDevice.getManager().press("KEYCODE_SPACE");
MainFrame.java: mChimpDevice.getManager().press("KEYCODE_HOME");
MainFrame.java: mChimpDevice.getManager().press("KEYCODE_DPAD_LEFT");
MainFrame.java: mChimpDevice.getManager().press("KEYCODE_DPAD_RIGHT");
MainFrame.java: mChimpDevice.getManager().press("KEYCODE_DPAD_UP");
MainFrame.java: mChimpDevice.getManager().press("KEYCODE_DPAD_DOWN");
MainFrame.java: mChimpDevice.getManager().type(c);
5.9. chimpchat ¶The latest version of the Android SDK and tools include chimpchat, a library that facilitates the use of monkey from Java. This is equivalent to monkeyrunner, which is the bridge between monkey and the Python scripting language. While Python is an incredibly powerful and expressive scripting language and will permit you creating tests with just a few statements, there are some occasions when you don't want to introduce a new language to the project leaving your Java confort zone or you prefer to leverage the use of previously created libraries instead of writing new ones. In such cases, you can now have the same access to monkey running on the device with the help of chimpchat, as we are going to demonstrate.
The monkeyrunner tool provides an API for writing programs that control an Android device or emulator from outside of Android code. With monkeyrunner, you can write a Python program that installs an Android application or test package, runs it, sends keystrokes to it, takes screenshots of its user interface, and stores screenshots on the workstation. The monkeyrunner tool is primarily designed to test applications and devices at the functional/framework level and for running unit test suites, but you are free to use it for other purposes. The monkeyrunner tool is not related to the UI/Application Exerciser Monkey, also known as the monkey tool. The monkey tool runs in an adb shell directly on the device or emulator and generates pseudo-random streams of user and system events. In comparison, the monkeyrunner tool controls devices and emulators from a workstation by sending specific commands and events from an API.
Interface between MonkeyRunner common code and the MonkeyRunner backend. The backend is responsible for communicating between the host and the device.
5.10. 자유게시판에 올릴 글 정리 ¶삶의 여유가 생겨 리눅스를 다시 보고 있읍니다. 너무 생소한 단어들이 많군요. 데스크탑 리눅스가 어떤 상황인지를 보니, 생각보다 너무 저조해 보입니다. 반면 smartphone 의 약진이 눈에 띄는군요. 일반인에게 데스크탑은 점점 사용의 필요성이 없어질 것 같아 보입니다. 전철에서, 버스에서, 길거리에서 모든 사람이 smartphone 을 들여다 보고 있읍니다. 리눅스 데스트탑을 smartphone 의 보조장치로 사용하는 것은 어떨까? 사진들의 저장 큰 화면에서 게임, 미디어 플레이 개인인증이 필요한 어플
7. Design ¶
|










