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 com.android.server.accessibility;
18 
19 import static com.android.server.accessibility.ProxyManager.PROXY_COMPONENT_CLASS_NAME;
20 import static com.android.server.accessibility.ProxyManager.PROXY_COMPONENT_PACKAGE_NAME;
21 
22 import android.accessibilityservice.AccessibilityServiceInfo;
23 import android.accessibilityservice.AccessibilityTrace;
24 import android.accessibilityservice.IAccessibilityServiceClient;
25 import android.accessibilityservice.MagnificationConfig;
26 import android.annotation.NonNull;
27 import android.annotation.PermissionManuallyEnforced;
28 import android.annotation.RequiresNoPermission;
29 import android.content.ComponentName;
30 import android.content.Context;
31 import android.content.pm.ApplicationInfo;
32 import android.content.pm.ParceledListSlice;
33 import android.content.pm.ResolveInfo;
34 import android.content.pm.ServiceInfo;
35 import android.graphics.Region;
36 import android.os.Binder;
37 import android.os.Handler;
38 import android.os.IBinder;
39 import android.os.RemoteCallback;
40 import android.os.RemoteException;
41 import android.view.KeyEvent;
42 import android.view.accessibility.AccessibilityDisplayProxy;
43 import android.view.accessibility.AccessibilityEvent;
44 import android.view.accessibility.AccessibilityNodeInfo;
45 import android.view.accessibility.AccessibilityWindowInfo;
46 
47 import androidx.annotation.Nullable;
48 
49 import com.android.internal.R;
50 import com.android.internal.util.DumpUtils;
51 import com.android.server.wm.WindowManagerInternal;
52 
53 import java.io.FileDescriptor;
54 import java.io.PrintWriter;
55 import java.util.Arrays;
56 import java.util.Collections;
57 import java.util.HashSet;
58 import java.util.List;
59 import java.util.Set;
60 
61 /**
62  * Represents the system connection to an {@link AccessibilityDisplayProxy}.
63  *
64  * <p>Most methods are no-ops since this connection does not need to capture input or listen to
65  * hardware-related changes.
66  *
67  * TODO(241429275): Initialize this when a proxy is registered.
68  */
69 public class ProxyAccessibilityServiceConnection extends AccessibilityServiceConnection {
70     private static final String LOG_TAG = "ProxyAccessibilityServiceConnection";
71 
72     private int mDeviceId;
73     private int mDisplayId;
74     private List<AccessibilityServiceInfo> mInstalledAndEnabledServices;
75 
76     /** The stroke width of the focus rectangle in pixels */
77     private int mFocusStrokeWidth;
78     /** The color of the focus rectangle */
79     private int mFocusColor;
80 
81     private int mInteractiveTimeout;
82     private int mNonInteractiveTimeout;
83 
ProxyAccessibilityServiceConnection( Context context, ComponentName componentName, AccessibilityServiceInfo accessibilityServiceInfo, int id, Handler mainHandler, Object lock, AccessibilitySecurityPolicy securityPolicy, SystemSupport systemSupport, AccessibilityTrace trace, WindowManagerInternal windowManagerInternal, AccessibilityWindowManager awm, int displayId, int deviceId)84     ProxyAccessibilityServiceConnection(
85             Context context,
86             ComponentName componentName,
87             AccessibilityServiceInfo accessibilityServiceInfo, int id,
88             Handler mainHandler, Object lock,
89             AccessibilitySecurityPolicy securityPolicy,
90             SystemSupport systemSupport, AccessibilityTrace trace,
91             WindowManagerInternal windowManagerInternal,
92             AccessibilityWindowManager awm, int displayId, int deviceId) {
93         super(/* userState= */null, context, componentName, accessibilityServiceInfo, id,
94                 mainHandler, lock, securityPolicy, systemSupport, trace, windowManagerInternal,
95                 /* systemActionPerformer= */ null, awm, /* activityTaskManagerService= */ null);
96         mDisplayId = displayId;
97         setDisplayTypes(DISPLAY_TYPE_PROXY);
98         mFocusStrokeWidth = mContext.getResources().getDimensionPixelSize(
99                 R.dimen.accessibility_focus_highlight_stroke_width);
100         mFocusColor = mContext.getResources().getColor(
101                 R.color.accessibility_focus_highlight_color);
102         mDeviceId = deviceId;
103     }
104 
getDisplayId()105     int getDisplayId() {
106         return mDisplayId;
107     }
getDeviceId()108     int getDeviceId() {
109         return mDeviceId;
110     }
111 
112     /**
113      * Called when the proxy is registered.
114      */
initializeServiceInterface(IAccessibilityServiceClient serviceInterface)115     void initializeServiceInterface(IAccessibilityServiceClient serviceInterface)
116             throws RemoteException {
117         mServiceInterface = serviceInterface;
118         mService = serviceInterface.asBinder();
119         mServiceInterface.init(this, mId, this.mOverlayWindowTokens.get(mDisplayId));
120     }
121 
122     /**
123      * Keeps mAccessibilityServiceInfo in sync with the proxy's list of AccessibilityServiceInfos.
124      *
125      * <p>This also sets the properties that are assumed to be populated by installed packages.
126      *
127      * @param infos the list of enabled and installed services.
128      */
129     @RequiresNoPermission
130     @Override
setInstalledAndEnabledServices(@onNull List<AccessibilityServiceInfo> infos)131     public void setInstalledAndEnabledServices(@NonNull List<AccessibilityServiceInfo> infos) {
132         final long identity = Binder.clearCallingIdentity();
133         try {
134             synchronized (mLock) {
135                 mInstalledAndEnabledServices = infos;
136                 final AccessibilityServiceInfo proxyInfo = mAccessibilityServiceInfo;
137                 // Reset values. mAccessibilityServiceInfo is not completely reset since it is final
138                 proxyInfo.flags = 0;
139                 proxyInfo.eventTypes = 0;
140                 proxyInfo.notificationTimeout = 0;
141                 final Set<String> packageNames = new HashSet<>();
142                 boolean hasNullPackagesNames = false;
143                 boolean isAccessibilityTool = false;
144                 int interactiveUiTimeout = 0;
145                 int nonInteractiveUiTimeout = 0;
146 
147                 // Go through and set properties that are relevant to the proxy. This bypasses
148                 // A11yServiceInfo.updateDynamicallyConfigurableProperties since the proxy has
149                 // higher security privileges as a SystemAPI and has to set values at runtime.
150                 for (AccessibilityServiceInfo info : infos) {
151                     isAccessibilityTool = isAccessibilityTool | info.isAccessibilityTool();
152                     if (info.packageNames == null || info.packageNames.length == 0) {
153                         hasNullPackagesNames = true;
154                     } else if (!hasNullPackagesNames) {
155                         packageNames.addAll(Arrays.asList(info.packageNames));
156                     }
157                     interactiveUiTimeout = Math.max(interactiveUiTimeout,
158                             info.getInteractiveUiTimeoutMillis());
159                     nonInteractiveUiTimeout = Math.max(nonInteractiveUiTimeout,
160                                     info.getNonInteractiveUiTimeoutMillis());
161                     proxyInfo.notificationTimeout = Math.max(proxyInfo.notificationTimeout,
162                             info.notificationTimeout);
163                     proxyInfo.eventTypes |= info.eventTypes;
164                     proxyInfo.feedbackType |= info.feedbackType;
165                     proxyInfo.flags |= info.flags;
166                     // For each info, populate default properties like ResolveInfo.
167                     setDefaultPropertiesIfNullLocked(info);
168                 }
169 
170                 proxyInfo.setAccessibilityTool(isAccessibilityTool);
171                 proxyInfo.setInteractiveUiTimeoutMillis(interactiveUiTimeout);
172                 proxyInfo.setNonInteractiveUiTimeoutMillis(nonInteractiveUiTimeout);
173                 mInteractiveTimeout = interactiveUiTimeout;
174                 mNonInteractiveTimeout = nonInteractiveUiTimeout;
175 
176                 // If any one service info doesn't set package names, i.e. if it's interested in all
177                 // apps, the proxy shouldn't filter by package name even if some infos specify this.
178                 if (hasNullPackagesNames) {
179                     proxyInfo.packageNames = null;
180                 } else {
181                     proxyInfo.packageNames = packageNames.toArray(new String[0]);
182                 }
183 
184                 // Update connection with mAccessibilityServiceInfo values.
185                 setDynamicallyConfigurableProperties(proxyInfo);
186                 // Notify manager service.
187                 mSystemSupport.onProxyChanged(mDeviceId);
188             }
189         } finally {
190             Binder.restoreCallingIdentity(identity);
191         }
192     }
193 
setDefaultPropertiesIfNullLocked(AccessibilityServiceInfo info)194     private void setDefaultPropertiesIfNullLocked(AccessibilityServiceInfo info) {
195         final String componentClassDisplayName = PROXY_COMPONENT_CLASS_NAME + mDisplayId;
196         // Populate the properties that can't be null, since this may cause crashes in apps that
197         // assume these are populated by an installed package.
198         if (info.getResolveInfo() == null) {
199             final ResolveInfo resolveInfo = new ResolveInfo();
200             final ServiceInfo serviceInfo = new ServiceInfo();
201             final ApplicationInfo applicationInfo = new ApplicationInfo();
202 
203             serviceInfo.packageName = PROXY_COMPONENT_PACKAGE_NAME;
204             serviceInfo.name = componentClassDisplayName;
205 
206             applicationInfo.processName = PROXY_COMPONENT_PACKAGE_NAME;
207             applicationInfo.className = componentClassDisplayName;
208 
209             resolveInfo.serviceInfo = serviceInfo;
210             serviceInfo.applicationInfo = applicationInfo;
211             info.setResolveInfo(resolveInfo);
212         }
213 
214         if (info.getComponentName() == null) {
215             info.setComponentName(new ComponentName(PROXY_COMPONENT_PACKAGE_NAME,
216                             componentClassDisplayName));
217         }
218     }
219 
220     @RequiresNoPermission
221     @Override
222     @NonNull
getInstalledAndEnabledServices()223     public List<AccessibilityServiceInfo> getInstalledAndEnabledServices() {
224         synchronized (mLock) {
225             return mInstalledAndEnabledServices != null
226                     ? mInstalledAndEnabledServices : Collections.emptyList();
227         }
228     }
229 
230     @RequiresNoPermission
231     @Override
getWindows()232     public AccessibilityWindowInfo.WindowListSparseArray getWindows() {
233         final AccessibilityWindowInfo.WindowListSparseArray allWindows = super.getWindows();
234         AccessibilityWindowInfo.WindowListSparseArray displayWindows = new
235                 AccessibilityWindowInfo.WindowListSparseArray();
236         // Filter here so A11yInteractionClient will not cache all the windows belonging to other
237         // proxy connections.
238         displayWindows.put(mDisplayId, allWindows.get(mDisplayId, Collections.emptyList()));
239         return displayWindows;
240     }
241 
242     @RequiresNoPermission
243     @Override
setFocusAppearance(int strokeWidth, int color)244     public void setFocusAppearance(int strokeWidth, int color) {
245         synchronized (mLock) {
246             if (!hasRightsToCurrentUserLocked()) {
247                 return;
248             }
249 
250             if (!mSecurityPolicy.checkAccessibilityAccess(this)) {
251                 return;
252             }
253 
254             if (getFocusStrokeWidthLocked() == strokeWidth && getFocusColorLocked() == color) {
255                 return;
256             }
257 
258             mFocusStrokeWidth = strokeWidth;
259             mFocusColor = color;
260             mSystemSupport.onProxyChanged(mDeviceId);
261         }
262     }
263 
264     /**
265      * Gets the stroke width of the focus rectangle.
266      * @return The stroke width.
267      */
getFocusStrokeWidthLocked()268     public int getFocusStrokeWidthLocked() {
269         return mFocusStrokeWidth;
270     }
271 
272     /**
273      * Gets the color of the focus rectangle.
274      * @return The color.
275      */
getFocusColorLocked()276     public int getFocusColorLocked() {
277         return mFocusColor;
278     }
279 
280     @RequiresNoPermission
281     @Override
resolveAccessibilityWindowIdForFindFocusLocked(int windowId, int focusType)282     int resolveAccessibilityWindowIdForFindFocusLocked(int windowId, int focusType) {
283         if (windowId == AccessibilityWindowInfo.ANY_WINDOW_ID) {
284             final int focusedWindowId = mA11yWindowManager.getFocusedWindowId(focusType,
285                     mDisplayId);
286             // If the caller is a proxy and the found window doesn't belong to a proxy display
287             // (or vice versa), then return null. This doesn't work if there are multiple active
288             // proxys, but in the future this code shouldn't be needed if input focus
289             // properly split. (so we will deal with the issues if we see them).
290             //TODO(254545943): Remove this when there is user and proxy separation of input
291             if (!mA11yWindowManager.windowIdBelongsToDisplayType(focusedWindowId, mDisplayTypes)) {
292                 return AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
293             }
294             return focusedWindowId;
295         }
296         return windowId;
297     }
298 
299     @Override
binderDied()300     public void binderDied() {
301     }
302 
303     @Override
supportsFlagForNotImportantViews(AccessibilityServiceInfo info)304     protected boolean supportsFlagForNotImportantViews(AccessibilityServiceInfo info) {
305         // Don't need to check for earlier APIs.
306         return true;
307     }
308 
309     @Override
hasRightsToCurrentUserLocked()310     protected boolean hasRightsToCurrentUserLocked() {
311         // TODO(250929565): Proxy access is not currently determined by user. Adjust in refactoring.
312         return true;
313     }
314 
315     /** @throws UnsupportedOperationException since a proxy does not need key events */
316     @Override
onKeyEvent(KeyEvent keyEvent, int sequenceNumber)317     public boolean onKeyEvent(KeyEvent keyEvent, int sequenceNumber)
318             throws UnsupportedOperationException  {
319         throw new UnsupportedOperationException("onKeyEvent is not supported");
320     }
321 
322     /** @throws UnsupportedOperationException since a proxy does not need fingerprint hardware */
323     @RequiresNoPermission
324     @Override
isCapturingFingerprintGestures()325     public boolean isCapturingFingerprintGestures() throws UnsupportedOperationException {
326         throw new UnsupportedOperationException("isCapturingFingerprintGestures is not supported");
327     }
328 
329     /** @throws UnsupportedOperationException since a proxy does not need fingerprint hardware */
330     @RequiresNoPermission
331     @Override
onFingerprintGestureDetectionActiveChanged(boolean active)332     public void onFingerprintGestureDetectionActiveChanged(boolean active)
333             throws UnsupportedOperationException {
334         throw new UnsupportedOperationException("onFingerprintGestureDetectionActiveChanged is not"
335                 + " supported");
336     }
337 
338     /** @throws UnsupportedOperationException since a proxy does not need fingerprint hardware */
339     @RequiresNoPermission
340     @Override
onFingerprintGesture(int gesture)341     public void onFingerprintGesture(int gesture) throws UnsupportedOperationException {
342         throw new UnsupportedOperationException("onFingerprintGesture is not supported");
343     }
344 
345     /** @throws UnsupportedOperationException since a proxy does not need fingerprint hardware */
346     @RequiresNoPermission
347     @Override
isFingerprintGestureDetectionAvailable()348     public boolean isFingerprintGestureDetectionAvailable() throws UnsupportedOperationException {
349         throw new UnsupportedOperationException("isFingerprintGestureDetectionAvailable is not"
350                 + " supported");
351     }
352 
353     /** @throws UnsupportedOperationException since a proxy is not a Service */
354     @RequiresNoPermission
355     @Override
onServiceConnected(ComponentName name, IBinder service)356     public void onServiceConnected(ComponentName name, IBinder service)
357             throws UnsupportedOperationException {
358         throw new UnsupportedOperationException("onServiceConnected is not supported");
359 
360     }
361 
362     /** @throws UnsupportedOperationException since a proxy is not a Service */
363     @RequiresNoPermission
364     @Override
onServiceDisconnected(ComponentName name)365     public void onServiceDisconnected(ComponentName name)
366             throws UnsupportedOperationException {
367         throw new UnsupportedOperationException("onServiceDisconnected is not supported");
368     }
369 
370     /** @throws UnsupportedOperationException since a proxy should use
371      * setInstalledAndEnabledServices*/
372     @RequiresNoPermission
373     @Override
setServiceInfo(AccessibilityServiceInfo info)374     public void setServiceInfo(AccessibilityServiceInfo info)
375             throws UnsupportedOperationException  {
376         // TODO(241429275): Ensure getServiceInfo is called appropriately for a proxy or is a no-op.
377         throw new UnsupportedOperationException("setServiceInfo is not supported");
378     }
379 
380     /** @throws UnsupportedOperationException since a proxy should use A11yManager#unregister */
381     @RequiresNoPermission
382     @Override
disableSelf()383     public void disableSelf() throws UnsupportedOperationException {
384         // A proxy uses A11yManager#unregister to turn itself off.
385         throw new UnsupportedOperationException("disableSelf is not supported");
386     }
387 
388     /** @throws UnsupportedOperationException since a proxy does not have global system access */
389     @RequiresNoPermission
390     @Override
performGlobalAction(int action)391     public boolean performGlobalAction(int action) throws UnsupportedOperationException {
392         throw new UnsupportedOperationException("performGlobalAction is not supported");
393     }
394 
395     /** @throws UnsupportedOperationException since a proxy does not need key events */
396     @RequiresNoPermission
397     @Override
setOnKeyEventResult(boolean handled, int sequence)398     public void setOnKeyEventResult(boolean handled, int sequence)
399             throws UnsupportedOperationException {
400         throw new UnsupportedOperationException("setOnKeyEventResult is not supported");
401     }
402 
403     /** @throws UnsupportedOperationException since a proxy does not have global system access */
404     @RequiresNoPermission
405     @Override
getSystemActions()406     public @NonNull List<AccessibilityNodeInfo.AccessibilityAction> getSystemActions()
407             throws UnsupportedOperationException {
408         throw new UnsupportedOperationException("getSystemActions is not supported");
409     }
410 
411     /** @throws UnsupportedOperationException since a proxy does not need magnification */
412     @Nullable
413     @RequiresNoPermission
414     @Override
getMagnificationConfig(int displayId)415     public MagnificationConfig getMagnificationConfig(int displayId)
416             throws UnsupportedOperationException {
417         throw new UnsupportedOperationException("getMagnificationConfig is not supported");
418     }
419 
420     /** @throws UnsupportedOperationException since a proxy does not need magnification */
421     @RequiresNoPermission
422     @Override
getMagnificationScale(int displayId)423     public float getMagnificationScale(int displayId) throws UnsupportedOperationException {
424         throw new UnsupportedOperationException("getMagnificationScale is not supported");
425     }
426 
427     /** @throws UnsupportedOperationException since a proxy does not need magnification */
428     @RequiresNoPermission
429     @Override
getMagnificationCenterX(int displayId)430     public float getMagnificationCenterX(int displayId) throws UnsupportedOperationException {
431         throw new UnsupportedOperationException("getMagnificationCenterX is not supported");
432     }
433 
434     /** @throws UnsupportedOperationException since a proxy does not need magnification */
435     @RequiresNoPermission
436     @Override
getMagnificationCenterY(int displayId)437     public float getMagnificationCenterY(int displayId) throws UnsupportedOperationException {
438         throw new UnsupportedOperationException("getMagnificationCenterY is not supported");
439     }
440 
441     /** @throws UnsupportedOperationException since a proxy does not need magnification */
442     @RequiresNoPermission
443     @Override
getMagnificationRegion(int displayId)444     public Region getMagnificationRegion(int displayId) throws UnsupportedOperationException {
445         throw new UnsupportedOperationException("getMagnificationRegion is not supported");
446     }
447 
448     /** @throws UnsupportedOperationException since a proxy does not need magnification */
449     @RequiresNoPermission
450     @Override
getCurrentMagnificationRegion(int displayId)451     public Region getCurrentMagnificationRegion(int displayId)
452             throws UnsupportedOperationException {
453         throw new UnsupportedOperationException("getCurrentMagnificationRegion is not supported");
454     }
455 
456     /** @throws UnsupportedOperationException since a proxy does not need magnification */
457     @RequiresNoPermission
458     @Override
resetMagnification(int displayId, boolean animate)459     public boolean resetMagnification(int displayId, boolean animate)
460             throws UnsupportedOperationException {
461         throw new UnsupportedOperationException("resetMagnification is not supported");
462     }
463 
464     /** @throws UnsupportedOperationException since a proxy does not need magnification */
465     @RequiresNoPermission
466     @Override
resetCurrentMagnification(int displayId, boolean animate)467     public boolean resetCurrentMagnification(int displayId, boolean animate)
468             throws UnsupportedOperationException {
469         throw new UnsupportedOperationException("resetCurrentMagnification is not supported");
470     }
471 
472     /** @throws UnsupportedOperationException since a proxy does not need magnification */
473     @RequiresNoPermission
474     @Override
setMagnificationConfig(int displayId, @androidx.annotation.NonNull MagnificationConfig config, boolean animate)475     public boolean setMagnificationConfig(int displayId,
476             @androidx.annotation.NonNull MagnificationConfig config, boolean animate)
477             throws UnsupportedOperationException {
478         throw new UnsupportedOperationException("setMagnificationConfig is not supported");
479     }
480 
481     /** @throws UnsupportedOperationException since a proxy does not need magnification */
482     @RequiresNoPermission
483     @Override
setMagnificationCallbackEnabled(int displayId, boolean enabled)484     public void setMagnificationCallbackEnabled(int displayId, boolean enabled)
485             throws UnsupportedOperationException {
486         throw new UnsupportedOperationException("setMagnificationCallbackEnabled is not supported");
487     }
488 
489     /** @throws UnsupportedOperationException since a proxy does not need magnification */
490     @RequiresNoPermission
491     @Override
isMagnificationCallbackEnabled(int displayId)492     public boolean isMagnificationCallbackEnabled(int displayId) {
493         throw new UnsupportedOperationException("isMagnificationCallbackEnabled is not supported");
494     }
495 
496     /** @throws UnsupportedOperationException since a proxy does not need IME access*/
497     @RequiresNoPermission
498     @Override
setSoftKeyboardShowMode(int showMode)499     public boolean setSoftKeyboardShowMode(int showMode) throws UnsupportedOperationException {
500         throw new UnsupportedOperationException("setSoftKeyboardShowMode is not supported");
501     }
502 
503     /** @throws UnsupportedOperationException since a proxy does not need IME access */
504     @RequiresNoPermission
505     @Override
getSoftKeyboardShowMode()506     public int getSoftKeyboardShowMode() throws UnsupportedOperationException {
507         throw new UnsupportedOperationException("getSoftKeyboardShowMode is not supported");
508     }
509 
510     /** @throws UnsupportedOperationException since a proxy does not need IME access */
511     @RequiresNoPermission
512     @Override
setSoftKeyboardCallbackEnabled(boolean enabled)513     public void setSoftKeyboardCallbackEnabled(boolean enabled)
514             throws UnsupportedOperationException {
515         throw new UnsupportedOperationException("setSoftKeyboardCallbackEnabled is not supported");
516     }
517 
518     /** @throws UnsupportedOperationException since a proxy does not need IME access */
519     @RequiresNoPermission
520     @Override
switchToInputMethod(String imeId)521     public boolean switchToInputMethod(String imeId) throws UnsupportedOperationException {
522         throw new UnsupportedOperationException("switchToInputMethod is not supported");
523     }
524 
525     /** @throws UnsupportedOperationException since a proxy does not need IME access */
526     @RequiresNoPermission
527     @Override
setInputMethodEnabled(String imeId, boolean enabled)528     public int setInputMethodEnabled(String imeId, boolean enabled)
529             throws UnsupportedOperationException {
530         throw new UnsupportedOperationException("setInputMethodEnabled is not supported");
531     }
532 
533     /** @throws UnsupportedOperationException since a proxy does not need access to the shortcut */
534     @RequiresNoPermission
535     @Override
isAccessibilityButtonAvailable()536     public boolean isAccessibilityButtonAvailable() throws UnsupportedOperationException {
537         throw new UnsupportedOperationException("isAccessibilityButtonAvailable is not supported");
538     }
539 
540     /** @throws UnsupportedOperationException since a proxy does not need gestures/input access */
541     @RequiresNoPermission
542     @Override
sendGesture(int sequence, ParceledListSlice gestureSteps)543     public void sendGesture(int sequence, ParceledListSlice gestureSteps)
544             throws UnsupportedOperationException {
545         throw new UnsupportedOperationException("sendGesture is not supported");
546     }
547 
548     /** @throws UnsupportedOperationException since a proxy does not need gestures/input access */
549     @RequiresNoPermission
550     @Override
dispatchGesture(int sequence, ParceledListSlice gestureSteps, int displayId)551     public void dispatchGesture(int sequence, ParceledListSlice gestureSteps, int displayId)
552             throws UnsupportedOperationException {
553         throw new UnsupportedOperationException("dispatchGesture is not supported");
554     }
555 
556     /** @throws UnsupportedOperationException since a proxy does not need access to screenshots */
557     @RequiresNoPermission
558     @Override
takeScreenshot(int displayId, RemoteCallback callback)559     public void takeScreenshot(int displayId, RemoteCallback callback)
560             throws UnsupportedOperationException {
561         throw new UnsupportedOperationException("takeScreenshot is not supported");
562     }
563 
564     /** @throws UnsupportedOperationException since a proxy does not need gestures/input access */
565     @RequiresNoPermission
566     @Override
setGestureDetectionPassthroughRegion(int displayId, Region region)567     public void setGestureDetectionPassthroughRegion(int displayId, Region region)
568             throws UnsupportedOperationException {
569         throw new UnsupportedOperationException("setGestureDetectionPassthroughRegion is not"
570                 + " supported");
571     }
572 
573     /** @throws UnsupportedOperationException since a proxy does not need gestures/input access */
574     @RequiresNoPermission
575     @Override
setTouchExplorationPassthroughRegion(int displayId, Region region)576     public void setTouchExplorationPassthroughRegion(int displayId, Region region)
577             throws UnsupportedOperationException {
578         throw new UnsupportedOperationException("setTouchExplorationPassthroughRegion is not"
579                 + " supported");
580     }
581 
582     /** @throws UnsupportedOperationException since a proxy does not need gestures/input access */
583     @RequiresNoPermission
584     @Override
setServiceDetectsGesturesEnabled(int displayId, boolean mode)585     public void setServiceDetectsGesturesEnabled(int displayId, boolean mode)
586             throws UnsupportedOperationException {
587         throw new UnsupportedOperationException("setServiceDetectsGesturesEnabled is not"
588                 + " supported");
589     }
590 
591     /** @throws UnsupportedOperationException since a proxy does not need touch input access */
592     @RequiresNoPermission
593     @Override
requestTouchExploration(int displayId)594     public void requestTouchExploration(int displayId) throws UnsupportedOperationException  {
595         throw new UnsupportedOperationException("requestTouchExploration is not supported");
596     }
597 
598     /** @throws UnsupportedOperationException since a proxy does not need touch input access */
599     @RequiresNoPermission
600     @Override
requestDragging(int displayId, int pointerId)601     public void requestDragging(int displayId, int pointerId) throws UnsupportedOperationException {
602         throw new UnsupportedOperationException("requestDragging is not supported");
603     }
604 
605     /** @throws UnsupportedOperationException since a proxy does not need touch input access */
606     @RequiresNoPermission
607     @Override
requestDelegating(int displayId)608     public void requestDelegating(int displayId) throws UnsupportedOperationException {
609         throw new UnsupportedOperationException("requestDelegating is not supported");
610     }
611 
612     /** @throws UnsupportedOperationException since a proxy does not need touch input access */
613     @RequiresNoPermission
614     @Override
onDoubleTap(int displayId)615     public void onDoubleTap(int displayId) throws UnsupportedOperationException {
616         throw new UnsupportedOperationException("onDoubleTap is not supported");
617     }
618 
619     /** @throws UnsupportedOperationException since a proxy does not need touch input access */
620     @RequiresNoPermission
621     @Override
onDoubleTapAndHold(int displayId)622     public void onDoubleTapAndHold(int displayId) throws UnsupportedOperationException {
623         throw new UnsupportedOperationException("onDoubleTapAndHold is not supported");
624     }
625 
626     /** @throws UnsupportedOperationException since a proxy does not need touch input access */
627     @RequiresNoPermission
628     @Override
setAnimationScale(float scale)629     public void setAnimationScale(float scale) throws UnsupportedOperationException {
630         throw new UnsupportedOperationException("setAnimationScale is not supported");
631     }
632 
getInteractiveTimeout()633     public int getInteractiveTimeout() {
634         return mInteractiveTimeout;
635     }
636 
getNonInteractiveTimeout()637     public int getNonInteractiveTimeout() {
638         return mNonInteractiveTimeout;
639     }
640 
641     /**
642      * Returns true if a timeout was updated.
643      */
updateTimeouts(int nonInteractiveUiTimeout, int interactiveUiTimeout)644     public boolean updateTimeouts(int nonInteractiveUiTimeout, int interactiveUiTimeout) {
645         final int newInteractiveUiTimeout = interactiveUiTimeout != 0
646                 ? interactiveUiTimeout
647                 : mAccessibilityServiceInfo.getInteractiveUiTimeoutMillis();
648         final int newNonInteractiveUiTimeout = nonInteractiveUiTimeout != 0
649                 ? nonInteractiveUiTimeout
650                 : mAccessibilityServiceInfo.getNonInteractiveUiTimeoutMillis();
651         boolean updated = false;
652 
653         if (mInteractiveTimeout != newInteractiveUiTimeout) {
654             mInteractiveTimeout =  newInteractiveUiTimeout;
655             updated = true;
656         }
657         if (mNonInteractiveTimeout != newNonInteractiveUiTimeout) {
658             mNonInteractiveTimeout = newNonInteractiveUiTimeout;
659             updated = true;
660         }
661         return updated;
662     }
663 
664     @PermissionManuallyEnforced
665     @Override
dump(FileDescriptor fd, final PrintWriter pw, String[] args)666     public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) {
667         if (!DumpUtils.checkDumpPermission(mContext, LOG_TAG, pw)) return;
668         synchronized (mLock) {
669             pw.append("Proxy[displayId=" + mDisplayId);
670             pw.append(", deviceId=" + mDeviceId);
671             pw.append(", feedbackType"
672                     + AccessibilityServiceInfo.feedbackTypeToString(mFeedbackType));
673             pw.append(", capabilities=" + mAccessibilityServiceInfo.getCapabilities());
674             pw.append(", eventTypes="
675                     + AccessibilityEvent.eventTypeToString(mEventTypes));
676             pw.append(", notificationTimeout=" + mNotificationTimeout);
677             pw.append(", nonInteractiveUiTimeout=").append(String.valueOf(mNonInteractiveTimeout));
678             pw.append(", interactiveUiTimeout=").append(String.valueOf(mInteractiveTimeout));
679             pw.append(", focusStrokeWidth=").append(String.valueOf(mFocusStrokeWidth));
680             pw.append(", focusColor=").append(String.valueOf(mFocusColor));
681             pw.append(", installedAndEnabledServiceCount=").append(String.valueOf(
682                     mInstalledAndEnabledServices.size()));
683             pw.append(", installedAndEnabledServices=").append(
684                     mInstalledAndEnabledServices.toString());
685             pw.append("]");
686         }
687     }
688 }
689