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