从上一章对UiDevice的学习,可以看出几乎所有的操作都离不开 UiAutomationBridge。重新看一下UIDevice的构造方法:
private UiDevice(Instrumentation instrumentation) { mInstrumentation = instrumentation; UiAutomation uiAutomation = instrumentation.getUiAutomation(); mUiAutomationBridge = new InstrumentationUiAutomatorBridge( instrumentation.getContext(), uiAutomation); // Enable multi-window support for API level 21 and up if (UiDevice.API_LEVEL_ACTUAL >= Build.VERSION_CODES.LOLLIPOP) { // Subscribe to window information AccessibilityServiceInfo info = uiAutomation.getServiceInfo(); info.flags |= AccessibilityServiceInfo.FLAG_RETRIEVE_INTERACTIVE_WINDOWS; uiAutomation.setServiceInfo(info); } }
UiAutomationBridge 是一个抽象类。我们先看UiDevice的构造函数中,UiAutomatorBridge的实现类InstrumentationUiAutomatorBridge。这个类比较简单复写了getRotation和isScreenOn方法。接下来我们看一下这个抽象类的构造方法:
UiAutomatorBridge(UiAutomation uiAutomation) { mUiAutomation = uiAutomation; mInteractionController = new InteractionController(this); mQueryController = new QueryController(this); }
在这里初始化了 InteractionController和 QueryController这两个类的对象。在学习UiDevice的时候应该还记得,几乎所有的操作都是通过这两个类来完成的。这里是UiDevice里的pressHome方法:
/** * Simulates a short press on the HOME button. * @return true if successful, else return false * @since API Level 16 */ public boolean pressHome() { Tracer.trace(); waitForIdle(); return getAutomatorBridge().getInteractionController().sendKeyAndWaitForEvent( KeyEvent.KEYCODE_HOME, 0, AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED, KEY_PRESS_EVENT_TIMEOUT); }
通过这个方法可以看到,这个InteractionController可以向系统注入事件。那接下来就来看看这个InteractionController到底是怎么向系统注入事件的。还是从构造方法看起:
public InteractionController(UiAutomatorBridge bridge) { mUiAutomatorBridge = bridge; }
这个InteractionController持有UiAutomatorBridge的引用。并且在这个类中定义了很多模拟用户的操作方法如,sendKeyAndWaitForEvent, touchDown,touchUp,swipe等,例如uiDevcie里用到的sendKeyAndWaitForEvent。
1 /** 2 * Send keys and blocks until the first specified accessibility event. 3 * 4 * Most key presses will cause some UI change to occur. If the device is busy, this will 5 * block until the device begins to process the key press at which point the call returns 6 * and normal wait for idle processing may begin. If no events are detected for the 7 * timeout period specified, the call will return anyway with false. 8 * 9 * @param keyCode 10 * @param metaState 11 * @param eventType 12 * @param timeout 13 * @return true if events is received, otherwise false. 14 */ 15 public boolean sendKeyAndWaitForEvent(final int keyCode, final int metaState, 16 final int eventType, long timeout) { 17 Runnable command = new Runnable() { 18 @Override 19 public void run() { 20 final long eventTime = SystemClock.uptimeMillis(); 21 KeyEvent downEvent = new KeyEvent(eventTime, eventTime, KeyEvent.ACTION_DOWN, 22 keyCode, 0, metaState, KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 0, 23 InputDevice.SOURCE_KEYBOARD); 24 if (injectEventSync(downEvent)) { 25 KeyEvent upEvent = new KeyEvent(eventTime, eventTime, KeyEvent.ACTION_UP, 26 keyCode, 0, metaState, KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 0, 27 InputDevice.SOURCE_KEYBOARD); 28 injectEventSync(upEvent); 29 } 30 } 31 }; 32 return runAndWaitForEvents(command, new WaitForAnyEventPredicate(eventType), timeout) 33 != null; 34 }
Line17,定义一个Runnable对象,Runnable只是一个接口,它里面只有一个run()方法,没有start()方法,所以该对象无法启动线程,必须依托其他类来启动这个线程。
在这个run方法中,定义了一个KeyEvent事件,KeyEnvet对象是android.view.*包下的类,用于报告键和按钮事件。每次按键是通过一系列按键事件来描述的。按键操作以ACTION_DOWN按键事件开始。如果密钥被保持足够长的时间以至于可以重复,则在初始按下后会出现其他具有ACTION_DOWN和getRepeatCount()非零值的密钥事件。最后一个按键事件是用于按键启动的ACTION_UP。如果取消按键,则按键事件将设置FLAG_CANCELED标志。
这个run方法里还有一个if判断条件injectEventSync,通过这个方法名就可以看出这是用来判断同步注入事件是否成功,在injectEventSync方法中,它调用了mUiAutomatorBridge.injectInputEvent(event, true);而mUiAutomatorBridge这个类的injectInputEvent方法里,是调用的mUiAutomation.injectInputEvent(event, sync);而mUiAutomation是Android SDK中 android.app.UiAutomation这个类的对象,我们回过头来看各个函数的构造函数发现,这个UiAutomation来自于UiDevice:
UiAutomation uiAutomation = instrumentation.getUiAutomation();
来看一下这个类中定义的injectInputEvent事件:
/** * A method for injecting an arbitrary input event. ** Note: It is caller's responsibility to recycle the event. *
* @param event The event to inject. * @param sync Whether to inject the event synchronously. * @return Whether event injection succeeded. */ public boolean injectInputEvent(InputEvent event, boolean sync) { synchronized (mLock) { throwIfNotConnectedLocked(); } try { if (DEBUG) { Log.i(LOG_TAG, "Injecting: " + event + " sync: " + sync); } // Calling out without a lock held. return mUiAutomationConnection.injectInputEvent(event, sync); } catch (RemoteException re) { Log.e(LOG_TAG, "Error while injecting input event!", re); } return false; }
看来这里也不是真正做事件注入的地方,mUiAutomationConnection是一个接口对象,这个对象是在UiAutomaton构造函数里初始化的。看他的实现类UiAutomationConnection中的injectInputEvent方法。
@Override public boolean injectInputEvent(InputEvent event, boolean sync) { synchronized (mLock) { throwIfCalledByNotTrustedUidLocked(); throwIfShutdownLocked(); throwIfNotConnectedLocked(); } final int mode = (sync) ? InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH : InputManager.INJECT_INPUT_EVENT_MODE_ASYNC; final long identity = Binder.clearCallingIdentity(); try { return mWindowManager.injectInputAfterTransactionsApplied(event, mode); } catch (RemoteException e) { } finally { Binder.restoreCallingIdentity(identity); } return false; }
private final IWindowManager mWindowManager = IWindowManager.Stub.asInterface( ServiceManager.getService(Service.WINDOW_SERVICE));
package android.os; public final class ServiceManager { public static IBinder getService(String name) { try { IBinder service = sCache.get(name); if (service != null) { return service; } else { return getIServiceManager().getService(name); } } catch (RemoteException e) { Log.e(TAG, "error in getService", e); } return null; } }
从这里可以看出mWindowManager是一个IBinder对象,通过这个对象调用openSession打开一个Session,实现IPC通信。看一下
WindowManagerService里的
injectInputAfterTransactionsApplied方法:
1 @Override 2 public boolean injectInputAfterTransactionsApplied(InputEvent ev, int mode) { 3 boolean isDown; 4 boolean isUp; 5 6 if (ev instanceof KeyEvent) { 7 KeyEvent keyEvent = (KeyEvent) ev; 8 isDown = keyEvent.getAction() == KeyEvent.ACTION_DOWN; 9 isUp = keyEvent.getAction() == KeyEvent.ACTION_UP; 10 } else { 11 MotionEvent motionEvent = (MotionEvent) ev; 12 isDown = motionEvent.getAction() == MotionEvent.ACTION_DOWN; 13 isUp = motionEvent.getAction() == MotionEvent.ACTION_UP; 14 } 15 final boolean isMouseEvent = ev.getSource() == InputDevice.SOURCE_MOUSE; 16 17 // For ACTION_DOWN, syncInputTransactions before injecting input. 18 // For all mouse events, also sync before injecting. 19 // For ACTION_UP, sync after injecting. 20 if (isDown || isMouseEvent) { 21 syncInputTransactions(); 22 } 23 final boolean result = 24 LocalServices.getService(InputManagerInternal.class).injectInputEvent(ev, mode); 25 if (isUp) { 26 syncInputTransactions(); 27 } 28 return result; 29 }
syncInputTransactions()这个方法是同步系统注入事件的事物,对于action up事件是在注入之后同步,其他的事件是在事件注入之前同步。 我们主要看一下事件注入.
LocalServices 的getService方法,返回一个实现了InputManagerInternal类型的Service, InputManagerInternal是一个抽象类,而injectInputEvent也是一个抽象方法。
那接下来我们就看一下这个InputManger类型的service。这是一个系统的服务 SystemService。
1 /** 2 * Injects an input event into the event system on behalf of an application. 3 * The synchronization mode determines whether the method blocks while waiting for 4 * input injection to proceed. 5 *6 * Requires {@link android.Manifest.permission.INJECT_EVENTS} to inject into 7 * windows that are owned by other applications. 8 *
9 * Make sure you correctly set the event time and input source of the event 10 * before calling this method. 11 * 12 * 13 * @param event The event to inject. 14 * @param mode The synchronization mode. One of: 15 * {@link #INJECT_INPUT_EVENT_MODE_ASYNC}, 16 * {@link #INJECT_INPUT_EVENT_MODE_WAIT_FOR_RESULT}, or 17 * {@link #INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH}. 18 * @return True if input event injection succeeded. 19 * 20 * @hide 21 */ 22 @UnsupportedAppUsage 23 public boolean injectInputEvent(InputEvent event, int mode) { 24 if (event == null) { 25 throw new IllegalArgumentException("event must not be null"); 26 } 27 if (mode != INJECT_INPUT_EVENT_MODE_ASYNC 28 && mode != INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH 29 && mode != INJECT_INPUT_EVENT_MODE_WAIT_FOR_RESULT) { 30 throw new IllegalArgumentException("mode is invalid"); 31 } 32 try { 33 return mIm.injectInputEvent(event, mode); 34 } catch (RemoteException ex) { 35 throw ex.rethrowFromSystemServer(); 36 } 37 }
Line33,调用的是IInputManager.aidl里的injectInputEvent,通过进程之间的通信,实现了系统的事件注入。到此事件注入的流程分析完毕,先到此为止。再想深入研究就是Native层的逻辑了。