2018年10月8日 星期一

07-迷霧中的MonkeyDevice.drag

對於手機、平板等手持裝置來說,「滑動」這個動作是必不可少的,因此可以模擬滑動效果的 MonkeyDevice.drag (tuple start, tuple end, float duration, integer steps) 是非常重要的功能,但他的參數與實際表現的落差有時卻讓人迷惑。

參數:
start 起始點(手指接觸螢幕時的坐標),形式為 (x, y),x 與 y 的單位為像素。
end 終點(手指離開螢幕時的坐標),形式為 (x, y),x 與 y 的單位為像素。
duration 由手指接觸螢幕到離開螢幕所經過的時間,單位為秒,預設值為 1.0 秒。
steps 從起點開始,經過多少步到達終點,預設值為 10 步。
比如若 x 起始為 1,終點為 9,steps 為 4,則 x 的變化量為 (9 - 1) / 4 = 2,即:1、3、5、7、9。

咱們來看看 以 1 秒經過 10 步由 (900, 800) 向左滑到 (400, 800) 時的表現:
# 匯入所需模組
from com.android.monkeyrunner import MonkeyDevice, MonkeyImage, MonkeyRunner

# 連接 Android 裝置
device = MonkeyRunner.waitForConnection()

# 以 1 秒經過 10 步由 (900, 800) 向左滑到 (400, 800)
device.drag((900, 800), (400, 800), 1.0, 10)
咱們可以看到螢幕確實花費約 1 秒鐘滑動了

若調高 steps 參數是否能讓滑動更平順呢,咱們將 steps 設為 500 看看其表現:
# 匯入所需模組
from com.android.monkeyrunner import MonkeyDevice, MonkeyImage, MonkeyRunner

# 連接 Android 裝置
device = MonkeyRunner.waitForConnection()

# 以 1 秒經過 500 步由 (900, 800) 向左滑到 (400, 800)
device.drag((900, 800), (400, 800), 1.0, 500)
咦?怎麼這次滑動花了約 3 秒才完成?duration 參數不是要求 1 秒嗎?

咱們再來看個例子,今天看官想慢慢滑好了,咱們將 duration 調為 3 秒
# 匯入所需模組
from com.android.monkeyrunner import MonkeyDevice, MonkeyImage, MonkeyRunner

# 連接 Android 裝置
device = MonkeyRunner.waitForConnection()

# 以 3 秒經過 10 步由 (900, 800) 向左滑到 (400, 800)
device.drag((900, 800), (400, 800), 3.0, 10)
ㄟ~怎麼現在變成長按後再滑動的狀態了?!

要理解其行為,咱們還是直接看看 MonkeyDevice.drag() 的實作吧!AdbChimpDevice.java
public void drag(int startx, int starty, int endx, int endy, int steps, long ms) {
    final long iterationTime = ms / steps;
    LinearInterpolator lerp = new LinearInterpolator(steps);
    LinearInterpolator.Point start = new LinearInterpolator.Point(startx, starty);
    LinearInterpolator.Point end = new LinearInterpolator.Point(endx, endy);
    lerp.interpolate(start, end, new LinearInterpolator.Callback() {
        @Override
        public void step(Point point) {
            try {
                manager.touchMove(point.getX(), point.getY());
            } catch (IOException e) {
                LOG.log(Level.SEVERE, "Error sending drag start event", e);
            }
            try {
                Thread.sleep(iterationTime);
            } catch (InterruptedException e) {
                LOG.log(Level.SEVERE, "Error sleeping", e);
            }
        }
        @Override
        public void start(Point point) {
            try {
                manager.touchDown(point.getX(), point.getY());
                manager.touchMove(point.getX(), point.getY());
            } catch (IOException e) {
                LOG.log(Level.SEVERE, "Error sending drag start event", e);
            }
            try {
                Thread.sleep(iterationTime);
            } catch (InterruptedException e) {
                LOG.log(Level.SEVERE, "Error sleeping", e);
            }
        }
        @Override
        public void end(Point point) {
            try {
                manager.touchMove(point.getX(), point.getY());
                manager.touchUp(point.getX(), point.getY());
            } catch (IOException e) {
                LOG.log(Level.SEVERE, "Error sending drag end event", e);
            }
        }
    });
}
  • 首先看第 2 行,不精準地講,iterationTime 便是每次移動手指後會暫停的時間
  • 第 23 和 24 行,是模擬手指一開始按下螢幕的動作(雖然本喵不知道是否一定要執行第 24 行的 manager.touchMove()),按下螢幕後,執行 29 行的暫停
  • 然後第 10 行便是模擬手指的移動,共會執行 steps - 1 次,每執行一次後都會執行第 15 行的暫停
  • 最後是第 37 和 38 行的離開螢幕(一樣,本喵還是不知道第 37 行一定要呼叫嗎)

看了 MonkeyDevice.drag() 的實作之後,看官們是否明白了為何上面例子的表現和想像有些出入了呢?

另外有一點非常重要,那就是:
千萬不要在 MonkeyDevice.drag() 執行時去操作手機,如點擊螢幕,這將可能導致如下 exception:
S [main] [com.android.chimpchat.adb.AdbChimpDevice] Error sending drag start event
S [main] [com.android.chimpchat.adb.AdbChimpDevice]java.net.SocketException: Software caused connection abort: recv failed
S [main] [com.android.chimpchat.adb.AdbChimpDevice] at java.net.SocketInputStream.socketRead0(Native Method)
S [main] [com.android.chimpchat.adb.AdbChimpDevice] at java.net.SocketInputStream.socketRead(Unknown Source)
S [main] [com.android.chimpchat.adb.AdbChimpDevice] at java.net.SocketInputStream.read(Unknown Source)
雖然這和 durationsteps 的設定也有關係,不一定會出現,但在 monkeyrunner 裡,有許多操作都會因外力作用導致 monkeyrunner 溝通不良,所以看官們還是盡量安分點,不要在 monkeyrunner 對底層下指令時也一併操作手機。。

沒有留言:

張貼留言