Loading core/java/android/view/MotionEvent.java +29 −0 Original line number Diff line number Diff line Loading @@ -486,6 +486,21 @@ public final class MotionEvent extends InputEvent implements Parcelable { */ public static final int FLAG_TAINTED = 0x80000000; /** * Private flag indicating that this event was synthesized by the system and should be delivered * to the accessibility focused view first. When being dispatched such an event is not handled * by predecessors of the accessibility focused view and after the event reaches that view the * flag is cleared and normal event dispatch is performed. This ensures that the platform can * click on any view that has accessibility focus which is semantically equivalent to asking the * view to perform a click accessibility action but more generic as views not implementing click * action correctly can still be activated. * * @hide * @see #isTargetAccessibilityFocus() * @see #setTargetAccessibilityFocus(boolean) */ public static final int FLAG_TARGET_ACCESSIBILITY_FOCUS = 0x40000000; /** * Flag indicating the motion event intersected the top edge of the screen. */ Loading Loading @@ -2139,6 +2154,20 @@ public final class MotionEvent extends InputEvent implements Parcelable { nativeSetFlags(mNativePtr, tainted ? flags | FLAG_TAINTED : flags & ~FLAG_TAINTED); } /** @hide */ public boolean isTargetAccessibilityFocus() { final int flags = getFlags(); return (flags & FLAG_TARGET_ACCESSIBILITY_FOCUS) != 0; } /** @hide */ public void setTargetAccessibilityFocus(boolean targetsFocus) { final int flags = getFlags(); nativeSetFlags(mNativePtr, targetsFocus ? flags | FLAG_TARGET_ACCESSIBILITY_FOCUS : flags & ~FLAG_TARGET_ACCESSIBILITY_FOCUS); } /** @hide */ public final boolean isHoverExitPending() { final int flags = getFlags(); Loading core/java/android/view/View.java +8 −0 Original line number Diff line number Diff line Loading @@ -14274,6 +14274,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback, */ public boolean dispatchTouchEvent(MotionEvent event) { // If the event should be handled by accessibility focus first. if (event.isTargetAccessibilityFocus()) { // We don't have focus or no virtual descendant has it, do not handle the event. if (!isAccessibilityFocusedViewOrHost()) { return false; } // We have focus and got the event, then use normal event dispatch. event.setTargetAccessibilityFocus(false); } boolean result = false; if (mInputEventConsistencyVerifier != null) { core/java/android/view/ViewGroup.java +77 −4 Original line number Diff line number Diff line Loading @@ -2048,8 +2048,26 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager for (int i = childrenCount - 1; i >= 0; i--) { final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder); final View child = getAndVerifyPreorderedView(preorderedList, children, childIndex); View childWithAccessibilityFocus = event.isTargetAccessibilityFocus() ? findChildWithAccessibilityFocus() : null; if (!child.canReceivePointerEvents() || !isTransformedTouchPointInView(x, y, child, null)) { // If there is a view that has accessibility focus we want it // to get the event first and if not handled we will perform a // normal dispatch. We may do a double iteration but this is // safer given the timeframe. if (childWithAccessibilityFocus != null) { if (childWithAccessibilityFocus != child) { continue; } childWithAccessibilityFocus = null; i = childrenCount - 1; } event.setTargetAccessibilityFocus(false); continue; } final PointerIcon pointerIcon = Loading Loading @@ -2617,6 +2635,12 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager mInputEventConsistencyVerifier.onTouchEvent(ev, 1); } // If the event targets the accessibility focused view and this is it, start // normal event dispatch. Maybe a descendant is what will handle the click. if (ev.isTargetAccessibilityFocus() && isAccessibilityFocusedViewOrHost()) { ev.setTargetAccessibilityFocus(false); } boolean handled = false; if (onFilterTouchEventForSecurity(ev)) { final int action = ev.getAction(); Loading Loading @@ -2647,6 +2671,13 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager // so this view group continues to intercept touches. intercepted = true; } // If intercepted, start normal event dispatch. Also if there is already // a view that is handling the gesture, do normal event dispatch. if (intercepted || mFirstTouchTarget != null) { ev.setTargetAccessibilityFocus(false); } // Check for cancelation. final boolean canceled = resetCancelNextUpFlag(this) || actionMasked == MotionEvent.ACTION_CANCEL; Loading @@ -2658,6 +2689,14 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager TouchTarget newTouchTarget = null; boolean alreadyDispatchedToNewTouchTarget = false; if (!canceled && !intercepted) { // If the event is targeting accessibility focus we give it to the // view that has accessibility focus and if it does not handle it // we clear the flag and dispatch the event to all children as usual. // We are looking up the accessibility focused host to avoid keeping // state since these events are very rare. View childWithAccessibilityFocus = ev.isTargetAccessibilityFocus() ? findChildWithAccessibilityFocus() : null; if (actionMasked == MotionEvent.ACTION_DOWN || (split && actionMasked == MotionEvent.ACTION_POINTER_DOWN) || actionMasked == MotionEvent.ACTION_HOVER_MOVE) { Loading Loading @@ -2720,6 +2759,10 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager alreadyDispatchedToNewTouchTarget = true; break; } // The accessibility focus didn't handle the event, so clear // the flag and do a normal dispatch to all children. ev.setTargetAccessibilityFocus(false); } if (preorderedList != null) preorderedList.clear(); } Loading Loading @@ -2803,6 +2846,34 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager return buildOrderedChildList(); } /** * Finds the child which has accessibility focus. * * @return The child that has focus. */ private View findChildWithAccessibilityFocus() { ViewRootImpl viewRoot = getViewRootImpl(); if (viewRoot == null) { return null; } View current = viewRoot.getAccessibilityFocusedHost(); if (current == null) { return null; } ViewParent parent = current.getParent(); while (parent instanceof View) { if (parent == this) { return current; } current = (View) parent; parent = current.getParent(); } return null; } /** * Resets all touch state in preparation for a new cycle. */ Loading Loading @@ -3257,9 +3328,10 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager break; } default: throw new IllegalStateException("descendant focusability must be " + "one of FOCUS_BEFORE_DESCENDANTS, FOCUS_AFTER_DESCENDANTS, FOCUS_BLOCK_DESCENDANTS " + "but is " + descendantFocusability); throw new IllegalStateException( "descendant focusability must be one of FOCUS_BEFORE_DESCENDANTS," + " FOCUS_AFTER_DESCENDANTS, FOCUS_BLOCK_DESCENDANTS but is " + descendantFocusability); } if (result && !isLayoutValid() && ((mPrivateFlags & PFLAG_WANTS_FOCUS) == 0)) { mPrivateFlags |= PFLAG_WANTS_FOCUS; Loading Loading @@ -4925,7 +4997,8 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager if (params == null) { params = generateDefaultLayoutParams(); if (params == null) { throw new IllegalArgumentException("generateDefaultLayoutParams() cannot return null"); throw new IllegalArgumentException( "generateDefaultLayoutParams() cannot return null"); } } addView(child, index, params); Loading services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java +96 −0 Original line number Diff line number Diff line Loading @@ -56,6 +56,8 @@ import android.content.pm.PackageManagerInternal; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.database.ContentObserver; import android.graphics.Point; import android.graphics.Rect; import android.graphics.Region; import android.hardware.display.DisplayManager; import android.hardware.fingerprint.IFingerprintService; Loading Loading @@ -190,6 +192,9 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub private final SimpleStringSplitter mStringColonSplitter = new SimpleStringSplitter(COMPONENT_NAME_SEPARATOR); private final Rect mTempRect = new Rect(); private final Rect mTempRect1 = new Rect(); private final PackageManager mPackageManager; private final PowerManager mPowerManager; Loading Loading @@ -246,6 +251,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub //TODO: Remove this hack private boolean mInitialized; private Point mTempPoint; private boolean mIsAccessibilityButtonShown; private AccessibilityUserState getCurrentUserStateLocked() { Loading Loading @@ -1067,6 +1073,18 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub return motionEventInjector; } /** * Gets a point within the accessibility focused node where we can send down * and up events to perform a click. * * @param outPoint The click point to populate. * @return Whether accessibility a click point was found and set. */ // TODO: (multi-display) Make sure this works for multiple displays. public boolean getAccessibilityFocusClickPointInScreen(Point outPoint) { return getInteractionBridge().getAccessibilityFocusClickPointInScreenNotLocked(outPoint); } /** * Perform an accessibility action on the view that currently has accessibility focus. * Has no effect if no item has accessibility focus, if the item with accessibility Loading @@ -1081,6 +1099,32 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub return getInteractionBridge().performActionOnAccessibilityFocusedItemNotLocked(action); } /** * Returns true if accessibility focus is confined to the active window. */ public boolean accessibilityFocusOnlyInActiveWindow() { synchronized (mLock) { return mA11yWindowManager.isTrackingWindowsLocked(); } } /** * Gets the bounds of a window. * * @param outBounds The output to which to write the bounds. */ boolean getWindowBounds(int windowId, Rect outBounds) { IBinder token; synchronized (mLock) { token = getWindowToken(windowId, mCurrentUserId); } mWindowManagerService.getWindowFrame(token, outBounds); if (!outBounds.isEmpty()) { return true; } return false; } public int getActiveWindowId() { return mA11yWindowManager.getActiveWindowId(mCurrentUserId); } Loading Loading @@ -1824,9 +1868,11 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub for (int i = 0; !observingWindows && (i < boundServiceCount); i++) { AccessibilityServiceConnection boundService = boundServices.get(i); if (boundService.canRetrieveInteractiveWindowsLocked()) { userState.setAccessibilityFocusOnlyInActiveWindow(false); observingWindows = true; } } userState.setAccessibilityFocusOnlyInActiveWindow(true); // Gets all valid displays and start tracking windows of each display if there is at least // one bound service that can retrieve window content. Loading Loading @@ -2929,6 +2975,19 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub mDefaultDisplay = displayManager.getDisplay(Display.DEFAULT_DISPLAY); } /** * Gets a point within the accessibility focused node where we can send down and up events * to perform a click. * * @param outPoint The click point to populate. * @return Whether accessibility a click point was found and set. */ // TODO: (multi-display) Make sure this works for multiple displays. boolean getAccessibilityFocusClickPointInScreen(Point outPoint) { return getInteractionBridge() .getAccessibilityFocusClickPointInScreenNotLocked(outPoint); } /** * Perform an accessibility action on the view that currently has accessibility focus. * Has no effect if no item has accessibility focus, if the item with accessibility Loading @@ -2947,6 +3006,43 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub return focus.performAction(action.getId()); } public boolean getAccessibilityFocusClickPointInScreenNotLocked(Point outPoint) { AccessibilityNodeInfo focus = getAccessibilityFocusNotLocked(); if (focus == null) { return false; } synchronized (mLock) { Rect boundsInScreen = mTempRect; focus.getBoundsInScreen(boundsInScreen); // Apply magnification if needed. MagnificationSpec spec = getCompatibleMagnificationSpecLocked(focus.getWindowId()); if (spec != null && !spec.isNop()) { boundsInScreen.offset((int) -spec.offsetX, (int) -spec.offsetY); boundsInScreen.scale(1 / spec.scale); } // Clip to the window bounds. Rect windowBounds = mTempRect1; getWindowBounds(focus.getWindowId(), windowBounds); if (!boundsInScreen.intersect(windowBounds)) { return false; } // Clip to the screen bounds. Point screenSize = mTempPoint; mDefaultDisplay.getRealSize(screenSize); if (!boundsInScreen.intersect(0, 0, screenSize.x, screenSize.y)) { return false; } outPoint.set(boundsInScreen.centerX(), boundsInScreen.centerY()); } return true; } private AccessibilityNodeInfo getAccessibilityFocusNotLocked() { final int focusedWindowId; synchronized (mLock) { Loading services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java +8 −0 Original line number Diff line number Diff line Loading @@ -104,6 +104,7 @@ class AccessibilityUserState { private boolean mIsDisplayMagnificationEnabled; private boolean mIsFilterKeyEventsEnabled; private boolean mIsPerformGesturesEnabled; private boolean mAccessibilityFocusOnlyInActiveWindow; private boolean mIsTextHighContrastEnabled; private boolean mIsTouchExplorationEnabled; private boolean mServiceHandlesDoubleTap; Loading Loading @@ -685,6 +686,13 @@ class AccessibilityUserState { mIsPerformGesturesEnabled = enabled; } public boolean isAccessibilityFocusOnlyInActiveWindow() { return mAccessibilityFocusOnlyInActiveWindow; } public void setAccessibilityFocusOnlyInActiveWindow(boolean enabled) { mAccessibilityFocusOnlyInActiveWindow = enabled; } public ComponentName getServiceChangingSoftKeyboardModeLocked() { return mServiceChangingSoftKeyboardMode; } Loading Loading
core/java/android/view/MotionEvent.java +29 −0 Original line number Diff line number Diff line Loading @@ -486,6 +486,21 @@ public final class MotionEvent extends InputEvent implements Parcelable { */ public static final int FLAG_TAINTED = 0x80000000; /** * Private flag indicating that this event was synthesized by the system and should be delivered * to the accessibility focused view first. When being dispatched such an event is not handled * by predecessors of the accessibility focused view and after the event reaches that view the * flag is cleared and normal event dispatch is performed. This ensures that the platform can * click on any view that has accessibility focus which is semantically equivalent to asking the * view to perform a click accessibility action but more generic as views not implementing click * action correctly can still be activated. * * @hide * @see #isTargetAccessibilityFocus() * @see #setTargetAccessibilityFocus(boolean) */ public static final int FLAG_TARGET_ACCESSIBILITY_FOCUS = 0x40000000; /** * Flag indicating the motion event intersected the top edge of the screen. */ Loading Loading @@ -2139,6 +2154,20 @@ public final class MotionEvent extends InputEvent implements Parcelable { nativeSetFlags(mNativePtr, tainted ? flags | FLAG_TAINTED : flags & ~FLAG_TAINTED); } /** @hide */ public boolean isTargetAccessibilityFocus() { final int flags = getFlags(); return (flags & FLAG_TARGET_ACCESSIBILITY_FOCUS) != 0; } /** @hide */ public void setTargetAccessibilityFocus(boolean targetsFocus) { final int flags = getFlags(); nativeSetFlags(mNativePtr, targetsFocus ? flags | FLAG_TARGET_ACCESSIBILITY_FOCUS : flags & ~FLAG_TARGET_ACCESSIBILITY_FOCUS); } /** @hide */ public final boolean isHoverExitPending() { final int flags = getFlags(); Loading
core/java/android/view/View.java +8 −0 Original line number Diff line number Diff line Loading @@ -14274,6 +14274,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback, */ public boolean dispatchTouchEvent(MotionEvent event) { // If the event should be handled by accessibility focus first. if (event.isTargetAccessibilityFocus()) { // We don't have focus or no virtual descendant has it, do not handle the event. if (!isAccessibilityFocusedViewOrHost()) { return false; } // We have focus and got the event, then use normal event dispatch. event.setTargetAccessibilityFocus(false); } boolean result = false; if (mInputEventConsistencyVerifier != null) {
core/java/android/view/ViewGroup.java +77 −4 Original line number Diff line number Diff line Loading @@ -2048,8 +2048,26 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager for (int i = childrenCount - 1; i >= 0; i--) { final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder); final View child = getAndVerifyPreorderedView(preorderedList, children, childIndex); View childWithAccessibilityFocus = event.isTargetAccessibilityFocus() ? findChildWithAccessibilityFocus() : null; if (!child.canReceivePointerEvents() || !isTransformedTouchPointInView(x, y, child, null)) { // If there is a view that has accessibility focus we want it // to get the event first and if not handled we will perform a // normal dispatch. We may do a double iteration but this is // safer given the timeframe. if (childWithAccessibilityFocus != null) { if (childWithAccessibilityFocus != child) { continue; } childWithAccessibilityFocus = null; i = childrenCount - 1; } event.setTargetAccessibilityFocus(false); continue; } final PointerIcon pointerIcon = Loading Loading @@ -2617,6 +2635,12 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager mInputEventConsistencyVerifier.onTouchEvent(ev, 1); } // If the event targets the accessibility focused view and this is it, start // normal event dispatch. Maybe a descendant is what will handle the click. if (ev.isTargetAccessibilityFocus() && isAccessibilityFocusedViewOrHost()) { ev.setTargetAccessibilityFocus(false); } boolean handled = false; if (onFilterTouchEventForSecurity(ev)) { final int action = ev.getAction(); Loading Loading @@ -2647,6 +2671,13 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager // so this view group continues to intercept touches. intercepted = true; } // If intercepted, start normal event dispatch. Also if there is already // a view that is handling the gesture, do normal event dispatch. if (intercepted || mFirstTouchTarget != null) { ev.setTargetAccessibilityFocus(false); } // Check for cancelation. final boolean canceled = resetCancelNextUpFlag(this) || actionMasked == MotionEvent.ACTION_CANCEL; Loading @@ -2658,6 +2689,14 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager TouchTarget newTouchTarget = null; boolean alreadyDispatchedToNewTouchTarget = false; if (!canceled && !intercepted) { // If the event is targeting accessibility focus we give it to the // view that has accessibility focus and if it does not handle it // we clear the flag and dispatch the event to all children as usual. // We are looking up the accessibility focused host to avoid keeping // state since these events are very rare. View childWithAccessibilityFocus = ev.isTargetAccessibilityFocus() ? findChildWithAccessibilityFocus() : null; if (actionMasked == MotionEvent.ACTION_DOWN || (split && actionMasked == MotionEvent.ACTION_POINTER_DOWN) || actionMasked == MotionEvent.ACTION_HOVER_MOVE) { Loading Loading @@ -2720,6 +2759,10 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager alreadyDispatchedToNewTouchTarget = true; break; } // The accessibility focus didn't handle the event, so clear // the flag and do a normal dispatch to all children. ev.setTargetAccessibilityFocus(false); } if (preorderedList != null) preorderedList.clear(); } Loading Loading @@ -2803,6 +2846,34 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager return buildOrderedChildList(); } /** * Finds the child which has accessibility focus. * * @return The child that has focus. */ private View findChildWithAccessibilityFocus() { ViewRootImpl viewRoot = getViewRootImpl(); if (viewRoot == null) { return null; } View current = viewRoot.getAccessibilityFocusedHost(); if (current == null) { return null; } ViewParent parent = current.getParent(); while (parent instanceof View) { if (parent == this) { return current; } current = (View) parent; parent = current.getParent(); } return null; } /** * Resets all touch state in preparation for a new cycle. */ Loading Loading @@ -3257,9 +3328,10 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager break; } default: throw new IllegalStateException("descendant focusability must be " + "one of FOCUS_BEFORE_DESCENDANTS, FOCUS_AFTER_DESCENDANTS, FOCUS_BLOCK_DESCENDANTS " + "but is " + descendantFocusability); throw new IllegalStateException( "descendant focusability must be one of FOCUS_BEFORE_DESCENDANTS," + " FOCUS_AFTER_DESCENDANTS, FOCUS_BLOCK_DESCENDANTS but is " + descendantFocusability); } if (result && !isLayoutValid() && ((mPrivateFlags & PFLAG_WANTS_FOCUS) == 0)) { mPrivateFlags |= PFLAG_WANTS_FOCUS; Loading Loading @@ -4925,7 +4997,8 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager if (params == null) { params = generateDefaultLayoutParams(); if (params == null) { throw new IllegalArgumentException("generateDefaultLayoutParams() cannot return null"); throw new IllegalArgumentException( "generateDefaultLayoutParams() cannot return null"); } } addView(child, index, params); Loading
services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java +96 −0 Original line number Diff line number Diff line Loading @@ -56,6 +56,8 @@ import android.content.pm.PackageManagerInternal; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.database.ContentObserver; import android.graphics.Point; import android.graphics.Rect; import android.graphics.Region; import android.hardware.display.DisplayManager; import android.hardware.fingerprint.IFingerprintService; Loading Loading @@ -190,6 +192,9 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub private final SimpleStringSplitter mStringColonSplitter = new SimpleStringSplitter(COMPONENT_NAME_SEPARATOR); private final Rect mTempRect = new Rect(); private final Rect mTempRect1 = new Rect(); private final PackageManager mPackageManager; private final PowerManager mPowerManager; Loading Loading @@ -246,6 +251,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub //TODO: Remove this hack private boolean mInitialized; private Point mTempPoint; private boolean mIsAccessibilityButtonShown; private AccessibilityUserState getCurrentUserStateLocked() { Loading Loading @@ -1067,6 +1073,18 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub return motionEventInjector; } /** * Gets a point within the accessibility focused node where we can send down * and up events to perform a click. * * @param outPoint The click point to populate. * @return Whether accessibility a click point was found and set. */ // TODO: (multi-display) Make sure this works for multiple displays. public boolean getAccessibilityFocusClickPointInScreen(Point outPoint) { return getInteractionBridge().getAccessibilityFocusClickPointInScreenNotLocked(outPoint); } /** * Perform an accessibility action on the view that currently has accessibility focus. * Has no effect if no item has accessibility focus, if the item with accessibility Loading @@ -1081,6 +1099,32 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub return getInteractionBridge().performActionOnAccessibilityFocusedItemNotLocked(action); } /** * Returns true if accessibility focus is confined to the active window. */ public boolean accessibilityFocusOnlyInActiveWindow() { synchronized (mLock) { return mA11yWindowManager.isTrackingWindowsLocked(); } } /** * Gets the bounds of a window. * * @param outBounds The output to which to write the bounds. */ boolean getWindowBounds(int windowId, Rect outBounds) { IBinder token; synchronized (mLock) { token = getWindowToken(windowId, mCurrentUserId); } mWindowManagerService.getWindowFrame(token, outBounds); if (!outBounds.isEmpty()) { return true; } return false; } public int getActiveWindowId() { return mA11yWindowManager.getActiveWindowId(mCurrentUserId); } Loading Loading @@ -1824,9 +1868,11 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub for (int i = 0; !observingWindows && (i < boundServiceCount); i++) { AccessibilityServiceConnection boundService = boundServices.get(i); if (boundService.canRetrieveInteractiveWindowsLocked()) { userState.setAccessibilityFocusOnlyInActiveWindow(false); observingWindows = true; } } userState.setAccessibilityFocusOnlyInActiveWindow(true); // Gets all valid displays and start tracking windows of each display if there is at least // one bound service that can retrieve window content. Loading Loading @@ -2929,6 +2975,19 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub mDefaultDisplay = displayManager.getDisplay(Display.DEFAULT_DISPLAY); } /** * Gets a point within the accessibility focused node where we can send down and up events * to perform a click. * * @param outPoint The click point to populate. * @return Whether accessibility a click point was found and set. */ // TODO: (multi-display) Make sure this works for multiple displays. boolean getAccessibilityFocusClickPointInScreen(Point outPoint) { return getInteractionBridge() .getAccessibilityFocusClickPointInScreenNotLocked(outPoint); } /** * Perform an accessibility action on the view that currently has accessibility focus. * Has no effect if no item has accessibility focus, if the item with accessibility Loading @@ -2947,6 +3006,43 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub return focus.performAction(action.getId()); } public boolean getAccessibilityFocusClickPointInScreenNotLocked(Point outPoint) { AccessibilityNodeInfo focus = getAccessibilityFocusNotLocked(); if (focus == null) { return false; } synchronized (mLock) { Rect boundsInScreen = mTempRect; focus.getBoundsInScreen(boundsInScreen); // Apply magnification if needed. MagnificationSpec spec = getCompatibleMagnificationSpecLocked(focus.getWindowId()); if (spec != null && !spec.isNop()) { boundsInScreen.offset((int) -spec.offsetX, (int) -spec.offsetY); boundsInScreen.scale(1 / spec.scale); } // Clip to the window bounds. Rect windowBounds = mTempRect1; getWindowBounds(focus.getWindowId(), windowBounds); if (!boundsInScreen.intersect(windowBounds)) { return false; } // Clip to the screen bounds. Point screenSize = mTempPoint; mDefaultDisplay.getRealSize(screenSize); if (!boundsInScreen.intersect(0, 0, screenSize.x, screenSize.y)) { return false; } outPoint.set(boundsInScreen.centerX(), boundsInScreen.centerY()); } return true; } private AccessibilityNodeInfo getAccessibilityFocusNotLocked() { final int focusedWindowId; synchronized (mLock) { Loading
services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java +8 −0 Original line number Diff line number Diff line Loading @@ -104,6 +104,7 @@ class AccessibilityUserState { private boolean mIsDisplayMagnificationEnabled; private boolean mIsFilterKeyEventsEnabled; private boolean mIsPerformGesturesEnabled; private boolean mAccessibilityFocusOnlyInActiveWindow; private boolean mIsTextHighContrastEnabled; private boolean mIsTouchExplorationEnabled; private boolean mServiceHandlesDoubleTap; Loading Loading @@ -685,6 +686,13 @@ class AccessibilityUserState { mIsPerformGesturesEnabled = enabled; } public boolean isAccessibilityFocusOnlyInActiveWindow() { return mAccessibilityFocusOnlyInActiveWindow; } public void setAccessibilityFocusOnlyInActiveWindow(boolean enabled) { mAccessibilityFocusOnlyInActiveWindow = enabled; } public ComponentName getServiceChangingSoftKeyboardModeLocked() { return mServiceChangingSoftKeyboardMode; } Loading