从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 ; } }