1 /*
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.view.accessibility;
18 
19 import android.accessibilityservice.IAccessibilityServiceConnection;
20 import android.graphics.Region;
21 import android.os.Bundle;
22 import android.os.Process;
23 import android.os.RemoteException;
24 
25 /**
26  * Minimal {@link IAccessibilityServiceConnection} implementation that interacts
27  * with the {@link android.view.AccessibilityInteractionController} of a
28  * {@link android.view.ViewRootImpl}.
29  *
30  * <p>
31  * Uses {@link android.view.ViewRootImpl}'s {@link IAccessibilityServiceConnection} that wraps
32  * {@link android.view.AccessibilityInteractionController} within the app process, so that no
33  * interprocess communication is performed.
34  * </p>
35  *
36  * <p>
37  * Only the following methods are supported:
38  * <li>{@link #findAccessibilityNodeInfoByAccessibilityId}</li>
39  * <li>{@link #findAccessibilityNodeInfosByText}</li>
40  * <li>{@link #findAccessibilityNodeInfosByViewId}</li>
41  * <li>{@link #findFocus}</li>
42  * <li>{@link #focusSearch}</li>
43  * <li>{@link #performAccessibilityAction}</li>
44  * </p>
45  *
46  * <p>
47  * Other methods are no-ops and return default values.
48  * </p>
49  */
50 class DirectAccessibilityConnection extends IAccessibilityServiceConnection.Default {
51     private final IAccessibilityInteractionConnection mAccessibilityInteractionConnection;
52     private final AccessibilityManager mAccessibilityManager;
53     private final int mMyProcessId;
54 
55     // Fetch all views, but do not use prefetching/cache since this "connection" does not
56     // receive cache invalidation events (as it is not linked to an AccessibilityService).
57     private static final int FETCH_FLAGS =
58             AccessibilityNodeInfo.FLAG_SERVICE_REQUESTS_REPORT_VIEW_IDS
59                     | AccessibilityNodeInfo.FLAG_SERVICE_REQUESTS_INCLUDE_NOT_IMPORTANT_VIEWS;
60     private static final Region INTERACTIVE_REGION = null;
61 
DirectAccessibilityConnection( IAccessibilityInteractionConnection accessibilityInteractionConnection, AccessibilityManager accessibilityManager)62     DirectAccessibilityConnection(
63             IAccessibilityInteractionConnection accessibilityInteractionConnection,
64             AccessibilityManager accessibilityManager) {
65         mAccessibilityInteractionConnection = accessibilityInteractionConnection;
66         mAccessibilityManager = accessibilityManager;
67         mMyProcessId = Process.myPid();
68     }
69 
70     @Override
findAccessibilityNodeInfoByAccessibilityId(int accessibilityWindowId, long accessibilityNodeId, int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, long threadId, Bundle arguments)71     public String[] findAccessibilityNodeInfoByAccessibilityId(int accessibilityWindowId,
72             long accessibilityNodeId, int interactionId,
73             IAccessibilityInteractionConnectionCallback callback, int flags, long threadId,
74             Bundle arguments) throws RemoteException {
75         IAccessibilityManager.WindowTransformationSpec spec =
76                 mAccessibilityManager.getWindowTransformationSpec(accessibilityWindowId);
77         mAccessibilityInteractionConnection.findAccessibilityNodeInfoByAccessibilityId(
78                 accessibilityNodeId, INTERACTIVE_REGION, interactionId, callback, FETCH_FLAGS,
79                 mMyProcessId, threadId, spec.magnificationSpec, spec.transformationMatrix,
80                 arguments);
81         return new String[0];
82     }
83 
84     @Override
findAccessibilityNodeInfosByText(int accessibilityWindowId, long accessibilityNodeId, String text, int interactionId, IAccessibilityInteractionConnectionCallback callback, long threadId)85     public String[] findAccessibilityNodeInfosByText(int accessibilityWindowId,
86             long accessibilityNodeId, String text, int interactionId,
87             IAccessibilityInteractionConnectionCallback callback, long threadId)
88             throws RemoteException {
89         IAccessibilityManager.WindowTransformationSpec spec =
90                 mAccessibilityManager.getWindowTransformationSpec(accessibilityWindowId);
91         mAccessibilityInteractionConnection.findAccessibilityNodeInfosByText(accessibilityNodeId,
92                 text, INTERACTIVE_REGION, interactionId, callback, FETCH_FLAGS, mMyProcessId,
93                 threadId, spec.magnificationSpec, spec.transformationMatrix);
94         return new String[0];
95     }
96 
97     @Override
findAccessibilityNodeInfosByViewId(int accessibilityWindowId, long accessibilityNodeId, String viewId, int interactionId, IAccessibilityInteractionConnectionCallback callback, long threadId)98     public String[] findAccessibilityNodeInfosByViewId(int accessibilityWindowId,
99             long accessibilityNodeId, String viewId, int interactionId,
100             IAccessibilityInteractionConnectionCallback callback, long threadId)
101             throws RemoteException {
102         IAccessibilityManager.WindowTransformationSpec spec =
103                 mAccessibilityManager.getWindowTransformationSpec(accessibilityWindowId);
104         mAccessibilityInteractionConnection.findAccessibilityNodeInfosByViewId(accessibilityNodeId,
105                 viewId, INTERACTIVE_REGION, interactionId, callback, FETCH_FLAGS, mMyProcessId,
106                 threadId, spec.magnificationSpec, spec.transformationMatrix);
107         return new String[0];
108     }
109 
110     @Override
findFocus(int accessibilityWindowId, long accessibilityNodeId, int focusType, int interactionId, IAccessibilityInteractionConnectionCallback callback, long threadId)111     public String[] findFocus(int accessibilityWindowId, long accessibilityNodeId, int focusType,
112             int interactionId, IAccessibilityInteractionConnectionCallback callback, long threadId)
113             throws RemoteException {
114         IAccessibilityManager.WindowTransformationSpec spec =
115                 mAccessibilityManager.getWindowTransformationSpec(accessibilityWindowId);
116         mAccessibilityInteractionConnection.findFocus(accessibilityNodeId, focusType,
117                 INTERACTIVE_REGION, interactionId, callback, FETCH_FLAGS, mMyProcessId, threadId,
118                 spec.magnificationSpec, spec.transformationMatrix);
119         return new String[0];
120     }
121 
122     @Override
focusSearch(int accessibilityWindowId, long accessibilityNodeId, int direction, int interactionId, IAccessibilityInteractionConnectionCallback callback, long threadId)123     public String[] focusSearch(int accessibilityWindowId, long accessibilityNodeId, int direction,
124             int interactionId, IAccessibilityInteractionConnectionCallback callback, long threadId)
125             throws RemoteException {
126         IAccessibilityManager.WindowTransformationSpec spec =
127                 mAccessibilityManager.getWindowTransformationSpec(accessibilityWindowId);
128         mAccessibilityInteractionConnection.focusSearch(accessibilityNodeId, direction,
129                 INTERACTIVE_REGION, interactionId, callback, FETCH_FLAGS, mMyProcessId, threadId,
130                 spec.magnificationSpec, spec.transformationMatrix);
131         return new String[0];
132     }
133 
134     @Override
performAccessibilityAction(int accessibilityWindowId, long accessibilityNodeId, int action, Bundle arguments, int interactionId, IAccessibilityInteractionConnectionCallback callback, long threadId)135     public boolean performAccessibilityAction(int accessibilityWindowId, long accessibilityNodeId,
136             int action, Bundle arguments, int interactionId,
137             IAccessibilityInteractionConnectionCallback callback, long threadId)
138             throws RemoteException {
139         mAccessibilityInteractionConnection.performAccessibilityAction(accessibilityNodeId, action,
140                 arguments, interactionId, callback, FETCH_FLAGS, mMyProcessId, threadId);
141         return true;
142     }
143 }
144