TV測試中的按鍵長按操作模擬
從UiAutomator在TV測試中的侷限性說起:
智慧TV的操作和手機的操作有很大不同,一般智慧TV的操作為遙控器按鍵操作,來向TV OS傳送 KeyCode,以完成指定操作。
UiAutomator在API中提供了控制元件和長按操作,也提供了點座標的長按操作,但無法設定長按的時間。
UiAutomator在API中也提供了模擬傳送KeyCode的方法,即UiDevice類中的pressKeyCode方法。
但TV遙控器按鍵的長按模擬方法,UiAutomator並沒有直接提供,而電視中的視訊快進等操作需要按 鍵長按,自動化測試有此方面的要求。
一. KeyCode按鍵長按操作通過Adb命令模擬
COMMAND: adb shell input keyevent --longpress 3
雖然可以實現長按操作,但長按只能實現簡單的長按操作,長按時間較短,針對快進等需較長時間長按實現的操作無用。
二. Appium的KeyCode長按模擬
Appium裡面實現了按鍵的長按操作,實現原始碼核心如下:
public AndroidCommandResult execute(final AndroidCommand command) throws JSONException { try { InteractionController interactionController = UiAutomatorBridge.getInstance().getInteractionController(); final Hashtable<String, Object> params = command.params(); keyCode = (Integer) params.get("keycode"); metaState = params.get("metastate") != JSONObject.NULL ? (Integer) params .get("metastate") : 0; final long eventTime = SystemClock.uptimeMillis(); // Send an initial down event final KeyEvent downEvent = new KeyEvent(eventTime, eventTime, KeyEvent.ACTION_DOWN, keyCode, 0, metaState, KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 0, InputDevice.SOURCE_KEYBOARD); if (interactionController.injectEventSync(downEvent)) { // Send a repeat event. This will cause the FLAG_LONG_PRESS to be set. final KeyEvent repeatEvent = KeyEvent.changeTimeRepeat(downEvent, eventTime, 1); interactionController.injectEventSync(repeatEvent); // Finally, send the up event final KeyEvent upEvent = new KeyEvent(eventTime, eventTime, KeyEvent.ACTION_UP, keyCode, 0, metaState, KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 0, InputDevice.SOURCE_KEYBOARD); interactionController.injectEventSync(upEvent); } return getSuccessResult(true); } catch (final Exception e) { return getErrorResult(e.getMessage()); } }
核心主要是:injectEventSync方法,剖析其原始碼發現最終是呼叫了uiautomator JAR包中 com.android.uiautomator.core.InteractionController類的injectEventSync方法
只是在uiautomator JAR包中,上述類型別為default且上述方法private方法
若要呼叫需要使用反射技術
三. 自己實現的時間可控的長按操作模擬原始碼
public void execute(int keycode, int times) { int keyCode = keycode; int timeCount = times; try { // InteractionController interactionController = UiAutomatorBridge.getInstance().getInteractionController(); System.out.println("......ttt...."); UiDevice device = UiDevice.getInstance(); Class UiDevice_class = UiDevice.class; Field field_UiD = UiDevice_class.getDeclaredField("mUiAutomationBridge"); field_UiD.setAccessible(true); Object uiAutomatorBridge = field_UiD.get(device); Class tmp = Class.forName("com.android.uiautomator.core.UiAutomatorBridge"); Field field = tmp.getDeclaredField("mInteractionController"); field.setAccessible(true); Object interactionController = field.get(uiAutomatorBridge); metaState = 0; final long eventTime = SystemClock.uptimeMillis(); // Send an initial down event final KeyEvent downEvent = new KeyEvent(eventTime, eventTime, KeyEvent.ACTION_DOWN, keyCode, 0, metaState, KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 0, InputDevice.SOURCE_KEYBOARD); System.out.println("......lll,...."); if (injectEventSync(downEvent,interactionController)) { // Send a repeat event. This will cause the FLAG_LONG_PRESS to be set. final KeyEvent repeatEvent = KeyEvent.changeTimeRepeat(downEvent, eventTime, 1); for(int i=0; i<timeCount; i++){ injectEventSync(repeatEvent,interactionController); } // Finally, send the up event System.out.println("......lll,...."); final KeyEvent upEvent = new KeyEvent(eventTime, eventTime, KeyEvent.ACTION_UP, keyCode, 0, metaState, KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 0, InputDevice.SOURCE_KEYBOARD); injectEventSync(upEvent,interactionController); } return ; } catch (final Exception e) { return ; } }