publicvoidconnect(IAccessibilityServiceClient client) { if (client == null) { thrownewIllegalArgumentException("Client cannot be null!"); } synchronized (mLock) { throwIfShutdownLocked(); if (isConnectedLocked()) { thrownewIllegalStateException("Already connected."); } mOwningUid = Binder.getCallingUid(); registerUiTestAutomationServiceLocked(client); storeRotationStateLocked(); } }
privatevoidregisterUiTestAutomationServiceLocked(IAccessibilityServiceClient client) { IAccessibilityManagermanager= IAccessibilityManager.Stub.asInterface( ServiceManager.getService(Context.ACCESSIBILITY_SERVICE)); AccessibilityServiceInfoinfo=newAccessibilityServiceInfo(); info.eventTypes = AccessibilityEvent.TYPES_ALL_MASK; info.feedbackType = AccessibilityServiceInfo.FEEDBACK_GENERIC; info.flags |= AccessibilityServiceInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS | AccessibilityServiceInfo.FLAG_REPORT_VIEW_IDS; info.setCapabilities(AccessibilityServiceInfo.CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT | AccessibilityServiceInfo.CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION | AccessibilityServiceInfo.CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY | AccessibilityServiceInfo.CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS); try { // Calling out with a lock held is fine since if the system // process is gone the client calling in will be killed. manager.registerUiTestAutomationService(mToken, client, info); mClient = client; } catch (RemoteException re) { thrownewIllegalStateException("Error while registering UiTestAutomationService.", re); } }
Caused by: java.lang.SecurityException: You do not have android.permission.RETRIEVE\_WINDOW_CONTENT required to call registerUiTestAutomationService from pid=3676, uid=10040 at android.os.Parcel.readException(Parcel.java:1599) at android.os.Parcel.readException(Parcel.java:1552) at android.view.accessibility.IAccessibilityManager$Stub$Proxy.registerUiTestAutomationService (IAccessibilityManager.java:352) at android.app.UiAutomationConnection.registerUiTestAutomationServiceLocked(UiAutomationConnection.java:337) at android.app.UiAutomationConnection.connect(UiAutomationConnection.java:89) at android.app.UiAutomation.connect(UiAutomation.java:197)
/** * This class represents an accessibility service. It stores all per service * data required for the service management, provides API for starting/stopping the * service and is responsible for adding/removing the service in the data structures * for service management. The class also exposes configuration interface that is * passed to the service it represents as soon it is bound. It also serves as the * connection for the service. */ classServiceextendsIAccessibilityServiceConnection.Stub implementsServiceConnection, DeathRecipient;
/** * Binds to the accessibility service. * * @return True if binding is successful. */ publicbooleanbindLocked() { UserStateuserState= getUserStateLocked(mUserId); if (!mIsAutomation) { if (mService == null && mContext.bindServiceAsUser( mIntent, this, Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE, newUserHandle(mUserId))) { userState.mBindingServices.add(mComponentName); } } else { userState.mBindingServices.add(mComponentName); mService = userState.mUiAutomationServiceClient.asBinder(); mMainHandler.post(newRunnable() { @Override publicvoidrun() { // Simulate asynchronous connection since in onServiceConnected // we may modify the state data in case of an error but bind is // called while iterating over the data and bad things can happen. onServiceConnected(mComponentName, mService); } }); userState.mUiAutomationService = this; } returnfalse; }
/** * @return The client for the current thread. */ publicstatic AccessibilityInteractionClient getInstance() { finallongthreadId= Thread.currentThread().getId(); return getInstanceForThread(threadId); }
/** * <strong>Note:</strong> We keep one instance per interrogating thread since * the instance contains state which can lead to undesired thread interleavings. * We do not have a thread local variable since other threads should be able to * look up the correct client knowing a thread id. See ViewRootImpl for details. * * @return The client for a given <code>threadId</code>. */ publicstatic AccessibilityInteractionClient getInstanceForThread(long threadId) { synchronized (sStaticLock) { AccessibilityInteractionClientclient= sClients.get(threadId); if (client == null) { client = newAccessibilityInteractionClient(); sClients.put(threadId, client); } return client; } }
booleanfindAccessibilityNodeInfoByAccessibilityId(int accessibilityWindowId, long accessibilityNodeId, int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, long threadId);
booleanfindAccessibilityNodeInfosByText(int accessibilityWindowId, long accessibilityNodeId, String text, int interactionId, IAccessibilityInteractionConnectionCallback callback, long threadId);
booleanfindAccessibilityNodeInfosByViewId(int accessibilityWindowId, long accessibilityNodeId, String viewId, int interactionId, IAccessibilityInteractionConnectionCallback callback, long threadId);
booleanfindFocus(int accessibilityWindowId, long accessibilityNodeId, int focusType, int interactionId, IAccessibilityInteractionConnectionCallback callback, long threadId);
booleanfocusSearch(int accessibilityWindowId, long accessibilityNodeId, int direction, int interactionId, IAccessibilityInteractionConnectionCallback callback, long threadId);
booleanperformAccessibilityAction(int accessibilityWindowId, long accessibilityNodeId, int action, in Bundle arguments, int interactionId, IAccessibilityInteractionConnectionCallback callback, long threadId);
AccessibilityWindowInfo getWindow(int windowId);
List<AccessibilityWindowInfo> getWindows();
AccessibilityServiceInfo getServiceInfo();
booleanperformGlobalAction(int action);
oneway voidsetOnKeyEventResult(boolean handled, int sequence); }
// The client may have already obtained the window manager, so // update the default token on whatever manager we gave them. finalWindowManagerImplwm= (WindowManagerImpl) getSystemService(WINDOW_SERVICE); wm.setDefaultToken(windowToken); }