summaryrefslogtreecommitdiff
path: root/services/accessibility
diff options
context:
space:
mode:
Diffstat (limited to 'services/accessibility')
-rw-r--r--services/accessibility/accessibility.aconfig46
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java315
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java93
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java301
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilitySecurityPolicy.java5
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java90
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java93
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java111
-rw-r--r--services/accessibility/java/com/android/server/accessibility/MouseKeysInterceptor.java74
-rw-r--r--services/accessibility/java/com/android/server/accessibility/ProxyAccessibilityServiceConnection.java13
-rw-r--r--services/accessibility/java/com/android/server/accessibility/ProxyManager.java78
-rw-r--r--services/accessibility/java/com/android/server/accessibility/UiAutomationManager.java93
-rw-r--r--services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java14
-rw-r--r--services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java131
-rw-r--r--services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java45
-rw-r--r--services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java89
-rw-r--r--services/accessibility/java/com/android/server/accessibility/magnification/MagnificationGestureHandler.java3
-rw-r--r--services/accessibility/java/com/android/server/accessibility/magnification/PanningScalingHandler.java11
18 files changed, 910 insertions, 695 deletions
diff --git a/services/accessibility/accessibility.aconfig b/services/accessibility/accessibility.aconfig
index ee3bbcaf711d..ad87ceaf6f38 100644
--- a/services/accessibility/accessibility.aconfig
+++ b/services/accessibility/accessibility.aconfig
@@ -45,10 +45,10 @@ flag {
}
flag {
- name: "compute_window_changes_on_a11y_v2"
+ name: "clear_shortcuts_when_activity_updates_to_service"
namespace: "accessibility"
- description: "Computes accessibility window changes in accessibility instead of wm package."
- bug: "322444245"
+ description: "When an a11y activity is updated to an a11y service, clears the associated shortcuts so that we don't skip the AccessibilityServiceWarning."
+ bug: "358092445"
metadata {
purpose: PURPOSE_BUGFIX
}
@@ -86,10 +86,17 @@ flag {
}
flag {
- name: "enable_hardware_shortcut_disables_warning"
- namespace: "accessibility"
- description: "When the user purposely enables the hardware shortcut, preemptively disables the first-time warning message."
- bug: "287065325"
+ name: "enable_hardware_shortcut_disables_warning"
+ namespace: "accessibility"
+ description: "When the user purposely enables the hardware shortcut, preemptively disables the first-time warning message."
+ bug: "287065325"
+}
+
+flag {
+ name: "enable_low_vision_hats"
+ namespace: "accessibility"
+ description: "Use HaTS for low vision feedback."
+ bug: "380346799"
}
flag {
@@ -114,10 +121,13 @@ flag {
}
flag {
- name: "enable_magnification_follows_mouse"
+ name: "enable_magnification_follows_mouse_bugfix"
namespace: "accessibility"
description: "Whether to enable mouse following for fullscreen magnification"
bug: "354696546"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
}
flag {
@@ -162,6 +172,16 @@ flag {
}
flag {
+ name: "magnification_enlarge_pointer_bugfix"
+ namespace: "accessibility"
+ description: "When fullscreen magnification is enabled, pointer icon is enlarged"
+ bug: "355734856"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
name: "manager_avoid_receiver_timeout"
namespace: "accessibility"
description: "Register receivers on background handler so they have more time to complete"
@@ -172,6 +192,16 @@ flag {
}
flag {
+ name: "package_monitor_dedicated_thread"
+ namespace: "accessibility"
+ description: "Runs the A11yManagerService PackageMonitor on a dedicated thread"
+ bug: "348138695"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
name: "manager_package_monitor_logic_fix"
namespace: "accessibility"
description: "Corrects the return values of the HandleForceStop function"
diff --git a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
index c234ee479a57..9ceca5d1dbfe 100644
--- a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
@@ -35,7 +35,6 @@ import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLICK;
import static android.view.accessibility.AccessibilityNodeInfo.ACTION_LONG_CLICK;
import static com.android.server.pm.UserManagerService.enforceCurrentUserIfVisibleBackgroundEnabled;
-import static com.android.window.flags.Flags.deleteCaptureDisplay;
import android.accessibilityservice.AccessibilityGestureEvent;
import android.accessibilityservice.AccessibilityService;
@@ -62,7 +61,6 @@ import android.graphics.ParcelableColorSpace;
import android.graphics.Region;
import android.hardware.HardwareBuffer;
import android.hardware.display.DisplayManager;
-import android.hardware.display.DisplayManagerInternal;
import android.hardware.usb.UsbDevice;
import android.os.Binder;
import android.os.Build;
@@ -104,7 +102,6 @@ import com.android.internal.inputmethod.IRemoteAccessibilityInputConnection;
import com.android.internal.os.SomeArgs;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.function.pooled.PooledLambda;
-import com.android.server.LocalServices;
import com.android.server.accessibility.AccessibilityWindowManager.RemoteAccessibilityConnection;
import com.android.server.accessibility.magnification.MagnificationProcessor;
import com.android.server.wm.WindowManagerInternal;
@@ -165,16 +162,27 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
protected final AccessibilitySecurityPolicy mSecurityPolicy;
protected final AccessibilityTrace mTrace;
- // The attribution tag set by the service that is bound to this instance
+ /** The attribution tag set by the client that is bound to this instance */
protected String mAttributionTag;
protected int mDisplayTypes = DISPLAY_TYPE_DEFAULT;
- // The service that's bound to this instance. Whenever this value is non-null, this
- // object is registered as a death recipient
- IBinder mService;
+ /**
+ * Binder of the {@link #mClient}.
+ *
+ * <p>Whenever this value is non-null, it should be registered as a {@link
+ * IBinder.DeathRecipient}
+ */
+ @Nullable IBinder mClientBinder;
- IAccessibilityServiceClient mServiceInterface;
+ /**
+ * The accessibility client this class represents.
+ *
+ * <p>The client is in the application process, i.e., it's a client of system_server. Depending
+ * on the use case, the client can be an {@link AccessibilityService}, a {@code UiAutomation},
+ * etc.
+ */
+ @Nullable IAccessibilityServiceClient mClient;
int mEventTypes;
@@ -218,10 +226,10 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
int mGenericMotionEventSources;
int mObservedMotionEventSources;
- // the events pending events to be dispatched to this service
+ /** Pending events to be dispatched to the client */
final SparseArray<AccessibilityEvent> mPendingEvents = new SparseArray<>();
- /** Whether this service relies on its {@link AccessibilityCache} being up to date */
+ /** Whether the client relies on its {@link AccessibilityCache} being up to date */
boolean mUsesAccessibilityCache = false;
// Handler only for dispatching accessibility events since we use event
@@ -230,7 +238,7 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
final SparseArray<IBinder> mOverlayWindowTokens = new SparseArray();
- // All the embedded accessibility overlays that have been added by this service.
+ /** All the embedded accessibility overlays that have been added by the client. */
private List<SurfaceControl> mOverlays = new ArrayList<>();
/** The timestamp of requesting to take screenshot in milliseconds */
@@ -274,7 +282,8 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
/**
* Called back to notify system that the client has changed
- * @param serviceInfoChanged True if the service's AccessibilityServiceInfo changed.
+ *
+ * @param serviceInfoChanged True if the client's AccessibilityServiceInfo changed.
*/
void onClientChangeLocked(boolean serviceInfoChanged);
@@ -360,21 +369,22 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
mIPlatformCompat = IPlatformCompat.Stub.asInterface(
ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE));
- mEventDispatchHandler = new Handler(mainHandler.getLooper()) {
- @Override
- public void handleMessage(Message message) {
- final int eventType = message.what;
- AccessibilityEvent event = (AccessibilityEvent) message.obj;
- boolean serviceWantsEvent = message.arg1 != 0;
- notifyAccessibilityEventInternal(eventType, event, serviceWantsEvent);
- }
- };
+ mEventDispatchHandler =
+ new Handler(mainHandler.getLooper()) {
+ @Override
+ public void handleMessage(Message message) {
+ final int eventType = message.what;
+ AccessibilityEvent event = (AccessibilityEvent) message.obj;
+ boolean clientWantsEvent = message.arg1 != 0;
+ notifyAccessibilityEventInternal(eventType, event, clientWantsEvent);
+ }
+ };
setDynamicallyConfigurableProperties(accessibilityServiceInfo);
}
@Override
public boolean onKeyEvent(KeyEvent keyEvent, int sequenceNumber) {
- if (!mRequestFilterKeyEvents || (mServiceInterface == null)) {
+ if (!mRequestFilterKeyEvents || (mClient == null)) {
return false;
}
if((mAccessibilityServiceInfo.getCapabilities()
@@ -388,7 +398,7 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
if (svcClientTracingEnabled()) {
logTraceSvcClient("onKeyEvent", keyEvent + ", " + sequenceNumber);
}
- mServiceInterface.onKeyEvent(keyEvent, sequenceNumber);
+ mClient.onKeyEvent(keyEvent, sequenceNumber);
} catch (RemoteException e) {
return false;
}
@@ -470,7 +480,7 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
}
public boolean canReceiveEventsLocked() {
- return (mEventTypes != 0 && mService != null);
+ return (mEventTypes != 0 && mClientBinder != null);
}
@RequiresNoPermission
@@ -520,7 +530,7 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
final long identity = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
- // If the XML manifest had data to configure the service its info
+ // If the XML manifest had data to configure the AccessibilityService, its info
// should be already set. In such a case update only the dynamically
// configurable properties.
boolean oldRequestIme = mRequestImeApis;
@@ -1500,68 +1510,31 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
return;
}
final long identity = Binder.clearCallingIdentity();
- if (deleteCaptureDisplay()) {
- try {
- ScreenCapture.ScreenCaptureListener screenCaptureListener = new
- ScreenCapture.ScreenCaptureListener(
- (screenshotBuffer, result) -> {
- if (screenshotBuffer != null && result == 0) {
- sendScreenshotSuccess(screenshotBuffer, callback);
- } else {
- sendScreenshotFailure(
- AccessibilityService.ERROR_TAKE_SCREENSHOT_INVALID_DISPLAY,
- callback);
- }
+ try {
+ ScreenCapture.ScreenCaptureListener screenCaptureListener = new
+ ScreenCapture.ScreenCaptureListener(
+ (screenshotBuffer, result) -> {
+ if (screenshotBuffer != null && result == 0) {
+ sendScreenshotSuccess(screenshotBuffer, callback);
+ } else {
+ sendScreenshotFailure(
+ AccessibilityService.ERROR_TAKE_SCREENSHOT_INVALID_DISPLAY,
+ callback);
}
- );
- mWindowManagerService.captureDisplay(displayId, null, screenCaptureListener);
- } catch (Exception e) {
- sendScreenshotFailure(AccessibilityService.ERROR_TAKE_SCREENSHOT_INVALID_DISPLAY,
- callback);
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
- } else {
- try {
- mMainHandler.post(PooledLambda.obtainRunnable((nonArg) -> {
- final ScreenshotHardwareBuffer screenshotBuffer = LocalServices
- .getService(DisplayManagerInternal.class).userScreenshot(displayId);
- if (screenshotBuffer != null) {
- sendScreenshotSuccess(screenshotBuffer, callback);
- } else {
- sendScreenshotFailure(
- AccessibilityService.ERROR_TAKE_SCREENSHOT_INVALID_DISPLAY,
- callback);
}
- }, null).recycleOnUse());
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
+ );
+ mWindowManagerService.captureDisplay(displayId, null, screenCaptureListener);
+ } catch (Exception e) {
+ sendScreenshotFailure(AccessibilityService.ERROR_TAKE_SCREENSHOT_INVALID_DISPLAY,
+ callback);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
}
}
private void sendScreenshotSuccess(ScreenshotHardwareBuffer screenshotBuffer,
RemoteCallback callback) {
- if (deleteCaptureDisplay()) {
- mMainHandler.post(PooledLambda.obtainRunnable((nonArg) -> {
- final HardwareBuffer hardwareBuffer = screenshotBuffer.getHardwareBuffer();
- final ParcelableColorSpace colorSpace =
- new ParcelableColorSpace(screenshotBuffer.getColorSpace());
-
- final Bundle payload = new Bundle();
- payload.putInt(KEY_ACCESSIBILITY_SCREENSHOT_STATUS,
- AccessibilityService.TAKE_SCREENSHOT_SUCCESS);
- payload.putParcelable(KEY_ACCESSIBILITY_SCREENSHOT_HARDWAREBUFFER,
- hardwareBuffer);
- payload.putParcelable(KEY_ACCESSIBILITY_SCREENSHOT_COLORSPACE, colorSpace);
- payload.putLong(KEY_ACCESSIBILITY_SCREENSHOT_TIMESTAMP,
- SystemClock.uptimeMillis());
-
- // Send back the result.
- callback.sendResult(payload);
- hardwareBuffer.close();
- }, null).recycleOnUse());
- } else {
+ mMainHandler.post(PooledLambda.obtainRunnable((nonArg) -> {
final HardwareBuffer hardwareBuffer = screenshotBuffer.getHardwareBuffer();
final ParcelableColorSpace colorSpace =
new ParcelableColorSpace(screenshotBuffer.getColorSpace());
@@ -1578,7 +1551,7 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
// Send back the result.
callback.sendResult(payload);
hardwareBuffer.close();
- }
+ }, null).recycleOnUse());
}
private void sendScreenshotFailure(@AccessibilityService.ScreenshotErrorCode int errorCode,
@@ -1745,40 +1718,40 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
try {
// Clear the proxy in the other process so this
// IAccessibilityServiceConnection can be garbage collected.
- if (mServiceInterface != null) {
+ if (mClient != null) {
if (svcClientTracingEnabled()) {
logTraceSvcClient("init", "null, " + mId + ", null");
}
- mServiceInterface.init(null, mId, null);
+ mClient.init(null, mId, null);
}
} catch (RemoteException re) {
/* ignore */
}
- if (mService != null) {
+ if (mClientBinder != null) {
try {
- mService.unlinkToDeath(this, 0);
+ mClientBinder.unlinkToDeath(this, 0);
} catch (NoSuchElementException e) {
Slog.e(LOG_TAG, "Failed unregistering death link");
}
- mService = null;
+ mClientBinder = null;
}
- mServiceInterface = null;
+ mClient = null;
mReceivedAccessibilityButtonCallbackSinceBind = false;
}
public boolean isConnectedLocked() {
- return (mService != null);
+ return (mClientBinder != null);
}
public void notifyAccessibilityEvent(AccessibilityEvent event) {
synchronized (mLock) {
final int eventType = event.getEventType();
- final boolean serviceWantsEvent = wantsEventLocked(event);
+ final boolean clientWantsEvent = clientWantsEventLocked(event);
final boolean requiredForCacheConsistency = mUsesAccessibilityCache
&& ((AccessibilityCache.CACHE_CRITICAL_EVENTS_MASK & eventType) != 0);
- if (!serviceWantsEvent && !requiredForCacheConsistency) {
+ if (!clientWantsEvent && !requiredForCacheConsistency) {
return;
}
@@ -1786,7 +1759,7 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
return;
}
// Make a copy since during dispatch it is possible the event to
- // be modified to remove its source if the receiving service does
+ // be modified to remove its source if the receiving client does
// not have permission to access the window content.
AccessibilityEvent newEvent = AccessibilityEvent.obtain(event);
Message message;
@@ -1804,22 +1777,20 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
// Send all messages, bypassing mPendingEvents
message = mEventDispatchHandler.obtainMessage(eventType, newEvent);
}
- message.arg1 = serviceWantsEvent ? 1 : 0;
+ message.arg1 = clientWantsEvent ? 1 : 0;
mEventDispatchHandler.sendMessageDelayed(message, mNotificationTimeout);
}
}
/**
- * Determines if given event can be dispatched to a service based on the package of the
- * event source. Specifically, a service is notified if it is interested in events from the
- * package.
+ * Determines if given event can be dispatched to a client based on the package of the event
+ * source. Specifically, a client is notified if it is interested in events from the package.
*
* @param event The event.
- * @return True if the listener should be notified, false otherwise.
+ * @return True if the client should be notified, false otherwise.
*/
- private boolean wantsEventLocked(AccessibilityEvent event) {
-
+ private boolean clientWantsEventLocked(AccessibilityEvent event) {
if (!canReceiveEventsLocked()) {
return false;
}
@@ -1850,22 +1821,20 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
}
/**
- * Notifies an accessibility service client for a scheduled event given the event type.
+ * Notifies a client for a scheduled event given the event type.
*
* @param eventType The type of the event to dispatch.
*/
private void notifyAccessibilityEventInternal(
- int eventType,
- AccessibilityEvent event,
- boolean serviceWantsEvent) {
- IAccessibilityServiceClient listener;
+ int eventType, AccessibilityEvent event, boolean clientWantsEvent) {
+ IAccessibilityServiceClient client;
synchronized (mLock) {
- listener = mServiceInterface;
+ client = mClient;
- // If the service died/was disabled while the message for dispatching
- // the accessibility event was propagating the listener may be null.
- if (listener == null) {
+ // If the client (in the application process) died/was disabled while the message for
+ // dispatching the accessibility event was propagating, "client" may be null.
+ if (client == null) {
return;
}
@@ -1880,7 +1849,7 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
// 1) A binder thread calls notifyAccessibilityServiceDelayedLocked
// which posts a message for dispatching an event and stores the event
// in mPendingEvents.
- // 2) The message is pulled from the queue by the handler on the service
+ // 2) The message is pulled from the queue by the handler on the client
// thread and this method is just about to acquire the lock.
// 3) Another binder thread acquires the lock in notifyAccessibilityEvent
// 4) notifyAccessibilityEvent recycles the event that this method was about
@@ -1888,7 +1857,7 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
// 5) This method grabs the new event, processes it, and removes it from
// mPendingEvents
// 6) The second message dispatched in (4) arrives, but the event has been
- // remvoved in (5).
+ // removed in (5).
event = mPendingEvents.get(eventType);
if (event == null) {
return;
@@ -1905,14 +1874,14 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
try {
if (svcClientTracingEnabled()) {
- logTraceSvcClient("onAccessibilityEvent", event + ";" + serviceWantsEvent);
+ logTraceSvcClient("onAccessibilityEvent", event + ";" + clientWantsEvent);
}
- listener.onAccessibilityEvent(event, serviceWantsEvent);
+ client.onAccessibilityEvent(event, clientWantsEvent);
if (DEBUG) {
- Slog.i(LOG_TAG, "Event " + event + " sent to " + listener);
+ Slog.i(LOG_TAG, "Event " + event + " sent to " + client);
}
} catch (RemoteException re) {
- Slog.e(LOG_TAG, "Error during sending " + event + " to " + listener, re);
+ Slog.e(LOG_TAG, "Error during sending " + event + " to " + client, re);
} finally {
event.recycle();
}
@@ -1990,122 +1959,126 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
return (mGenericMotionEventSources & eventSourceWithoutClass) != 0;
}
-
/**
- * Called by the invocation handler to notify the service that the
- * state of magnification has changed.
+ * Called by the invocation handler to notify the client that the state of magnification has
+ * changed.
*/
- private void notifyMagnificationChangedInternal(int displayId, @NonNull Region region,
- @NonNull MagnificationConfig config) {
- final IAccessibilityServiceClient listener = getServiceInterfaceSafely();
- if (listener != null) {
+ private void notifyMagnificationChangedInternal(
+ int displayId, @NonNull Region region, @NonNull MagnificationConfig config) {
+ final IAccessibilityServiceClient client = getClientSafely();
+ if (client != null) {
try {
if (svcClientTracingEnabled()) {
logTraceSvcClient("onMagnificationChanged", displayId + ", " + region + ", "
+ config.toString());
}
- listener.onMagnificationChanged(displayId, region, config);
+ client.onMagnificationChanged(displayId, region, config);
} catch (RemoteException re) {
- Slog.e(LOG_TAG, "Error sending magnification changes to " + mService, re);
+ Slog.e(LOG_TAG, "Error sending magnification changes to " + mClientBinder, re);
}
}
}
/**
- * Called by the invocation handler to notify the service that the state of the soft
- * keyboard show mode has changed.
+ * Called by the invocation handler to notify the client that the state of the soft keyboard
+ * show mode has changed.
*/
private void notifySoftKeyboardShowModeChangedInternal(int showState) {
- final IAccessibilityServiceClient listener = getServiceInterfaceSafely();
- if (listener != null) {
+ final IAccessibilityServiceClient client = getClientSafely();
+ if (client != null) {
try {
if (svcClientTracingEnabled()) {
logTraceSvcClient("onSoftKeyboardShowModeChanged", String.valueOf(showState));
}
- listener.onSoftKeyboardShowModeChanged(showState);
+ client.onSoftKeyboardShowModeChanged(showState);
} catch (RemoteException re) {
- Slog.e(LOG_TAG, "Error sending soft keyboard show mode changes to " + mService,
+ Slog.e(
+ LOG_TAG,
+ "Error sending soft keyboard show mode changes to " + mClientBinder,
re);
}
}
}
private void notifyAccessibilityButtonClickedInternal(int displayId) {
- final IAccessibilityServiceClient listener = getServiceInterfaceSafely();
- if (listener != null) {
+ final IAccessibilityServiceClient client = getClientSafely();
+ if (client != null) {
try {
if (svcClientTracingEnabled()) {
logTraceSvcClient("onAccessibilityButtonClicked", String.valueOf(displayId));
}
- listener.onAccessibilityButtonClicked(displayId);
+ client.onAccessibilityButtonClicked(displayId);
} catch (RemoteException re) {
- Slog.e(LOG_TAG, "Error sending accessibility button click to " + mService, re);
+ Slog.e(LOG_TAG, "Error sending accessibility button click to " + mClientBinder, re);
}
}
}
private void notifyAccessibilityButtonAvailabilityChangedInternal(boolean available) {
- // Only notify the service if it's not been notified or the state has changed
+ // Only notify the client if it's not been notified or the state has changed
if (mReceivedAccessibilityButtonCallbackSinceBind
&& (mLastAccessibilityButtonCallbackState == available)) {
return;
}
mReceivedAccessibilityButtonCallbackSinceBind = true;
mLastAccessibilityButtonCallbackState = available;
- final IAccessibilityServiceClient listener = getServiceInterfaceSafely();
- if (listener != null) {
+ final IAccessibilityServiceClient client = getClientSafely();
+ if (client != null) {
try {
if (svcClientTracingEnabled()) {
logTraceSvcClient("onAccessibilityButtonAvailabilityChanged",
String.valueOf(available));
}
- listener.onAccessibilityButtonAvailabilityChanged(available);
+ client.onAccessibilityButtonAvailabilityChanged(available);
} catch (RemoteException re) {
- Slog.e(LOG_TAG,
- "Error sending accessibility button availability change to " + mService,
+ Slog.e(
+ LOG_TAG,
+ "Error sending accessibility button availability change to "
+ + mClientBinder,
re);
}
}
}
private void notifyGestureInternal(AccessibilityGestureEvent gestureInfo) {
- final IAccessibilityServiceClient listener = getServiceInterfaceSafely();
- if (listener != null) {
+ final IAccessibilityServiceClient client = getClientSafely();
+ if (client != null) {
try {
if (svcClientTracingEnabled()) {
logTraceSvcClient("onGesture", gestureInfo.toString());
}
- listener.onGesture(gestureInfo);
+ client.onGesture(gestureInfo);
} catch (RemoteException re) {
- Slog.e(LOG_TAG, "Error during sending gesture " + gestureInfo
- + " to " + mService, re);
+ Slog.e(
+ LOG_TAG,
+ "Error during sending gesture " + gestureInfo + " to " + mClientBinder,
+ re);
}
}
}
private void notifySystemActionsChangedInternal() {
- final IAccessibilityServiceClient listener = getServiceInterfaceSafely();
- if (listener != null) {
+ final IAccessibilityServiceClient client = getClientSafely();
+ if (client != null) {
try {
if (svcClientTracingEnabled()) {
logTraceSvcClient("onSystemActionsChanged", "");
}
- listener.onSystemActionsChanged();
+ client.onSystemActionsChanged();
} catch (RemoteException re) {
- Slog.e(LOG_TAG, "Error sending system actions change to " + mService,
- re);
+ Slog.e(LOG_TAG, "Error sending system actions change to " + mClientBinder, re);
}
}
}
private void notifyClearAccessibilityCacheInternal() {
- final IAccessibilityServiceClient listener = getServiceInterfaceSafely();
- if (listener != null) {
+ final IAccessibilityServiceClient client = getClientSafely();
+ if (client != null) {
try {
if (svcClientTracingEnabled()) {
logTraceSvcClient("clearAccessibilityCache", "");
}
- listener.clearAccessibilityCache();
+ client.clearAccessibilityCache();
} catch (RemoteException re) {
Slog.e(LOG_TAG, "Error during requesting accessibility info cache"
+ " to be cleared.", re);
@@ -2118,70 +2091,66 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
private void setImeSessionEnabledInternal(IAccessibilityInputMethodSession session,
boolean enabled) {
- final IAccessibilityServiceClient listener = getServiceInterfaceSafely();
- if (listener != null && session != null) {
+ final IAccessibilityServiceClient client = getClientSafely();
+ if (client != null && session != null) {
try {
if (svcClientTracingEnabled()) {
logTraceSvcClient("createImeSession", "");
}
- listener.setImeSessionEnabled(session, enabled);
+ client.setImeSessionEnabled(session, enabled);
} catch (RemoteException re) {
- Slog.e(LOG_TAG,
- "Error requesting IME session from " + mService, re);
+ Slog.e(LOG_TAG, "Error requesting IME session from " + mClientBinder, re);
}
}
}
private void bindInputInternal() {
- final IAccessibilityServiceClient listener = getServiceInterfaceSafely();
- if (listener != null) {
+ final IAccessibilityServiceClient client = getClientSafely();
+ if (client != null) {
try {
if (svcClientTracingEnabled()) {
logTraceSvcClient("bindInput", "");
}
- listener.bindInput();
+ client.bindInput();
} catch (RemoteException re) {
- Slog.e(LOG_TAG,
- "Error binding input to " + mService, re);
+ Slog.e(LOG_TAG, "Error binding input to " + mClientBinder, re);
}
}
}
private void unbindInputInternal() {
- final IAccessibilityServiceClient listener = getServiceInterfaceSafely();
- if (listener != null) {
+ final IAccessibilityServiceClient client = getClientSafely();
+ if (client != null) {
try {
if (svcClientTracingEnabled()) {
logTraceSvcClient("unbindInput", "");
}
- listener.unbindInput();
+ client.unbindInput();
} catch (RemoteException re) {
- Slog.e(LOG_TAG,
- "Error unbinding input to " + mService, re);
+ Slog.e(LOG_TAG, "Error unbinding input to " + mClientBinder, re);
}
}
}
private void startInputInternal(IRemoteAccessibilityInputConnection connection,
EditorInfo editorInfo, boolean restarting) {
- final IAccessibilityServiceClient listener = getServiceInterfaceSafely();
- if (listener != null) {
+ final IAccessibilityServiceClient client = getClientSafely();
+ if (client != null) {
try {
if (svcClientTracingEnabled()) {
logTraceSvcClient("startInput", "editorInfo=" + editorInfo
+ " restarting=" + restarting);
}
- listener.startInput(connection, editorInfo, restarting);
+ client.startInput(connection, editorInfo, restarting);
} catch (RemoteException re) {
- Slog.e(LOG_TAG,
- "Error starting input to " + mService, re);
+ Slog.e(LOG_TAG, "Error starting input to " + mClientBinder, re);
}
}
}
- protected IAccessibilityServiceClient getServiceInterfaceSafely() {
+ protected IAccessibilityServiceClient getClientSafely() {
synchronized (mLock) {
- return mServiceInterface;
+ return mClient;
}
}
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
index 617cca9d3075..e1b6c9c5aa42 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
@@ -27,6 +27,8 @@ import android.annotation.NonNull;
import android.content.Context;
import android.graphics.Region;
import android.hardware.input.InputManager;
+import android.hardware.input.KeyGestureEvent;
+import android.os.IBinder;
import android.os.Looper;
import android.os.PowerManager;
import android.os.SystemClock;
@@ -44,11 +46,14 @@ import android.view.MotionEvent.PointerCoords;
import android.view.MotionEvent.PointerProperties;
import android.view.accessibility.AccessibilityEvent;
+import androidx.annotation.Nullable;
+
import com.android.server.LocalServices;
import com.android.server.accessibility.gestures.TouchExplorer;
import com.android.server.accessibility.magnification.FullScreenMagnificationController;
import com.android.server.accessibility.magnification.FullScreenMagnificationGestureHandler;
import com.android.server.accessibility.magnification.FullScreenMagnificationVibrationHelper;
+import com.android.server.accessibility.magnification.MagnificationController;
import com.android.server.accessibility.magnification.MagnificationGestureHandler;
import com.android.server.accessibility.magnification.MouseEventHandler;
import com.android.server.accessibility.magnification.WindowMagnificationGestureHandler;
@@ -187,6 +192,8 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo
private final AccessibilityManagerService mAms;
+ private final InputManager mInputManager;
+
private final SparseArray<EventStreamTransformation> mEventHandler;
private final SparseArray<TouchExplorer> mTouchExplorer = new SparseArray<>(0);
@@ -228,6 +235,47 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo
*/
private MotionEvent mLastActiveDeviceMotionEvent = null;
+ private boolean mKeyGestureEventHandlerInstalled = false;
+ private InputManager.KeyGestureEventHandler mKeyGestureEventHandler =
+ new InputManager.KeyGestureEventHandler() {
+ @Override
+ public boolean handleKeyGestureEvent(
+ @NonNull KeyGestureEvent event,
+ @Nullable IBinder focusedToken) {
+ final boolean complete =
+ event.getAction() == KeyGestureEvent.ACTION_GESTURE_COMPLETE
+ && !event.isCancelled();
+ final int gestureType = event.getKeyGestureType();
+ final int displayId = isDisplayIdValid(event.getDisplayId())
+ ? event.getDisplayId() : Display.DEFAULT_DISPLAY;
+
+ switch (gestureType) {
+ case KeyGestureEvent.KEY_GESTURE_TYPE_MAGNIFIER_ZOOM_IN:
+ if (complete) {
+ mAms.getMagnificationController().scaleMagnificationByStep(
+ displayId, MagnificationController.ZOOM_DIRECTION_IN);
+ }
+ return true;
+ case KeyGestureEvent.KEY_GESTURE_TYPE_MAGNIFIER_ZOOM_OUT:
+ if (complete) {
+ mAms.getMagnificationController().scaleMagnificationByStep(
+ displayId, MagnificationController.ZOOM_DIRECTION_OUT);
+ }
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public boolean isKeyGestureSupported(int gestureType) {
+ return switch (gestureType) {
+ case KeyGestureEvent.KEY_GESTURE_TYPE_MAGNIFIER_ZOOM_IN,
+ KeyGestureEvent.KEY_GESTURE_TYPE_MAGNIFIER_ZOOM_OUT -> true;
+ default -> false;
+ };
+ }
+ };
+
private static MotionEvent cancelMotion(MotionEvent event) {
if (event.getActionMasked() == MotionEvent.ACTION_CANCEL
|| event.getActionMasked() == MotionEvent.ACTION_HOVER_EXIT
@@ -287,6 +335,7 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo
mContext = context;
mAms = service;
mPm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
+ mInputManager = context.getSystemService(InputManager.class);
mEventHandler = eventHandler;
}
@@ -360,10 +409,6 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo
final int eventSource = event.getSource();
final int displayId = event.getDisplayId();
if ((policyFlags & WindowManagerPolicy.FLAG_PASS_TO_USER) == 0) {
- if (!Flags.doNotResetKeyEventState()) {
- state.reset();
- clearEventStreamHandler(displayId, eventSource);
- }
if (DEBUG) {
Slog.d(TAG, "Not processing event " + event);
}
@@ -723,6 +768,12 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo
createMagnificationGestureHandler(displayId, displayContext);
addFirstEventHandler(displayId, magnificationGestureHandler);
mMagnificationGestureHandler.put(displayId, magnificationGestureHandler);
+
+ if (com.android.hardware.input.Flags.enableTalkbackAndMagnifierKeyGestures()
+ && !mKeyGestureEventHandlerInstalled) {
+ mInputManager.registerKeyGestureEventHandler(mKeyGestureEventHandler);
+ mKeyGestureEventHandlerInstalled = true;
+ }
}
if ((mEnabledFeatures & FLAG_FEATURE_INJECT_MOTION_EVENTS) != 0) {
@@ -842,6 +893,11 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo
mMouseKeysInterceptor.onDestroy();
mMouseKeysInterceptor = null;
}
+
+ if (mKeyGestureEventHandlerInstalled) {
+ mInputManager.unregisterKeyGestureEventHandler(mKeyGestureEventHandler);
+ mKeyGestureEventHandlerInstalled = false;
+ }
}
private MagnificationGestureHandler createMagnificationGestureHandler(
@@ -1120,18 +1176,8 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo
}
private boolean anyServiceWantsGenericMotionEvent(MotionEvent event) {
- if (Flags.alwaysAllowObservingTouchEvents()) {
- final boolean isTouchEvent = event.isFromSource(InputDevice.SOURCE_TOUCHSCREEN);
- if (isTouchEvent && !canShareGenericTouchEvent()) {
- return false;
- }
- final int eventSourceWithoutClass = event.getSource() & ~InputDevice.SOURCE_CLASS_MASK;
- return (mCombinedGenericMotionEventSources & eventSourceWithoutClass) != 0;
- }
- // Disable SOURCE_TOUCHSCREEN generic event interception if any service is performing
- // touch exploration.
- if (event.isFromSource(InputDevice.SOURCE_TOUCHSCREEN)
- && (mEnabledFeatures & FLAG_FEATURE_TOUCH_EXPLORATION) != 0) {
+ final boolean isTouchEvent = event.isFromSource(InputDevice.SOURCE_TOUCHSCREEN);
+ if (isTouchEvent && !canShareGenericTouchEvent()) {
return false;
}
final int eventSourceWithoutClass = event.getSource() & ~InputDevice.SOURCE_CLASS_MASK;
@@ -1139,21 +1185,8 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo
}
private boolean anyServiceWantsToObserveMotionEvent(MotionEvent event) {
- if (Flags.alwaysAllowObservingTouchEvents()) {
- final int eventSourceWithoutClass = event.getSource() & ~InputDevice.SOURCE_CLASS_MASK;
- return (mCombinedMotionEventObservedSources & eventSourceWithoutClass) != 0;
- }
- // Disable SOURCE_TOUCHSCREEN generic event interception if any service is performing
- // touch exploration.
- if (event.isFromSource(InputDevice.SOURCE_TOUCHSCREEN)
- && (mEnabledFeatures & FLAG_FEATURE_TOUCH_EXPLORATION) != 0) {
- return false;
- }
final int eventSourceWithoutClass = event.getSource() & ~InputDevice.SOURCE_CLASS_MASK;
- return (mCombinedGenericMotionEventSources
- & mCombinedMotionEventObservedSources
- & eventSourceWithoutClass)
- != 0;
+ return (mCombinedMotionEventObservedSources & eventSourceWithoutClass) != 0;
}
private boolean canShareGenericTouchEvent() {
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 49f15e46894d..5c1ad74fac93 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -42,9 +42,11 @@ import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_FLOATIN
import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_GESTURE;
import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR;
import static android.provider.Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED;
+import static android.view.Display.INVALID_DISPLAY;
import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL;
import static android.view.accessibility.AccessibilityManager.FlashNotificationReason;
+import static com.android.hardware.input.Flags.enableTalkbackAndMagnifierKeyGestures;
import static com.android.hardware.input.Flags.keyboardA11yMouseKeys;
import static com.android.internal.accessibility.AccessibilityShortcutController.ACCESSIBILITY_HEARING_AIDS_COMPONENT_NAME;
import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_COMPONENT_NAME;
@@ -52,8 +54,10 @@ import static com.android.internal.accessibility.AccessibilityShortcutController
import static com.android.internal.accessibility.common.ShortcutConstants.CHOOSER_PACKAGE_NAME;
import static com.android.internal.accessibility.common.ShortcutConstants.USER_SHORTCUT_TYPES;
import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType;
+import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.ALL;
import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.GESTURE;
import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.HARDWARE;
+import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.KEY_GESTURE;
import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.QUICK_SETTINGS;
import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.SOFTWARE;
import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.TRIPLETAP;
@@ -110,12 +114,15 @@ import android.graphics.Rect;
import android.graphics.Region;
import android.hardware.display.DisplayManager;
import android.hardware.fingerprint.IFingerprintService;
+import android.hardware.input.InputManager;
+import android.hardware.input.KeyGestureEvent;
import android.media.AudioManagerInternal;
import android.net.Uri;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
+import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
@@ -336,6 +343,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
private AlertDialog mEnableTouchExplorationDialog;
+ private final InputManager mInputManager;
+
private AccessibilityInputFilter mInputFilter;
private boolean mHasInputFilter;
@@ -501,6 +510,25 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
}
}
+ private InputManager.KeyGestureEventHandler mKeyGestureEventHandler =
+ new InputManager.KeyGestureEventHandler() {
+ @Override
+ public boolean handleKeyGestureEvent(
+ @NonNull KeyGestureEvent event,
+ @Nullable IBinder focusedToken) {
+ return AccessibilityManagerService.this.handleKeyGestureEvent(event);
+ }
+
+ @Override
+ public boolean isKeyGestureSupported(int gestureType) {
+ return switch (gestureType) {
+ case KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_MAGNIFICATION,
+ KeyGestureEvent.KEY_GESTURE_TYPE_ACTIVATE_SELECT_TO_SPEAK -> true;
+ default -> false;
+ };
+ }
+ };
+
@VisibleForTesting
AccessibilityManagerService(
Context context,
@@ -540,6 +568,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
mUmi = LocalServices.getService(UserManagerInternal.class);
// TODO(b/255426725): not used on tests
mVisibleBgUserIds = null;
+ mInputManager = context.getSystemService(InputManager.class);
init();
}
@@ -581,6 +610,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
mUiAutomationManager, this);
mFlashNotificationsController = new FlashNotificationsController(mContext);
mUmi = LocalServices.getService(UserManagerInternal.class);
+ mInputManager = context.getSystemService(InputManager.class);
if (UserManager.isVisibleBackgroundUsersEnabled()) {
mVisibleBgUserIds = new SparseBooleanArray();
@@ -597,6 +627,9 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
registerBroadcastReceivers();
new AccessibilityContentObserver(mMainHandler).register(
mContext.getContentResolver());
+ if (enableTalkbackAndMagnifierKeyGestures()) {
+ mInputManager.registerKeyGestureEventHandler(mKeyGestureEventHandler);
+ }
disableAccessibilityMenuToMigrateIfNeeded();
}
@@ -638,6 +671,79 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
return mIsAccessibilityButtonShown;
}
+ @VisibleForTesting
+ boolean handleKeyGestureEvent(KeyGestureEvent event) {
+ final boolean complete =
+ event.getAction() == KeyGestureEvent.ACTION_GESTURE_COMPLETE
+ && !event.isCancelled();
+ final int gestureType = event.getKeyGestureType();
+ if (!complete) {
+ return false;
+ }
+
+ String targetName;
+ switch (gestureType) {
+ case KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_MAGNIFICATION:
+ targetName = MAGNIFICATION_CONTROLLER_NAME;
+ break;
+ case KeyGestureEvent.KEY_GESTURE_TYPE_ACTIVATE_SELECT_TO_SPEAK:
+ targetName = mContext.getString(R.string.config_defaultSelectToSpeakService);
+ if (targetName.isEmpty()) {
+ return false;
+ }
+
+ final ComponentName targetServiceComponent = TextUtils.isEmpty(targetName)
+ ? null : ComponentName.unflattenFromString(targetName);
+ AccessibilityServiceInfo accessibilityServiceInfo;
+ synchronized (mLock) {
+ AccessibilityUserState userState = getCurrentUserStateLocked();
+ accessibilityServiceInfo =
+ userState.getInstalledServiceInfoLocked(targetServiceComponent);
+ }
+ if (accessibilityServiceInfo == null) {
+ return false;
+ }
+
+ // Skip enabling if a warning dialog is required for the feature.
+ // TODO(b/377752960): Explore better options to instead show the warning dialog
+ // in this scenario.
+ if (isAccessibilityServiceWarningRequired(accessibilityServiceInfo)) {
+ Slog.w(LOG_TAG,
+ "Accessibility warning is required before this service can be "
+ + "activated automatically via KEY_GESTURE shortcut.");
+ return false;
+ }
+ break;
+ default:
+ return false;
+ }
+
+ List<String> shortcutTargets = getAccessibilityShortcutTargets(
+ KEY_GESTURE);
+ if (!shortcutTargets.contains(targetName)) {
+ int userId;
+ synchronized (mLock) {
+ userId = mCurrentUserId;
+ }
+ // TODO(b/377752960): Add dialog to confirm enabling the service and to
+ // activate the first time.
+ enableShortcutForTargets(true, UserShortcutType.KEY_GESTURE,
+ List.of(targetName), userId);
+
+ // Do not perform action on first press since it was just registered. Eventually,
+ // this will be a separate dialog that appears that requires the user to confirm
+ // which will resolve this race condition. For now, just require two presses the
+ // first time it is activated.
+ return true;
+ }
+
+ final int displayId = event.getDisplayId() != INVALID_DISPLAY
+ ? event.getDisplayId() : getLastNonProxyTopFocusedDisplayId();
+ performAccessibilityShortcutInternal(displayId, KEY_GESTURE, targetName);
+
+ return true;
+ }
+
@Override
public Pair<float[], MagnificationSpec> getWindowTransformationMatrixAndMagnificationSpec(
int windowId) {
@@ -901,7 +1007,19 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
private void registerBroadcastReceivers() {
// package changes
mPackageMonitor = new ManagerPackageMonitor(this);
- mPackageMonitor.register(mContext, null, UserHandle.ALL, true);
+ final Looper packageMonitorLooper;
+ if (Flags.packageMonitorDedicatedThread()) {
+ // Use a dedicated thread because the default BackgroundThread used by PackageMonitor
+ // is shared by other components and can get busy, causing a delay and eventual ANR when
+ // responding to broadcasts sent to this PackageMonitor.
+ HandlerThread packageMonitorThread = new HandlerThread(LOG_TAG + " PackageMonitor",
+ Process.THREAD_PRIORITY_BACKGROUND);
+ packageMonitorThread.start();
+ packageMonitorLooper = packageMonitorThread.getLooper();
+ } else {
+ packageMonitorLooper = null;
+ }
+ mPackageMonitor.register(mContext, packageMonitorLooper, UserHandle.ALL, true);
// user change and unlock
IntentFilter intentFilter = new IntentFilter();
@@ -910,8 +1028,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
intentFilter.addAction(Intent.ACTION_USER_REMOVED);
intentFilter.addAction(Intent.ACTION_SETTING_RESTORED);
- Handler receiverHandler =
- Flags.managerAvoidReceiverTimeout() ? BackgroundThread.getHandler() : null;
+ Handler receiverHandler = BackgroundThread.getHandler();
mContext.registerReceiverAsUser(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -953,8 +1070,11 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
newValue, restoredFromSdk);
}
}
+ // Currently in SUW, the user can't see gesture shortcut option as the
+ // navigation system is set to button navigation. We'll rely on the
+ // SettingsBackupAgent to restore the settings since we don't
+ // need to merge an empty gesture target.
case Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS,
- Settings.Secure.ACCESSIBILITY_GESTURE_TARGETS,
Settings.Secure.ACCESSIBILITY_QS_TARGETS,
Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE ->
restoreShortcutTargets(newValue,
@@ -1210,14 +1330,14 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
int displayId = event.getDisplayId();
final int windowId = event.getWindowId();
if (windowId != AccessibilityWindowInfo.UNDEFINED_WINDOW_ID
- && displayId == Display.INVALID_DISPLAY) {
+ && displayId == INVALID_DISPLAY) {
displayId = mA11yWindowManager.getDisplayIdByUserIdAndWindowId(
resolvedUserId, windowId);
event.setDisplayId(displayId);
}
synchronized (mLock) {
if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED
- && displayId != Display.INVALID_DISPLAY
+ && displayId != INVALID_DISPLAY
&& mA11yWindowManager.isTrackingWindowsLocked(displayId)) {
shouldComputeWindows = true;
}
@@ -1435,8 +1555,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
interfacesToInterrupt = new ArrayList<>(services.size());
for (int i = 0; i < services.size(); i++) {
AccessibilityServiceConnection service = services.get(i);
- IBinder a11yServiceBinder = service.mService;
- IAccessibilityServiceClient a11yServiceInterface = service.mServiceInterface;
+ IBinder a11yServiceBinder = service.mClientBinder;
+ IAccessibilityServiceClient a11yServiceInterface = service.mClient;
if ((a11yServiceBinder != null) && (a11yServiceInterface != null)) {
interfacesToInterrupt.add(a11yServiceInterface);
}
@@ -2139,10 +2259,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
if (shortcutType == QUICK_SETTINGS && !android.view.accessibility.Flags.a11yQsShortcut()) {
return;
}
- if (shortcutType == HARDWARE
- && !android.view.accessibility.Flags.restoreA11yShortcutTargetService()) {
- return;
- }
synchronized (mLock) {
final AccessibilityUserState userState = getUserStateLocked(UserHandle.USER_SYSTEM);
@@ -2151,8 +2267,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
mContext, shortcutType, userState.mUserId))
: userState.getShortcutTargetsLocked(shortcutType);
- if (Flags.clearDefaultFromA11yShortcutTargetServiceRestore()
- && shortcutType == HARDWARE) {
+ if (shortcutType == HARDWARE) {
final String defaultService =
mContext.getString(R.string.config_defaultAccessibilityService);
final ComponentName defaultServiceComponent = TextUtils.isEmpty(defaultService)
@@ -2513,6 +2628,19 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
private boolean readInstalledAccessibilityShortcutLocked(AccessibilityUserState userState,
List<AccessibilityShortcutInfo> parsedAccessibilityShortcutInfos) {
if (!parsedAccessibilityShortcutInfos.equals(userState.mInstalledShortcuts)) {
+ if (Flags.clearShortcutsWhenActivityUpdatesToService()) {
+ List<String> componentNames = userState.mInstalledShortcuts.stream()
+ .filter(a11yActivity ->
+ !parsedAccessibilityShortcutInfos.contains(a11yActivity))
+ .map(a11yActivity -> a11yActivity.getComponentName().flattenToString())
+ .toList();
+ if (!componentNames.isEmpty()) {
+ enableShortcutsForTargets(
+ /* enable= */ false, UserShortcutType.ALL,
+ componentNames, userState.mUserId);
+ }
+ }
+
userState.mInstalledShortcuts.clear();
userState.mInstalledShortcuts.addAll(parsedAccessibilityShortcutInfos);
userState.updateTileServiceMapForAccessibilityActivityLocked();
@@ -2799,27 +2927,25 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
final String builderValue = builder.toString();
final String settingValue = TextUtils.isEmpty(builderValue)
? defaultEmptyString : builderValue;
- if (android.view.accessibility.Flags.restoreA11yShortcutTargetService()) {
- final String currentValue = Settings.Secure.getStringForUser(
- mContext.getContentResolver(), settingName, userId);
- if (Objects.equals(settingValue, currentValue)) {
- // This logic exists to fix a bug where AccessibilityManagerService was writing
- // `null` to the ACCESSIBILITY_SHORTCUT_TARGET_SERVICE setting during early boot
- // during setup, due to a race condition in package scanning making A11yMS think
- // that the default service was not installed.
- //
- // Writing `null` was implicitly causing that Setting to have the default
- // `DEFAULT_OVERRIDEABLE_BY_RESTORE` property, which was preventing B&R for that
- // Setting altogether.
- //
- // The "quick fix" here is to not write `null` if the existing value is already
- // `null`. The ideal fix would be use the Settings.Secure#putStringForUser overload
- // that allows override-by-restore, but the full repercussions of using that here
- // have not yet been evaluated.
- // TODO: b/333457719 - Evaluate and fix AccessibilityManagerService's usage of
- // "overridable by restore" when writing secure settings.
- return;
- }
+ final String currentValue = Settings.Secure.getStringForUser(
+ mContext.getContentResolver(), settingName, userId);
+ if (Objects.equals(settingValue, currentValue)) {
+ // This logic exists to fix a bug where AccessibilityManagerService was writing
+ // `null` to the ACCESSIBILITY_SHORTCUT_TARGET_SERVICE setting during early boot
+ // during setup, due to a race condition in package scanning making A11yMS think
+ // that the default service was not installed.
+ //
+ // Writing `null` was implicitly causing that Setting to have the default
+ // `DEFAULT_OVERRIDEABLE_BY_RESTORE` property, which was preventing B&R for that
+ // Setting altogether.
+ //
+ // The "quick fix" here is to not write `null` if the existing value is already
+ // `null`. The ideal fix would be use the Settings.Secure#putStringForUser overload
+ // that allows override-by-restore, but the full repercussions of using that here
+ // have not yet been evaluated.
+ // TODO: b/333457719 - Evaluate and fix AccessibilityManagerService's usage of
+ // "overridable by restore" when writing secure settings.
+ return;
}
final long identity = Binder.clearCallingIdentity();
try {
@@ -3230,6 +3356,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
updateAccessibilityShortcutTargetsLocked(userState, SOFTWARE);
updateAccessibilityShortcutTargetsLocked(userState, GESTURE);
updateAccessibilityShortcutTargetsLocked(userState, QUICK_SETTINGS);
+ updateAccessibilityShortcutTargetsLocked(userState, KEY_GESTURE);
// Update the capabilities before the mode because we will check the current mode is
// invalid or not..
updateMagnificationCapabilitiesSettingsChangeLocked(userState);
@@ -3360,6 +3487,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
somethingChanged |= readAccessibilityShortcutTargetsLocked(userState, QUICK_SETTINGS);
somethingChanged |= readAccessibilityShortcutTargetsLocked(userState, SOFTWARE);
somethingChanged |= readAccessibilityShortcutTargetsLocked(userState, GESTURE);
+ somethingChanged |= readAccessibilityShortcutTargetsLocked(userState, KEY_GESTURE);
somethingChanged |= readAccessibilityButtonTargetComponentLocked(userState);
somethingChanged |= readUserRecommendedUiTimeoutSettingsLocked(userState);
somethingChanged |= readMagnificationModeForDefaultDisplayLocked(userState);
@@ -3664,13 +3792,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
|| (Flags.enableMagnificationMultipleFingerMultipleTapGesture()
&& userState.isMagnificationTwoFingerTripleTapEnabledLocked()));
- final boolean createConnectionForCurrentCapability =
- com.android.window.flags.Flags.alwaysDrawMagnificationFullscreenBorder()
- || (userState.getMagnificationCapabilitiesLocked()
- != Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN);
-
- final boolean connect = (shortcutEnabled && createConnectionForCurrentCapability)
- || userHasMagnificationServicesLocked(userState);
+ final boolean connect = shortcutEnabled || userHasMagnificationServicesLocked(userState);
getMagnificationConnectionManager().requestConnection(connect);
}
@@ -3871,6 +3993,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
userState.getShortcutTargetsLocked(HARDWARE);
final Set<String> qsShortcutTargets =
userState.getShortcutTargetsLocked(QUICK_SETTINGS);
+ final Set<String> shortcutTargets = userState.getShortcutTargetsLocked(ALL);
userState.mEnabledServices.forEach(componentName -> {
if (packageName != null && componentName != null
&& !packageName.equals(componentName.getPackageName())) {
@@ -3891,7 +4014,11 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
if (TextUtils.isEmpty(serviceName)) {
return;
}
- if (doesShortcutTargetsStringContain(buttonTargets, serviceName)
+ if (android.provider.Flags.a11yStandaloneGestureEnabled()) {
+ if (doesShortcutTargetsStringContain(shortcutTargets, serviceName)) {
+ return;
+ }
+ } else if (doesShortcutTargetsStringContain(buttonTargets, serviceName)
|| doesShortcutTargetsStringContain(shortcutKeyTargets, serviceName)
|| doesShortcutTargetsStringContain(qsShortcutTargets, serviceName)) {
return;
@@ -3936,6 +4063,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
if (android.provider.Flags.a11yStandaloneGestureEnabled()) {
shortcutTypes.add(GESTURE);
}
+ shortcutTypes.add(KEY_GESTURE);
final ComponentName serviceName = service.getComponentName();
for (Integer shortcutType: shortcutTypes) {
@@ -4046,13 +4174,15 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
*/
private void performAccessibilityShortcutInternal(int displayId,
@UserShortcutType int shortcutType, @Nullable String targetName) {
- final List<String> shortcutTargets = getAccessibilityShortcutTargetsInternal(shortcutType);
+ final List<String> shortcutTargets = getAccessibilityShortcutTargetsInternal(
+ shortcutType);
if (shortcutTargets.isEmpty()) {
Slog.d(LOG_TAG, "No target to perform shortcut, shortcutType=" + shortcutType);
return;
}
// In case the caller specified a target name
- if (targetName != null && !doesShortcutTargetsStringContain(shortcutTargets, targetName)) {
+ if (targetName != null && !doesShortcutTargetsStringContain(shortcutTargets,
+ targetName)) {
Slog.v(LOG_TAG, "Perform shortcut failed, invalid target name:" + targetName);
targetName = null;
}
@@ -4274,6 +4404,13 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
return;
}
+ if (shortcutType == UserShortcutType.KEY_GESTURE
+ && !enableTalkbackAndMagnifierKeyGestures()) {
+ Slog.w(LOG_TAG,
+ "KEY_GESTURE type shortcuts are disabled by feature flag");
+ return;
+ }
+
final String shortcutTypeSettingKey = ShortcutUtils.convertToKey(shortcutType);
if (shortcutType == UserShortcutType.TRIPLETAP
|| shortcutType == UserShortcutType.TWOFINGER_DOUBLETAP) {
@@ -4355,13 +4492,11 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
}
if (shortcutType == HARDWARE) {
skipVolumeShortcutDialogTimeoutRestriction(userId);
- if (com.android.server.accessibility.Flags.enableHardwareShortcutDisablesWarning()) {
- persistIntToSetting(
- userId,
- Settings.Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN,
- AccessibilityShortcutController.DialogStatus.SHOWN
- );
- }
+ persistIntToSetting(
+ userId,
+ Settings.Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN,
+ AccessibilityShortcutController.DialogStatus.SHOWN
+ );
} else if (shortcutType == SOFTWARE) {
// Update the A11y FAB size to large when the Magnification shortcut is
// enabled and the user hasn't changed the floating button size
@@ -4706,8 +4841,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
getMagnificationConnectionManager().setConnection(connection);
- if (com.android.window.flags.Flags.alwaysDrawMagnificationFullscreenBorder()
- && connection == null
+ if (connection == null
&& mMagnificationController.isFullScreenMagnificationControllerInitialized()) {
// Since the connection does not exist, the system ui cannot provide the border
// implementation for fullscreen magnification. So we call reset to deactivate the
@@ -4968,9 +5102,14 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
if (android.permission.flags.Flags.enhancedConfirmationModeApisEnabled()
&& android.security.Flags.extendEcmToAllSettings()) {
try {
- return !mContext.getSystemService(EnhancedConfirmationManager.class)
- .isRestricted(packageName,
- AppOpsManager.OPSTR_BIND_ACCESSIBILITY_SERVICE);
+ final EnhancedConfirmationManager userContextEcm =
+ mContext.createContextAsUser(UserHandle.of(userId), /* flags = */ 0)
+ .getSystemService(EnhancedConfirmationManager.class);
+ if (userContextEcm != null) {
+ return !userContextEcm.isRestricted(packageName,
+ AppOpsManager.OPSTR_BIND_ACCESSIBILITY_SERVICE);
+ }
+ return false;
} catch (PackageManager.NameNotFoundException e) {
Log.e(LOG_TAG, "Exception when retrieving package:" + packageName, e);
return false;
@@ -5034,6 +5173,11 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
@EnforcePermission(MANAGE_ACCESSIBILITY)
public boolean isAccessibilityServiceWarningRequired(AccessibilityServiceInfo info) {
isAccessibilityServiceWarningRequired_enforcePermission();
+ if (info == null) {
+ Log.e(LOG_TAG, "Called isAccessibilityServiceWarningRequired with null service info");
+ return true;
+ }
+
final ComponentName componentName = info.getComponentName();
// Warning is not required if the service is already enabled.
@@ -5641,6 +5785,9 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
private final Uri mAccessibilityGestureTargetsUri = Settings.Secure.getUriFor(
Settings.Secure.ACCESSIBILITY_GESTURE_TARGETS);
+ private final Uri mAccessibilityKeyGestureTargetsUri = Settings.Secure.getUriFor(
+ Settings.Secure.ACCESSIBILITY_KEY_GESTURE_TARGETS);
+
private final Uri mUserNonInteractiveUiTimeoutUri = Settings.Secure.getUriFor(
Settings.Secure.ACCESSIBILITY_NON_INTERACTIVE_UI_TIMEOUT_MS);
@@ -5705,6 +5852,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
contentResolver.registerContentObserver(
mAccessibilityGestureTargetsUri, false, this, UserHandle.USER_ALL);
contentResolver.registerContentObserver(
+ mAccessibilityKeyGestureTargetsUri, false, this, UserHandle.USER_ALL);
+ contentResolver.registerContentObserver(
mUserNonInteractiveUiTimeoutUri, false, this, UserHandle.USER_ALL);
contentResolver.registerContentObserver(
mUserInteractiveUiTimeoutUri, false, this, UserHandle.USER_ALL);
@@ -5786,6 +5935,10 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
if (readAccessibilityShortcutTargetsLocked(userState, GESTURE)) {
onUserStateChangedLocked(userState);
}
+ } else if (mAccessibilityKeyGestureTargetsUri.equals(uri)) {
+ if (readAccessibilityShortcutTargetsLocked(userState, KEY_GESTURE)) {
+ onUserStateChangedLocked(userState);
+ }
} else if (mUserNonInteractiveUiTimeoutUri.equals(uri)
|| mUserInteractiveUiTimeoutUri.equals(uri)) {
readUserRecommendedUiTimeoutSettingsLocked(userState);
@@ -6383,8 +6536,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
// Only continue setting up the packages if the service has been initialized.
// See: b/340927041
- if (Flags.skipPackageChangeBeforeUserSwitch()
- && !mManagerService.isServiceInitializedLocked()) {
+ if (!mManagerService.isServiceInitializedLocked()) {
Slog.w(LOG_TAG,
"onSomePackagesChanged: service not initialized, skip the callback.");
return;
@@ -6492,28 +6644,17 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
}
final AccessibilityUserState userState = mManagerService.getUserStateLocked(userId);
- if (Flags.managerPackageMonitorLogicFix()) {
- if (!doit) {
- // if we're not handling the stop here, then we only need to know
- // if any of the force-stopped packages are currently enabled.
- return userState.mEnabledServices.stream().anyMatch(
- (comp) -> Arrays.stream(packages).anyMatch(
- (pkg) -> pkg.equals(comp.getPackageName()))
- );
- } else if (mManagerService.onPackagesForceStoppedLocked(packages, userState)) {
- mManagerService.onUserStateChangedLocked(userState);
- }
- return false;
- } else {
- // this old logic did not properly indicate when base packageMonitor's routine
- // should handle stopping the package.
- if (doit && mManagerService.onPackagesForceStoppedLocked(packages, userState)) {
- mManagerService.onUserStateChangedLocked(userState);
- return false;
- } else {
- return true;
- }
+ if (!doit) {
+ // if we're not handling the stop here, then we only need to know
+ // if any of the force-stopped packages are currently enabled.
+ return userState.mEnabledServices.stream().anyMatch(
+ (comp) -> Arrays.stream(packages).anyMatch(
+ (pkg) -> pkg.equals(comp.getPackageName()))
+ );
+ } else if (mManagerService.onPackagesForceStoppedLocked(packages, userState)) {
+ mManagerService.onUserStateChangedLocked(userState);
}
+ return false;
}
}
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilitySecurityPolicy.java b/services/accessibility/java/com/android/server/accessibility/AccessibilitySecurityPolicy.java
index f45fa921c4a2..5ae077363c88 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilitySecurityPolicy.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilitySecurityPolicy.java
@@ -405,10 +405,9 @@ public class AccessibilitySecurityPolicy {
* @throws SecurityException if the input method is not in the same package as the service.
*/
@AccessibilityService.SoftKeyboardController.EnableImeResult
- int canEnableDisableInputMethod(String imeId, AbstractAccessibilityServiceConnection service)
- throws SecurityException {
+ int canEnableDisableInputMethod(String imeId, AbstractAccessibilityServiceConnection service,
+ int callingUserId) throws SecurityException {
final String servicePackageName = service.getComponentName().getPackageName();
- final int callingUserId = UserHandle.getCallingUserId();
InputMethodInfo inputMethodInfo = null;
List<InputMethodInfo> inputMethodInfoList =
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
index 786d167af5de..a3fe9ec5ea22 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
@@ -166,8 +166,9 @@ class AccessibilityServiceConnection extends AbstractAccessibilityServiceConnect
if (userState.getBindInstantServiceAllowedLocked()) {
flags |= Context.BIND_ALLOW_INSTANT;
}
- if (mService == null && mContext.bindServiceAsUser(
- mIntent, this, flags, new UserHandle(userState.mUserId))) {
+ if (mClientBinder == null
+ && mContext.bindServiceAsUser(
+ mIntent, this, flags, new UserHandle(userState.mUserId))) {
userState.getBindingServicesLocked().add(mComponentName);
}
} finally {
@@ -227,20 +228,20 @@ class AccessibilityServiceConnection extends AbstractAccessibilityServiceConnect
addWindowTokensForAllDisplays();
}
synchronized (mLock) {
- if (mService != service) {
- if (mService != null) {
- mService.unlinkToDeath(this, 0);
+ if (mClientBinder != service) {
+ if (mClientBinder != null) {
+ mClientBinder.unlinkToDeath(this, 0);
}
- mService = service;
+ mClientBinder = service;
try {
- mService.linkToDeath(this, 0);
+ mClientBinder.linkToDeath(this, 0);
} catch (RemoteException re) {
Slog.e(LOG_TAG, "Failed registering death link");
binderDied();
return;
}
}
- mServiceInterface = IAccessibilityServiceClient.Stub.asInterface(service);
+ mClient = IAccessibilityServiceClient.Stub.asInterface(service);
if (userState == null) return;
userState.addServiceLocked(this);
mSystemSupport.onClientChangeLocked(false);
@@ -261,7 +262,7 @@ class AccessibilityServiceConnection extends AbstractAccessibilityServiceConnect
}
private void initializeService() {
- IAccessibilityServiceClient serviceInterface = null;
+ IAccessibilityServiceClient client = null;
synchronized (mLock) {
AccessibilityUserState userState = mUserStateWeakReference.get();
if (userState == null) return;
@@ -272,18 +273,17 @@ class AccessibilityServiceConnection extends AbstractAccessibilityServiceConnect
bindingServices.remove(mComponentName);
crashedServices.remove(mComponentName);
mAccessibilityServiceInfo.crashed = false;
- serviceInterface = mServiceInterface;
+ client = mClient;
}
// There's a chance that service is removed from enabled_accessibility_services setting
// key, but skip unbinding because of it's in binding state. Unbinds it if it's
// not in enabled service list.
- if (serviceInterface != null
- && !userState.getEnabledServicesLocked().contains(mComponentName)) {
+ if (client != null && !userState.getEnabledServicesLocked().contains(mComponentName)) {
mSystemSupport.onClientChangeLocked(false);
return;
}
}
- if (serviceInterface == null) {
+ if (client == null) {
binderDied();
return;
}
@@ -292,10 +292,9 @@ class AccessibilityServiceConnection extends AbstractAccessibilityServiceConnect
logTraceSvcClient("init",
this + "," + mId + "," + mOverlayWindowTokens.get(Display.DEFAULT_DISPLAY));
}
- serviceInterface.init(this, mId, mOverlayWindowTokens.get(Display.DEFAULT_DISPLAY));
+ client.init(this, mId, mOverlayWindowTokens.get(Display.DEFAULT_DISPLAY));
} catch (RemoteException re) {
- Slog.w(LOG_TAG, "Error while setting connection for service: "
- + serviceInterface, re);
+ Slog.w(LOG_TAG, "Error while setting connection for service: " + client, re);
binderDied();
}
}
@@ -411,9 +410,7 @@ class AccessibilityServiceConnection extends AbstractAccessibilityServiceConnect
final @AccessibilityService.SoftKeyboardController.EnableImeResult int checkResult;
final long identity = Binder.clearCallingIdentity();
try {
- synchronized (mLock) {
- checkResult = mSecurityPolicy.canEnableDisableInputMethod(imeId, this);
- }
+ checkResult = mSecurityPolicy.canEnableDisableInputMethod(imeId, this, callingUserId);
if (checkResult != ENABLE_IME_SUCCESS) {
return checkResult;
}
@@ -496,7 +493,7 @@ class AccessibilityServiceConnection extends AbstractAccessibilityServiceConnect
@Override
public boolean isCapturingFingerprintGestures() {
- return (mServiceInterface != null)
+ return (mClient != null)
&& mSecurityPolicy.canCaptureFingerprintGestures(this)
&& mCaptureFingerprintGestures;
}
@@ -506,17 +503,17 @@ class AccessibilityServiceConnection extends AbstractAccessibilityServiceConnect
if (!isCapturingFingerprintGestures()) {
return;
}
- IAccessibilityServiceClient serviceInterface;
+ IAccessibilityServiceClient client;
synchronized (mLock) {
- serviceInterface = mServiceInterface;
+ client = mClient;
}
- if (serviceInterface != null) {
+ if (client != null) {
try {
if (svcClientTracingEnabled()) {
logTraceSvcClient(
"onFingerprintCapturingGesturesChanged", String.valueOf(active));
}
- mServiceInterface.onFingerprintCapturingGesturesChanged(active);
+ mClient.onFingerprintCapturingGesturesChanged(active);
} catch (RemoteException e) {
}
}
@@ -527,16 +524,16 @@ class AccessibilityServiceConnection extends AbstractAccessibilityServiceConnect
if (!isCapturingFingerprintGestures()) {
return;
}
- IAccessibilityServiceClient serviceInterface;
+ IAccessibilityServiceClient client;
synchronized (mLock) {
- serviceInterface = mServiceInterface;
+ client = mClient;
}
- if (serviceInterface != null) {
+ if (client != null) {
try {
if (svcClientTracingEnabled()) {
logTraceSvcClient("onFingerprintGesture", String.valueOf(gesture));
}
- mServiceInterface.onFingerprintGesture(gesture);
+ mClient.onFingerprintGesture(gesture);
} catch (RemoteException e) {
}
}
@@ -546,7 +543,7 @@ class AccessibilityServiceConnection extends AbstractAccessibilityServiceConnect
@Override
public void dispatchGesture(int sequence, ParceledListSlice gestureSteps, int displayId) {
synchronized (mLock) {
- if (mServiceInterface != null && mSecurityPolicy.canPerformGestures(this)) {
+ if (mClient != null && mSecurityPolicy.canPerformGestures(this)) {
final long identity = Binder.clearCallingIdentity();
try {
MotionEventInjector motionEventInjector =
@@ -557,16 +554,18 @@ class AccessibilityServiceConnection extends AbstractAccessibilityServiceConnect
if (motionEventInjector != null
&& mWindowManagerService.isTouchOrFaketouchDevice()) {
motionEventInjector.injectEvents(
- gestureSteps.getList(), mServiceInterface, sequence, displayId);
+ gestureSteps.getList(), mClient, sequence, displayId);
} else {
try {
if (svcClientTracingEnabled()) {
logTraceSvcClient("onPerformGestureResult", sequence + ", false");
}
- mServiceInterface.onPerformGestureResult(sequence, false);
+ mClient.onPerformGestureResult(sequence, false);
} catch (RemoteException re) {
- Slog.e(LOG_TAG, "Error sending motion event injection failure to "
- + mServiceInterface, re);
+ Slog.e(
+ LOG_TAG,
+ "Error sending motion event injection failure to " + mClient,
+ re);
}
}
} finally {
@@ -631,48 +630,47 @@ class AccessibilityServiceConnection extends AbstractAccessibilityServiceConnect
@Override
protected void createImeSessionInternal() {
- final IAccessibilityServiceClient listener = getServiceInterfaceSafely();
- if (listener != null) {
+ final IAccessibilityServiceClient client = getClientSafely();
+ if (client != null) {
try {
if (svcClientTracingEnabled()) {
logTraceSvcClient("createImeSession", "");
}
AccessibilityInputMethodSessionCallback
callback = new AccessibilityInputMethodSessionCallback(mUserId);
- listener.createImeSession(callback);
+ client.createImeSession(callback);
} catch (RemoteException re) {
- Slog.e(LOG_TAG,
- "Error requesting IME session from " + mService, re);
+ Slog.e(LOG_TAG, "Error requesting IME session from " + mClientBinder, re);
}
}
}
private void notifyMotionEventInternal(MotionEvent event) {
- final IAccessibilityServiceClient listener = getServiceInterfaceSafely();
- if (listener != null) {
+ final IAccessibilityServiceClient client = getClientSafely();
+ if (client != null) {
try {
if (mTrace.isA11yTracingEnabled()) {
logTraceSvcClient(".onMotionEvent ",
event.toString());
}
- listener.onMotionEvent(event);
+ client.onMotionEvent(event);
} catch (RemoteException re) {
- Slog.e(LOG_TAG, "Error sending motion event to" + mService, re);
+ Slog.e(LOG_TAG, "Error sending motion event to" + mClientBinder, re);
}
}
}
private void notifyTouchStateInternal(int displayId, int state) {
- final IAccessibilityServiceClient listener = getServiceInterfaceSafely();
- if (listener != null) {
+ final IAccessibilityServiceClient client = getClientSafely();
+ if (client != null) {
try {
if (mTrace.isA11yTracingEnabled()) {
logTraceSvcClient(".onTouchStateChanged ",
TouchInteractionController.stateToString(state));
}
- listener.onTouchStateChanged(displayId, state);
+ client.onTouchStateChanged(displayId, state);
} catch (RemoteException re) {
- Slog.e(LOG_TAG, "Error sending motion event to" + mService, re);
+ Slog.e(LOG_TAG, "Error sending motion event to" + mClientBinder, re);
}
}
}
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java
index 0bf7ec001d4d..8b3e63d0dc5e 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java
@@ -29,6 +29,7 @@ import static com.android.internal.accessibility.AccessibilityShortcutController
import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType;
import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.GESTURE;
import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.HARDWARE;
+import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.KEY_GESTURE;
import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.QUICK_SETTINGS;
import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.SOFTWARE;
import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.TRIPLETAP;
@@ -106,21 +107,17 @@ class AccessibilityUserState {
final Set<ComponentName> mTouchExplorationGrantedServices = new HashSet<>();
- private final ArraySet<String> mAccessibilityShortcutKeyTargets = new ArraySet<>();
-
- private final ArraySet<String> mAccessibilityButtonTargets = new ArraySet<>();
- private final ArraySet<String> mAccessibilityGestureTargets = new ArraySet<>();
- private final ArraySet<String> mAccessibilityQsTargets = new ArraySet<>();
+ private final HashMap<Integer, ArraySet<String>> mShortcutTargets = new HashMap<>();
/**
- * The QuickSettings tiles in the QS Panel. This can be different from
- * {@link #mAccessibilityQsTargets} in that {@link #mA11yTilesInQsPanel} stores the
+ * The QuickSettings tiles in the QS Panel. This can be different from the QS targets in
+ * {@link #mShortcutTargets} in that {@link #mA11yTilesInQsPanel} stores the
* TileService's or the a11y framework tile component names (e.g.
* {@link AccessibilityShortcutController#COLOR_INVERSION_TILE_COMPONENT_NAME}) instead of the
* A11y Feature's component names.
* <p/>
* In addition, {@link #mA11yTilesInQsPanel} stores what's on the QS Panel, whereas
- * {@link #mAccessibilityQsTargets} stores the targets that configured qs as their shortcut and
+ * {@link #mShortcutTargets} stores the targets that configured qs as their shortcut and
* also grant full device control permission.
*/
private final ArraySet<ComponentName> mA11yTilesInQsPanel = new ArraySet<>();
@@ -208,6 +205,12 @@ class AccessibilityUserState {
mSupportWindowMagnification = mContext.getResources().getBoolean(
R.bool.config_magnification_area) && mContext.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_WINDOW_MAGNIFICATION);
+
+ mShortcutTargets.put(HARDWARE, new ArraySet<>());
+ mShortcutTargets.put(SOFTWARE, new ArraySet<>());
+ mShortcutTargets.put(GESTURE, new ArraySet<>());
+ mShortcutTargets.put(QUICK_SETTINGS, new ArraySet<>());
+ mShortcutTargets.put(KEY_GESTURE, new ArraySet<>());
}
boolean isHandlingAccessibilityEventsLocked() {
@@ -233,10 +236,7 @@ class AccessibilityUserState {
// Clear state persisted in settings.
mEnabledServices.clear();
mTouchExplorationGrantedServices.clear();
- mAccessibilityShortcutKeyTargets.clear();
- mAccessibilityButtonTargets.clear();
- mAccessibilityGestureTargets.clear();
- mAccessibilityQsTargets.clear();
+ mShortcutTargets.forEach((type, targets) -> targets.clear());
mA11yTilesInQsPanel.clear();
mTargetAssignedToAccessibilityButton = null;
mIsTouchExplorationEnabled = false;
@@ -541,7 +541,7 @@ class AccessibilityUserState {
private void dumpShortcutTargets(
PrintWriter pw, @UserShortcutType int shortcutType, String name) {
pw.append(" ").append(name).append(":{");
- ArraySet<String> targets = getShortcutTargetsInternalLocked(shortcutType);
+ ArraySet<String> targets = getShortcutTargetsLocked(shortcutType);
int size = targets.size();
for (int i = 0; i < size; i++) {
if (i > 0) {
@@ -712,7 +712,7 @@ class AccessibilityUserState {
*/
public boolean isShortcutMagnificationEnabledLocked() {
for (int shortcutType : ShortcutConstants.USER_SHORTCUT_TYPES) {
- if (getShortcutTargetsInternalLocked(shortcutType)
+ if (getShortcutTargetsLocked(shortcutType)
.contains(MAGNIFICATION_CONTROLLER_NAME)) {
return true;
}
@@ -788,43 +788,29 @@ class AccessibilityUserState {
}
/**
- * Disable both shortcuts' magnification function.
- */
- public void disableShortcutMagnificationLocked() {
- mAccessibilityShortcutKeyTargets.remove(MAGNIFICATION_CONTROLLER_NAME);
- mAccessibilityButtonTargets.remove(MAGNIFICATION_CONTROLLER_NAME);
- }
-
- /**
* Returns a set which contains the flattened component names and the system class names
- * assigned to the given shortcut. The set is a defensive copy. To apply any changes to the set,
- * use {@link #updateShortcutTargetsLocked(Set, int)}
+ * assigned to the given shortcut. <strong>The set is a defensive copy.</strong>
+ * To apply any changes to the set, use {@link #updateShortcutTargetsLocked(Set, int)}
*
- * @param shortcutType The shortcut type.
+ * @param shortcutTypes The shortcut type or types (in bitmask format).
* @return The array set of the strings
*/
- public ArraySet<String> getShortcutTargetsLocked(@UserShortcutType int shortcutType) {
- return new ArraySet<>(getShortcutTargetsInternalLocked(shortcutType));
- }
-
- private ArraySet<String> getShortcutTargetsInternalLocked(@UserShortcutType int shortcutType) {
- if (shortcutType == HARDWARE) {
- return mAccessibilityShortcutKeyTargets;
- } else if (shortcutType == SOFTWARE) {
- return mAccessibilityButtonTargets;
- } else if (shortcutType == GESTURE) {
- return mAccessibilityGestureTargets;
- } else if (shortcutType == QUICK_SETTINGS) {
- return mAccessibilityQsTargets;
- } else if ((shortcutType == TRIPLETAP
- && isMagnificationSingleFingerTripleTapEnabledLocked()) || (
- shortcutType == TWOFINGER_DOUBLETAP
- && isMagnificationTwoFingerTripleTapEnabledLocked())) {
- ArraySet<String> targets = new ArraySet<>();
- targets.add(MAGNIFICATION_CONTROLLER_NAME);
- return targets;
+ public ArraySet<String> getShortcutTargetsLocked(int shortcutTypes) {
+ ArraySet<String> targets = new ArraySet<>();
+ for (int shortcutType : ShortcutConstants.USER_SHORTCUT_TYPES) {
+ if ((shortcutTypes & shortcutType) != shortcutType) {
+ continue;
+ }
+ if ((shortcutType == TRIPLETAP
+ && isMagnificationSingleFingerTripleTapEnabledLocked()) || (
+ shortcutType == TWOFINGER_DOUBLETAP
+ && isMagnificationTwoFingerTripleTapEnabledLocked())) {
+ targets.add(MAGNIFICATION_CONTROLLER_NAME);
+ } else if (mShortcutTargets.containsKey(shortcutType)) {
+ targets.addAll(mShortcutTargets.get(shortcutType));
+ }
}
- return new ArraySet<>();
+ return targets;
}
/**
@@ -843,8 +829,10 @@ class AccessibilityUserState {
if ((shortcutType & mask) != 0) {
throw new IllegalArgumentException("Tap shortcuts cannot be updated with target sets.");
}
-
- final Set<String> currentTargets = getShortcutTargetsInternalLocked(shortcutType);
+ if (!mShortcutTargets.containsKey(shortcutType)) {
+ mShortcutTargets.put(shortcutType, new ArraySet<>());
+ }
+ ArraySet<String> currentTargets = mShortcutTargets.get(shortcutType);
if (newTargets.equals(currentTargets)) {
return false;
}
@@ -904,7 +892,7 @@ class AccessibilityUserState {
}
// getting internal set lets us directly modify targets, as it's not a copy.
- Set<String> targets = getShortcutTargetsInternalLocked(shortcutType);
+ Set<String> targets = mShortcutTargets.get(shortcutType);
return targets.removeIf(name -> {
ComponentName componentName;
if (name == null
@@ -1169,13 +1157,6 @@ class AccessibilityUserState {
);
}
- /**
- * Returns a copy of the targets which has qs shortcut turned on
- */
- public ArraySet<String> getA11yQsTargets() {
- return new ArraySet<>(mAccessibilityQsTargets);
- }
-
public void updateA11yTilesInQsPanelLocked(Set<ComponentName> componentNames) {
mA11yTilesInQsPanel.clear();
mA11yTilesInQsPanel.addAll(componentNames);
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
index 9a81aa6cc506..b7fd09f7b594 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
@@ -434,21 +434,23 @@ public class AccessibilityWindowManager {
}
/**
- * Callbacks from window manager when there's an accessibility change in windows.
+ * Called when the windows for accessibility changed.
*
- * @param forceSend Send the windows for accessibility even if they haven't changed.
- * @param topFocusedDisplayId The display Id which has the top focused window.
+ * @param forceSend Send the windows for accessibility even if they haven't
+ * changed.
+ * @param topFocusedDisplayId The display Id which has the top focused window.
* @param topFocusedWindowToken The window token of top focused window.
- * @param windows The windows for accessibility.
+ * @param screenSize The size of the display that the change happened.
+ * @param accessibilityWindows The windows for accessibility.
*/
@Override
- public void onWindowsForAccessibilityChanged(boolean forceSend, int topFocusedDisplayId,
- IBinder topFocusedWindowToken, @NonNull List<WindowInfo> windows) {
+ public void onAccessibilityWindowsChanged(boolean forceSend, int topFocusedDisplayId,
+ @NonNull IBinder topFocusedWindowToken, @NonNull Point screenSize,
+ @NonNull List<AccessibilityWindow> accessibilityWindows) {
synchronized (mLock) {
- if (!Flags.computeWindowChangesOnA11yV2()) {
- // If the flag is enabled, it's already done in #createWindowInfoListLocked.
- updateWindowsByWindowAttributesLocked(windows);
- }
+ final List<WindowInfo> windows =
+ createWindowInfoListLocked(screenSize, accessibilityWindows);
+
if (DEBUG) {
Slogf.i(LOG_TAG, "mDisplayId=%d, topFocusedDisplayId=%d, currentUserId=%d, "
+ "visibleBgUsers=%s", mDisplayId, topFocusedDisplayId,
@@ -463,14 +465,15 @@ public class AccessibilityWindowManager {
Slogf.i(LOG_TAG, "%d windows changed: %s", windows.size(), windowsInfo);
}
}
- if (shouldUpdateWindowsLocked(forceSend, windows)) {
+
+ if (forceSend || shouldUpdateWindowsLocked(windows)) {
mTopFocusedDisplayId = topFocusedDisplayId;
if (!isProxyed(topFocusedDisplayId)) {
mLastNonProxyTopFocusedDisplayId = topFocusedDisplayId;
}
mTopFocusedWindowToken = topFocusedWindowToken;
if (DEBUG) {
- Slogf.d(LOG_TAG, "onWindowsForAccessibilityChanged(): updating windows for "
+ Slogf.d(LOG_TAG, "onAccessibilityWindowsChanged(): updating windows for "
+ "display %d and token %s",
topFocusedDisplayId, topFocusedWindowToken);
}
@@ -480,39 +483,14 @@ public class AccessibilityWindowManager {
windows);
// Someone may be waiting for the windows - advertise it.
mLock.notifyAll();
- }
- else if (DEBUG) {
- Slogf.d(LOG_TAG, "onWindowsForAccessibilityChanged(): NOT updating windows for "
+ } else if (DEBUG) {
+ Slogf.d(LOG_TAG, "onAccessibilityWindowsChanged(): NOT updating windows for "
+ "display %d and token %s",
topFocusedDisplayId, topFocusedWindowToken);
}
}
}
- /**
- * Called when the windows for accessibility changed. This is called if
- * {@link com.android.server.accessibility.Flags.FLAG_COMPUTE_WINDOW_CHANGES_ON_A11Y_V2} is
- * true.
- *
- * @param forceSend Send the windows for accessibility even if they haven't
- * changed.
- * @param topFocusedDisplayId The display Id which has the top focused window.
- * @param topFocusedWindowToken The window token of top focused window.
- * @param screenSize The size of the display that the change happened.
- * @param windows The windows for accessibility.
- */
- @Override
- public void onAccessibilityWindowsChanged(boolean forceSend, int topFocusedDisplayId,
- @NonNull IBinder topFocusedWindowToken, @NonNull Point screenSize,
- @NonNull List<AccessibilityWindow> windows) {
- synchronized (mLock) {
- final List<WindowInfo> windowInfoList =
- createWindowInfoListLocked(screenSize, windows);
- onWindowsForAccessibilityChanged(forceSend, topFocusedDisplayId,
- topFocusedWindowToken, windowInfoList);
- }
- }
-
private List<WindowInfo> createWindowInfoListLocked(@NonNull Point screenSize,
@NonNull List<AccessibilityWindow> visibleWindows) {
final Set<IBinder> addedWindows = new ArraySet<>();
@@ -655,16 +633,6 @@ public class AccessibilityWindowManager {
return true;
}
- private void updateWindowsByWindowAttributesLocked(List<WindowInfo> windows) {
- for (int i = windows.size() - 1; i >= 0; i--) {
- final WindowInfo windowInfo = windows.get(i);
- final IBinder token = windowInfo.token;
- final int windowId = findWindowIdLocked(
- mAccessibilityUserManager.getCurrentUserIdLocked(), token);
- updateWindowWithWindowAttributes(windowInfo, mWindowAttributes.get(windowId));
- }
- }
-
private void updateWindowWithWindowAttributes(@NonNull WindowInfo windowInfo,
@Nullable AccessibilityWindowAttributes attributes) {
if (attributes == null) {
@@ -674,12 +642,7 @@ public class AccessibilityWindowManager {
windowInfo.locales = attributes.getLocales();
}
- private boolean shouldUpdateWindowsLocked(boolean forceSend,
- @NonNull List<WindowInfo> windows) {
- if (forceSend) {
- return true;
- }
-
+ private boolean shouldUpdateWindowsLocked(@NonNull List<WindowInfo> windows) {
final int windowCount = windows.size();
if (VERBOSE) {
Slogf.v(LOG_TAG,
@@ -869,20 +832,12 @@ public class AccessibilityWindowManager {
!= AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
}
- boolean hasWindowIgnore = false;
if (windowCount > 0) {
- for (int i = 0; i < windowCount; i++) {
- final WindowInfo windowInfo = windows.get(i);
- final AccessibilityWindowInfo window;
- if (mTrackingWindows) {
- window = populateReportedWindowLocked(userId, windowInfo, oldWindowsById);
- if (window == null) {
- hasWindowIgnore = true;
- }
- } else {
- window = null;
- }
- if (window != null) {
+ if (mTrackingWindows) {
+ for (int i = 0; i < windowCount; i++) {
+ final WindowInfo windowInfo = windows.get(i);
+ final AccessibilityWindowInfo window =
+ populateReportedWindowLocked(userId, windowInfo, oldWindowsById);
// Flip layers in list to be consistent with AccessibilityService#getWindows
window.setLayer(windowCount - 1 - window.getLayer());
@@ -907,13 +862,6 @@ public class AccessibilityWindowManager {
}
}
final int accessibilityWindowCount = mWindows.size();
- // Re-order the window layer of all windows in the windows list because there's
- // window not been added into the windows list.
- if (hasWindowIgnore) {
- for (int i = 0; i < accessibilityWindowCount; i++) {
- mWindows.get(i).setLayer(accessibilityWindowCount - 1 - i);
- }
- }
if (isTopFocusedDisplay) {
if (mTouchInteractionInProgress && activeWindowGone) {
mActiveWindowId = mTopFocusedWindowId;
@@ -990,19 +938,6 @@ public class AccessibilityWindowManager {
private AccessibilityWindowInfo populateReportedWindowLocked(int userId,
WindowInfo window, SparseArray<AccessibilityWindowInfo> oldWindowsById) {
final int windowId = findWindowIdLocked(userId, window.token);
-
- // With the flag enabled, createWindowInfoListLocked() already removes invalid windows.
- if (!Flags.computeWindowChangesOnA11yV2()) {
- if (windowId < 0) {
- return null;
- }
-
- // Don't need to add the embedded hierarchy windows into the a11y windows list.
- if (isEmbeddedHierarchyWindowsLocked(windowId)) {
- return null;
- }
- }
-
final AccessibilityWindowInfo reportedWindow = AccessibilityWindowInfo.obtain();
reportedWindow.setId(windowId);
diff --git a/services/accessibility/java/com/android/server/accessibility/MouseKeysInterceptor.java b/services/accessibility/java/com/android/server/accessibility/MouseKeysInterceptor.java
index 54368ca9c03e..1212c757f1c2 100644
--- a/services/accessibility/java/com/android/server/accessibility/MouseKeysInterceptor.java
+++ b/services/accessibility/java/com/android/server/accessibility/MouseKeysInterceptor.java
@@ -73,12 +73,16 @@ public class MouseKeysInterceptor extends BaseEventStreamTransformation
private static final int MESSAGE_MOVE_MOUSE_POINTER = 1;
private static final int MESSAGE_SCROLL_MOUSE_POINTER = 2;
- private static final float MOUSE_POINTER_MOVEMENT_STEP = 1.8f;
private static final int KEY_NOT_SET = -1;
/** Time interval after which mouse action will be repeated */
private static final int INTERVAL_MILLIS = 10;
+ @VisibleForTesting
+ public static final float MOUSE_POINTER_MOVEMENT_STEP = 1.8f;
+ @VisibleForTesting
+ public static final float MOUSE_SCROLL_STEP = 0.2f;
+
private final AccessibilityManagerService mAms;
private final Handler mHandler;
private final InputManager mInputManager;
@@ -134,8 +138,8 @@ public class MouseKeysInterceptor extends BaseEventStreamTransformation
DIAGONAL_UP_LEFT_MOVE(KeyEvent.KEYCODE_7),
UP_MOVE_OR_SCROLL(KeyEvent.KEYCODE_8),
DIAGONAL_UP_RIGHT_MOVE(KeyEvent.KEYCODE_9),
- LEFT_MOVE(KeyEvent.KEYCODE_U),
- RIGHT_MOVE(KeyEvent.KEYCODE_O),
+ LEFT_MOVE_OR_SCROLL(KeyEvent.KEYCODE_U),
+ RIGHT_MOVE_OR_SCROLL(KeyEvent.KEYCODE_O),
DIAGONAL_DOWN_LEFT_MOVE(KeyEvent.KEYCODE_J),
DOWN_MOVE_OR_SCROLL(KeyEvent.KEYCODE_K),
DIAGONAL_DOWN_RIGHT_MOVE(KeyEvent.KEYCODE_L),
@@ -263,6 +267,16 @@ public class MouseKeysInterceptor extends BaseEventStreamTransformation
);
}
+ @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
+ private void sendVirtualMouseScrollEvent(float x, float y) {
+ waitForVirtualMouseCreation();
+ mVirtualMouse.sendScrollEvent(new VirtualMouseScrollEvent.Builder()
+ .setXAxisMovement(x)
+ .setYAxisMovement(y)
+ .build()
+ );
+ }
+
/**
* Performs a mouse scroll action based on the provided key code.
* The scroll action will only be performed if the scroll toggle is on.
@@ -280,19 +294,31 @@ public class MouseKeysInterceptor extends BaseEventStreamTransformation
private void performMouseScrollAction(int keyCode) {
MouseKeyEvent mouseKeyEvent = MouseKeyEvent.from(
keyCode, mActiveInputDeviceId, mDeviceKeyCodeMap);
- float y = switch (mouseKeyEvent) {
- case UP_MOVE_OR_SCROLL -> 1.0f;
- case DOWN_MOVE_OR_SCROLL -> -1.0f;
- default -> 0.0f;
- };
- waitForVirtualMouseCreation();
- mVirtualMouse.sendScrollEvent(new VirtualMouseScrollEvent.Builder()
- .setYAxisMovement(y)
- .build()
- );
+ float x = 0f;
+ float y = 0f;
+
+ switch (mouseKeyEvent) {
+ case UP_MOVE_OR_SCROLL -> {
+ y = MOUSE_SCROLL_STEP;
+ }
+ case DOWN_MOVE_OR_SCROLL -> {
+ y = -MOUSE_SCROLL_STEP;
+ }
+ case LEFT_MOVE_OR_SCROLL -> {
+ x = MOUSE_SCROLL_STEP;
+ }
+ case RIGHT_MOVE_OR_SCROLL -> {
+ x = -MOUSE_SCROLL_STEP;
+ }
+ default -> {
+ x = 0.0f;
+ y = 0.0f;
+ }
+ }
+ sendVirtualMouseScrollEvent(x, y);
if (DEBUG) {
Slog.d(LOG_TAG, "Performed mouse key event: " + mouseKeyEvent.name()
- + " for scroll action with axis movement (y=" + y + ")");
+ + " for scroll action with axis movement (x=" + x + ", y=" + y + ")");
}
}
@@ -340,8 +366,8 @@ public class MouseKeysInterceptor extends BaseEventStreamTransformation
* The method calculates the relative movement of the mouse pointer
* and sends the corresponding event to the virtual mouse.
*
- * The UP and DOWN pointer actions will only take place for their respective keys
- * if the scroll toggle is off.
+ * The UP, DOWN, LEFT, RIGHT pointer actions will only take place for their
+ * respective keys if the scroll toggle is off.
*
* @param keyCode The key code representing the direction or button press.
* Supported keys are:
@@ -349,8 +375,8 @@ public class MouseKeysInterceptor extends BaseEventStreamTransformation
* <li>{@link MouseKeysInterceptor.MouseKeyEvent#DIAGONAL_DOWN_LEFT_MOVE}
* <li>{@link MouseKeysInterceptor.MouseKeyEvent#DOWN_MOVE_OR_SCROLL}
* <li>{@link MouseKeysInterceptor.MouseKeyEvent#DIAGONAL_DOWN_RIGHT_MOVE}
- * <li>{@link MouseKeysInterceptor.MouseKeyEvent#LEFT_MOVE}
- * <li>{@link MouseKeysInterceptor.MouseKeyEvent#RIGHT_MOVE}
+ * <li>{@link MouseKeysInterceptor.MouseKeyEvent#LEFT_MOVE_OR_SCROLL}
+ * <li>{@link MouseKeysInterceptor.MouseKeyEvent#RIGHT_MOVE_OR_SCROLL}
* <li>{@link MouseKeysInterceptor.MouseKeyEvent#DIAGONAL_UP_LEFT_MOVE}
* <li>{@link MouseKeysInterceptor.MouseKeyEvent#UP_MOVE_OR_SCROLL}
* <li>{@link MouseKeysInterceptor.MouseKeyEvent#DIAGONAL_UP_RIGHT_MOVE}
@@ -377,10 +403,10 @@ public class MouseKeysInterceptor extends BaseEventStreamTransformation
x = MOUSE_POINTER_MOVEMENT_STEP / sqrt(2);
y = MOUSE_POINTER_MOVEMENT_STEP / sqrt(2);
}
- case LEFT_MOVE -> {
+ case LEFT_MOVE_OR_SCROLL -> {
x = -MOUSE_POINTER_MOVEMENT_STEP;
}
- case RIGHT_MOVE -> {
+ case RIGHT_MOVE_OR_SCROLL -> {
x = MOUSE_POINTER_MOVEMENT_STEP;
}
case DIAGONAL_UP_LEFT_MOVE -> {
@@ -420,7 +446,9 @@ public class MouseKeysInterceptor extends BaseEventStreamTransformation
private boolean isMouseScrollKey(int keyCode, InputDevice inputDevice) {
return keyCode == MouseKeyEvent.UP_MOVE_OR_SCROLL.getKeyCode(inputDevice)
- || keyCode == MouseKeyEvent.DOWN_MOVE_OR_SCROLL.getKeyCode(inputDevice);
+ || keyCode == MouseKeyEvent.DOWN_MOVE_OR_SCROLL.getKeyCode(inputDevice)
+ || keyCode == MouseKeyEvent.LEFT_MOVE_OR_SCROLL.getKeyCode(inputDevice)
+ || keyCode == MouseKeyEvent.RIGHT_MOVE_OR_SCROLL.getKeyCode(inputDevice);
}
/**
@@ -597,7 +625,9 @@ public class MouseKeysInterceptor extends BaseEventStreamTransformation
});
mHandler.removeCallbacksAndMessages(null);
- mVirtualDevice.close();
+ if (mVirtualDevice != null) {
+ mVirtualDevice.close();
+ }
}
@Override
diff --git a/services/accessibility/java/com/android/server/accessibility/ProxyAccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/ProxyAccessibilityServiceConnection.java
index 4cb3d247edb0..cd97d838e3a0 100644
--- a/services/accessibility/java/com/android/server/accessibility/ProxyAccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/ProxyAccessibilityServiceConnection.java
@@ -109,14 +109,11 @@ public class ProxyAccessibilityServiceConnection extends AccessibilityServiceCon
return mDeviceId;
}
- /**
- * Called when the proxy is registered.
- */
- void initializeServiceInterface(IAccessibilityServiceClient serviceInterface)
- throws RemoteException {
- mServiceInterface = serviceInterface;
- mService = serviceInterface.asBinder();
- mServiceInterface.init(this, mId, this.mOverlayWindowTokens.get(mDisplayId));
+ /** Called when the proxy is registered. */
+ void initializeClient(IAccessibilityServiceClient client) throws RemoteException {
+ mClient = client;
+ mClientBinder = client.asBinder();
+ mClient.init(this, mId, this.mOverlayWindowTokens.get(mDisplayId));
}
/**
diff --git a/services/accessibility/java/com/android/server/accessibility/ProxyManager.java b/services/accessibility/java/com/android/server/accessibility/ProxyManager.java
index b4deeb0a6872..f8551457d04d 100644
--- a/services/accessibility/java/com/android/server/accessibility/ProxyManager.java
+++ b/services/accessibility/java/com/android/server/accessibility/ProxyManager.java
@@ -183,14 +183,12 @@ public class ProxyManager {
synchronized (mLock) {
mProxyA11yServiceConnections.put(displayId, connection);
- if (Flags.proxyUseAppsOnVirtualDeviceListener()) {
- if (mAppsOnVirtualDeviceListener == null) {
- mAppsOnVirtualDeviceListener = allRunningUids ->
- notifyProxyOfRunningAppsChange(allRunningUids);
- final VirtualDeviceManagerInternal localVdm = getLocalVdm();
- if (localVdm != null) {
- localVdm.registerAppsOnVirtualDeviceListener(mAppsOnVirtualDeviceListener);
- }
+ if (mAppsOnVirtualDeviceListener == null) {
+ mAppsOnVirtualDeviceListener = allRunningUids ->
+ notifyProxyOfRunningAppsChange(allRunningUids);
+ final VirtualDeviceManagerInternal localVdm = getLocalVdm();
+ if (localVdm != null) {
+ localVdm.registerAppsOnVirtualDeviceListener(mAppsOnVirtualDeviceListener);
}
}
if (mProxyA11yServiceConnections.size() == 1) {
@@ -214,7 +212,7 @@ public class ProxyManager {
mA11yInputFilter.disableFeaturesForDisplayIfInstalled(displayId);
}
});
- connection.initializeServiceInterface(client);
+ connection.initializeClient(client);
}
private void registerVirtualDeviceListener() {
@@ -331,14 +329,12 @@ public class ProxyManager {
// device.
if (!isProxyedDeviceId(deviceId)) {
synchronized (mLock) {
- if (Flags.proxyUseAppsOnVirtualDeviceListener()) {
- if (mProxyA11yServiceConnections.size() == 0) {
- final VirtualDeviceManagerInternal localVdm = getLocalVdm();
- if (localVdm != null && mAppsOnVirtualDeviceListener != null) {
- localVdm.unregisterAppsOnVirtualDeviceListener(
- mAppsOnVirtualDeviceListener);
- mAppsOnVirtualDeviceListener = null;
- }
+ if (mProxyA11yServiceConnections.size() == 0) {
+ final VirtualDeviceManagerInternal localVdm = getLocalVdm();
+ if (localVdm != null && mAppsOnVirtualDeviceListener != null) {
+ localVdm.unregisterAppsOnVirtualDeviceListener(
+ mAppsOnVirtualDeviceListener);
+ mAppsOnVirtualDeviceListener = null;
}
}
mSystemSupport.removeDeviceIdLocked(deviceId);
@@ -561,8 +557,8 @@ public class ProxyManager {
final ProxyAccessibilityServiceConnection proxy =
mProxyA11yServiceConnections.valueAt(i);
if (proxy != null && proxy.getDeviceId() == deviceId) {
- final IBinder proxyBinder = proxy.mService;
- final IAccessibilityServiceClient proxyInterface = proxy.mServiceInterface;
+ final IBinder proxyBinder = proxy.mClientBinder;
+ final IAccessibilityServiceClient proxyInterface = proxy.mClient;
if ((proxyBinder != null) && (proxyInterface != null)) {
interfaces.add(proxyInterface);
}
@@ -671,8 +667,7 @@ public class ProxyManager {
+ getLastSentStateLocked(deviceId));
Slog.v(LOG_TAG, "force update: " + forceUpdate);
}
- if ((getLastSentStateLocked(deviceId)) != proxyState
- || (Flags.proxyUseAppsOnVirtualDeviceListener() && forceUpdate)) {
+ if ((getLastSentStateLocked(deviceId)) != proxyState || forceUpdate) {
setLastStateLocked(deviceId, proxyState);
mMainHandler.post(() -> {
synchronized (mLock) {
@@ -873,33 +868,22 @@ public class ProxyManager {
for (int i = 0; i < clients.getRegisteredCallbackCount(); i++) {
final AccessibilityManagerService.Client client =
((AccessibilityManagerService.Client) clients.getRegisteredCallbackCookie(i));
- if (Flags.proxyUseAppsOnVirtualDeviceListener()) {
- if (deviceId == DEVICE_ID_DEFAULT || deviceId == DEVICE_ID_INVALID) {
- continue;
- }
- boolean uidBelongsToDevice =
- localVdm.getDeviceIdsForUid(client.mUid).contains(deviceId);
- if (client.mDeviceId != deviceId && uidBelongsToDevice) {
- if (DEBUG) {
- Slog.v(LOG_TAG, "Packages moved to device id " + deviceId + " are "
- + Arrays.toString(client.mPackageNames));
- }
- client.mDeviceId = deviceId;
- } else if (client.mDeviceId == deviceId && !uidBelongsToDevice) {
- client.mDeviceId = DEVICE_ID_DEFAULT;
- if (DEBUG) {
- Slog.v(LOG_TAG, "Packages moved to the default device from device id "
- + deviceId + " are " + Arrays.toString(client.mPackageNames));
- }
+ if (deviceId == DEVICE_ID_DEFAULT || deviceId == DEVICE_ID_INVALID) {
+ continue;
+ }
+ boolean uidBelongsToDevice =
+ localVdm.getDeviceIdsForUid(client.mUid).contains(deviceId);
+ if (client.mDeviceId != deviceId && uidBelongsToDevice) {
+ if (DEBUG) {
+ Slog.v(LOG_TAG, "Packages moved to device id " + deviceId + " are "
+ + Arrays.toString(client.mPackageNames));
}
- } else {
- if (deviceId != DEVICE_ID_DEFAULT && deviceId != DEVICE_ID_INVALID
- && localVdm.getDeviceIdsForUid(client.mUid).contains(deviceId)) {
- if (DEBUG) {
- Slog.v(LOG_TAG, "Packages moved to device id " + deviceId + " are "
- + Arrays.toString(client.mPackageNames));
- }
- client.mDeviceId = deviceId;
+ client.mDeviceId = deviceId;
+ } else if (client.mDeviceId == deviceId && !uidBelongsToDevice) {
+ client.mDeviceId = DEVICE_ID_DEFAULT;
+ if (DEBUG) {
+ Slog.v(LOG_TAG, "Packages moved to the default device from device id "
+ + deviceId + " are " + Arrays.toString(client.mPackageNames));
}
}
}
diff --git a/services/accessibility/java/com/android/server/accessibility/UiAutomationManager.java b/services/accessibility/java/com/android/server/accessibility/UiAutomationManager.java
index f85d786f89c5..ed4eeb534412 100644
--- a/services/accessibility/java/com/android/server/accessibility/UiAutomationManager.java
+++ b/services/accessibility/java/com/android/server/accessibility/UiAutomationManager.java
@@ -107,8 +107,7 @@ class UiAutomationManager {
Binder.getCallingUserHandle().getIdentifier());
if (mUiAutomationService != null) {
throw new IllegalStateException(
- "UiAutomationService " + mUiAutomationService.mServiceInterface
- + "already registered!");
+ "UiAutomationService " + mUiAutomationService.mClient + "already registered!");
}
try {
@@ -130,10 +129,9 @@ class UiAutomationManager {
mainHandler, mLock, securityPolicy, systemSupport, trace, windowManagerInternal,
systemActionPerformer, awm);
mUiAutomationServiceOwner = owner;
- mUiAutomationService.mServiceInterface = serviceClient;
+ mUiAutomationService.mClient = serviceClient;
try {
- mUiAutomationService.mServiceInterface.asBinder().linkToDeath(mUiAutomationService,
- 0);
+ mUiAutomationService.mClient.asBinder().linkToDeath(mUiAutomationService, 0);
} catch (RemoteException re) {
Slog.e(LOG_TAG, "Failed registering death link: " + re);
destroyUiAutomationService();
@@ -149,10 +147,10 @@ class UiAutomationManager {
synchronized (mLock) {
if (useAccessibility()
&& ((mUiAutomationService == null)
- || (serviceClient == null)
- || (mUiAutomationService.mServiceInterface == null)
- || (serviceClient.asBinder()
- != mUiAutomationService.mServiceInterface.asBinder()))) {
+ || (serviceClient == null)
+ || (mUiAutomationService.mClient == null)
+ || (serviceClient.asBinder()
+ != mUiAutomationService.mClient.asBinder()))) {
throw new IllegalStateException("UiAutomationService " + serviceClient
+ " not registered!");
}
@@ -230,8 +228,7 @@ class UiAutomationManager {
private void destroyUiAutomationService() {
synchronized (mLock) {
if (mUiAutomationService != null) {
- mUiAutomationService.mServiceInterface.asBinder().unlinkToDeath(
- mUiAutomationService, 0);
+ mUiAutomationService.mClient.asBinder().unlinkToDeath(mUiAutomationService, 0);
mUiAutomationService.onRemoved();
mUiAutomationService.resetLocked();
mUiAutomationService = null;
@@ -271,40 +268,48 @@ class UiAutomationManager {
void connectServiceUnknownThread() {
// This needs to be done on the main thread
- mMainHandler.post(() -> {
- try {
- final IAccessibilityServiceClient serviceInterface;
- final UiAutomationService uiAutomationService;
- synchronized (mLock) {
- serviceInterface = mServiceInterface;
- uiAutomationService = mUiAutomationService;
- if (serviceInterface == null) {
- mService = null;
- } else {
- mService = mServiceInterface.asBinder();
- mService.linkToDeath(this, 0);
+ mMainHandler.post(
+ () -> {
+ try {
+ final IAccessibilityServiceClient client;
+ final UiAutomationService uiAutomationService;
+ synchronized (mLock) {
+ client = mClient;
+ uiAutomationService = mUiAutomationService;
+ if (client == null) {
+ mClientBinder = null;
+ } else {
+ mClientBinder = mClient.asBinder();
+ mClientBinder.linkToDeath(this, 0);
+ }
+ }
+ // If the client is null, the UiAutomation has been shut down on
+ // another thread.
+ if (client != null && uiAutomationService != null) {
+ uiAutomationService.addWindowTokensForAllDisplays();
+ if (mTrace.isA11yTracingEnabledForTypes(
+ AccessibilityTrace.FLAGS_ACCESSIBILITY_SERVICE_CLIENT)) {
+ mTrace.logTrace(
+ "UiAutomationService.connectServiceUnknownThread",
+ AccessibilityTrace.FLAGS_ACCESSIBILITY_SERVICE_CLIENT,
+ "serviceConnection="
+ + this
+ + ";connectionId="
+ + mId
+ + "windowToken="
+ + mOverlayWindowTokens.get(
+ Display.DEFAULT_DISPLAY));
+ }
+ client.init(
+ this,
+ mId,
+ mOverlayWindowTokens.get(Display.DEFAULT_DISPLAY));
+ }
+ } catch (RemoteException re) {
+ Slog.w(LOG_TAG, "Error initializing connection", re);
+ destroyUiAutomationService();
}
- }
- // If the serviceInterface is null, the UiAutomation has been shut down on
- // another thread.
- if (serviceInterface != null && uiAutomationService != null) {
- uiAutomationService.addWindowTokensForAllDisplays();
- if (mTrace.isA11yTracingEnabledForTypes(
- AccessibilityTrace.FLAGS_ACCESSIBILITY_SERVICE_CLIENT)) {
- mTrace.logTrace("UiAutomationService.connectServiceUnknownThread",
- AccessibilityTrace.FLAGS_ACCESSIBILITY_SERVICE_CLIENT,
- "serviceConnection=" + this + ";connectionId=" + mId
- + "windowToken="
- + mOverlayWindowTokens.get(Display.DEFAULT_DISPLAY));
- }
- serviceInterface.init(this, mId,
- mOverlayWindowTokens.get(Display.DEFAULT_DISPLAY));
- }
- } catch (RemoteException re) {
- Slog.w(LOG_TAG, "Error initializing connection", re);
- destroyUiAutomationService();
- }
- });
+ });
}
@Override
diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
index 0ed239e442e7..0cbbf6da022b 100644
--- a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
@@ -240,10 +240,7 @@ public class TouchExplorer extends BaseEventStreamTransformation
}
private void clear(MotionEvent event, int policyFlags) {
- if (mState.isTouchExploring() || Flags.sendHoverEventsBasedOnEventStream()) {
- // If a touch exploration gesture is in progress send events for its end.
- sendHoverExitAndTouchExplorationGestureEndIfNeeded(policyFlags);
- }
+ sendHoverExitAndTouchExplorationGestureEndIfNeeded(policyFlags);
mDraggingPointerId = INVALID_POINTER_ID;
// Send exit to any pointers that we have delivered as part of delegating or dragging.
mDispatcher.sendUpForInjectedDownPointers(event, policyFlags);
@@ -562,10 +559,7 @@ public class TouchExplorer extends BaseEventStreamTransformation
// clear any hover events that might have been queued and never sent.
mSendHoverEnterAndMoveDelayed.clear();
mSendHoverExitDelayed.cancel();
- // If a touch exploration gesture is in progress send events for its end.
- if (mState.isTouchExploring() || Flags.sendHoverEventsBasedOnEventStream()) {
- sendHoverExitAndTouchExplorationGestureEndIfNeeded(policyFlags);
- }
+ sendHoverExitAndTouchExplorationGestureEndIfNeeded(policyFlags);
if (mState.isClear()) {
if (!mSendHoverEnterAndMoveDelayed.isPending()) {
// Queue a delayed transition to STATE_TOUCH_EXPLORING.
@@ -1599,9 +1593,7 @@ public class TouchExplorer extends BaseEventStreamTransformation
if (mEvents.size() == 0) {
return;
}
- if (Flags.sendHoverEventsBasedOnEventStream()) {
- sendHoverExitAndTouchExplorationGestureEndIfNeeded(mPolicyFlags);
- }
+ sendHoverExitAndTouchExplorationGestureEndIfNeeded(mPolicyFlags);
// Send an accessibility event to announce the touch exploration start.
mDispatcher.sendAccessibilityEvent(TYPE_TOUCH_EXPLORATION_GESTURE_START);
if (isSendMotionEventsEnabled()) {
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java
index 6b6b39df24d7..11b8ccb70dfb 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java
@@ -47,7 +47,6 @@ import android.util.MathUtils;
import android.util.Slog;
import android.util.SparseArray;
import android.util.TypedValue;
-import android.view.Display;
import android.view.DisplayInfo;
import android.view.MagnificationSpec;
import android.view.View;
@@ -65,6 +64,7 @@ import com.android.server.LocalServices;
import com.android.server.accessibility.AccessibilityManagerService;
import com.android.server.accessibility.AccessibilityTraceManager;
import com.android.server.accessibility.Flags;
+import com.android.server.input.InputManagerInternal;
import com.android.server.wm.WindowManagerInternal;
import java.util.ArrayList;
@@ -397,7 +397,7 @@ public class FullScreenMagnificationController implements
mCurrentMagnificationSpec.offsetX, mCurrentMagnificationSpec.offsetY)) {
sendSpecToAnimation(mCurrentMagnificationSpec, null);
}
- onMagnificationChangedLocked();
+ onMagnificationChangedLocked(/* isScaleTransient= */ false);
}
magnified.recycle();
}
@@ -475,8 +475,16 @@ public class FullScreenMagnificationController implements
return mIdOfLastServiceToMagnify;
}
+ /**
+ * This is invoked whenever magnification change happens.
+ *
+ * @param isScaleTransient represents that if the scale is being changed and the changed
+ * value may be short lived and be updated again soon.
+ * Calling the method usually notifies input manager to update the
+ * cursor scale, but setting this value {@code true} prevents it.
+ */
@GuardedBy("mLock")
- void onMagnificationChangedLocked() {
+ void onMagnificationChangedLocked(boolean isScaleTransient) {
final float scale = getScale();
final float centerX = getCenterX();
final float centerY = getCenterY();
@@ -499,6 +507,10 @@ public class FullScreenMagnificationController implements
} else {
hideThumbnail();
}
+
+ if (!isScaleTransient) {
+ notifyScaleForInput(mDisplayId, scale);
+ }
}
@GuardedBy("mLock")
@@ -612,8 +624,9 @@ public class FullScreenMagnificationController implements
* Directly Zooms out the scale to 1f with animating the transition. This method is
* triggered only by service automatically, such as when user context changed.
*/
+ @GuardedBy("mLock")
void zoomOutFromService() {
- setScaleAndCenter(1.0f, Float.NaN, Float.NaN,
+ setScaleAndCenter(1.0f, Float.NaN, Float.NaN, /* isScaleTransient= */ false,
transformToStubCallback(true),
AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID);
mZoomedOutFromService = true;
@@ -641,7 +654,7 @@ public class FullScreenMagnificationController implements
setActivated(false);
if (changed) {
spec.clear();
- onMagnificationChangedLocked();
+ onMagnificationChangedLocked(/* isScaleTransient= */ false);
}
mIdOfLastServiceToMagnify = INVALID_SERVICE_ID;
sendSpecToAnimation(spec, animationCallback);
@@ -652,7 +665,7 @@ public class FullScreenMagnificationController implements
}
@GuardedBy("mLock")
- boolean setScale(float scale, float pivotX, float pivotY,
+ boolean setScale(float scale, float pivotX, float pivotY, boolean isScaleTransient,
boolean animate, int id) {
if (!mRegistered) {
return false;
@@ -675,19 +688,20 @@ public class FullScreenMagnificationController implements
final float centerX = normPivotX + offsetX;
final float centerY = normPivotY + offsetY;
mIdOfLastServiceToMagnify = id;
- return setScaleAndCenter(scale, centerX, centerY, transformToStubCallback(animate), id);
+ return setScaleAndCenter(scale, centerX, centerY, isScaleTransient,
+ transformToStubCallback(animate), id);
}
@GuardedBy("mLock")
boolean setScaleAndCenter(float scale, float centerX, float centerY,
- MagnificationAnimationCallback animationCallback, int id) {
+ boolean isScaleTransient, MagnificationAnimationCallback animationCallback,
+ int id) {
if (!mRegistered) {
return false;
}
- // If the border implementation is on system ui side but the connection is not
+ // The border implementation is on system ui side but the connection is not
// established, the fullscreen magnification should not work.
- if (com.android.window.flags.Flags.alwaysDrawMagnificationFullscreenBorder()
- && !mMagnificationConnectionStateSupplier.get()) {
+ if (!mMagnificationConnectionStateSupplier.get()) {
return false;
}
if (DEBUG) {
@@ -697,7 +711,7 @@ public class FullScreenMagnificationController implements
+ animationCallback + ", id = " + id + ")");
}
boolean changed = setActivated(true);
- changed |= updateMagnificationSpecLocked(scale, centerX, centerY);
+ changed |= updateMagnificationSpecLocked(scale, centerX, centerY, isScaleTransient);
sendSpecToAnimation(mCurrentMagnificationSpec, animationCallback);
if (isActivated() && (id != INVALID_SERVICE_ID)) {
mIdOfLastServiceToMagnify = id;
@@ -774,7 +788,9 @@ public class FullScreenMagnificationController implements
* @return {@code true} if the magnification spec changed or {@code false}
* otherwise
*/
- boolean updateMagnificationSpecLocked(float scale, float centerX, float centerY) {
+ @GuardedBy("mLock")
+ boolean updateMagnificationSpecLocked(float scale, float centerX, float centerY,
+ boolean isScaleTransient) {
// Handle defaults.
if (Float.isNaN(centerX)) {
centerX = getCenterX();
@@ -802,7 +818,7 @@ public class FullScreenMagnificationController implements
changed |= updateCurrentSpecWithOffsetsLocked(nonNormOffsetX, nonNormOffsetY);
if (changed) {
- onMagnificationChangedLocked();
+ onMagnificationChangedLocked(isScaleTransient);
}
return changed;
@@ -817,7 +833,7 @@ public class FullScreenMagnificationController implements
final float nonNormOffsetX = mCurrentMagnificationSpec.offsetX - offsetX;
final float nonNormOffsetY = mCurrentMagnificationSpec.offsetY - offsetY;
if (updateCurrentSpecWithOffsetsLocked(nonNormOffsetX, nonNormOffsetY)) {
- onMagnificationChangedLocked();
+ onMagnificationChangedLocked(/* isScaleTransient= */ false);
}
if (id != INVALID_SERVICE_ID) {
mIdOfLastServiceToMagnify = id;
@@ -862,7 +878,7 @@ public class FullScreenMagnificationController implements
}
synchronized (mLock) {
mCurrentMagnificationSpec.setTo(lastSpecSent);
- onMagnificationChangedLocked();
+ onMagnificationChangedLocked(/* isScaleTransient= */ false);
}
}
});
@@ -956,6 +972,7 @@ public class FullScreenMagnificationController implements
context,
traceManager,
LocalServices.getService(WindowManagerInternal.class),
+ LocalServices.getService(InputManagerInternal.class),
new Handler(context.getMainLooper()),
context.getResources().getInteger(R.integer.config_longAnimTime)),
lock,
@@ -1465,20 +1482,24 @@ public class FullScreenMagnificationController implements
* @param scale the target scale, must be >= 1
* @param pivotX the screen-relative X coordinate around which to scale
* @param pivotY the screen-relative Y coordinate around which to scale
+ * @param isScaleTransient {@code true} if the scale is for a short time and potentially changed
+ * soon. {@code false} otherwise.
* @param animate {@code true} to animate the transition, {@code false}
* to transition immediately
* @param id the ID of the service requesting the change
* @return {@code true} if the magnification spec changed, {@code false} if
* the spec did not change
*/
+ @SuppressWarnings("GuardedBy")
+ // errorprone cannot recognize an inner class guarded by an outer class member.
public boolean setScale(int displayId, float scale, float pivotX, float pivotY,
- boolean animate, int id) {
+ boolean isScaleTransient, boolean animate, int id) {
synchronized (mLock) {
final DisplayMagnification display = mDisplays.get(displayId);
if (display == null) {
return false;
}
- return display.setScale(scale, pivotX, pivotY, animate, id);
+ return display.setScale(scale, pivotX, pivotY, isScaleTransient, animate, id);
}
}
@@ -1497,6 +1518,8 @@ public class FullScreenMagnificationController implements
* @return {@code true} if the magnification spec changed, {@code false} if
* the spec did not change
*/
+ @SuppressWarnings("GuardedBy")
+ // errorprone cannot recognize an inner class guarded by an outer class member.
public boolean setCenter(int displayId, float centerX, float centerY, boolean animate, int id) {
synchronized (mLock) {
final DisplayMagnification display = mDisplays.get(displayId);
@@ -1504,7 +1527,7 @@ public class FullScreenMagnificationController implements
return false;
}
return display.setScaleAndCenter(Float.NaN, centerX, centerY,
- animate ? STUB_ANIMATION_CALLBACK : null, id);
+ /* isScaleTransient= */ false, animate ? STUB_ANIMATION_CALLBACK : null, id);
}
}
@@ -1527,7 +1550,32 @@ public class FullScreenMagnificationController implements
*/
public boolean setScaleAndCenter(int displayId, float scale, float centerX, float centerY,
boolean animate, int id) {
- return setScaleAndCenter(displayId, scale, centerX, centerY,
+ return setScaleAndCenter(displayId, scale, centerX, centerY, /* isScaleTransient= */ false,
+ transformToStubCallback(animate), id);
+ }
+
+ /**
+ * Sets the scale and center of the magnified region, optionally
+ * animating the transition. If animation is disabled, the transition
+ * is immediate.
+ *
+ * @param displayId The logical display id.
+ * @param scale the target scale, or {@link Float#NaN} to leave unchanged
+ * @param centerX the screen-relative X coordinate around which to
+ * center and scale, or {@link Float#NaN} to leave unchanged
+ * @param centerY the screen-relative Y coordinate around which to
+ * center and scale, or {@link Float#NaN} to leave unchanged
+ * @param isScaleTransient {@code true} if the scale is for a short time and potentially changed
+ * soon. {@code false} otherwise.
+ * @param animate {@code true} to animate the transition, {@code false}
+ * to transition immediately
+ * @param id the ID of the service requesting the change
+ * @return {@code true} if the magnification spec changed, {@code false} if
+ * the spec did not change
+ */
+ public boolean setScaleAndCenter(int displayId, float scale, float centerX, float centerY,
+ boolean isScaleTransient, boolean animate, int id) {
+ return setScaleAndCenter(displayId, scale, centerX, centerY, isScaleTransient,
transformToStubCallback(animate), id);
}
@@ -1542,20 +1590,25 @@ public class FullScreenMagnificationController implements
* center and scale, or {@link Float#NaN} to leave unchanged
* @param centerY the screen-relative Y coordinate around which to
* center and scale, or {@link Float#NaN} to leave unchanged
+ * @param isScaleTransient {@code true} if the scale is for a short time and potentially changed
+ * soon. {@code false} otherwise.
* @param animationCallback Called when the animation result is valid.
* {@code null} to transition immediately
* @param id the ID of the service requesting the change
* @return {@code true} if the magnification spec changed, {@code false} if
* the spec did not change
*/
+ @SuppressWarnings("GuardedBy")
+ // errorprone cannot recognize an inner class guarded by an outer class member.
public boolean setScaleAndCenter(int displayId, float scale, float centerX, float centerY,
- MagnificationAnimationCallback animationCallback, int id) {
+ boolean isScaleTransient, MagnificationAnimationCallback animationCallback, int id) {
synchronized (mLock) {
final DisplayMagnification display = mDisplays.get(displayId);
if (display == null) {
return false;
}
- return display.setScaleAndCenter(scale, centerX, centerY, animationCallback, id);
+ return display.setScaleAndCenter(scale, centerX, centerY, isScaleTransient,
+ animationCallback, id);
}
}
@@ -1570,6 +1623,8 @@ public class FullScreenMagnificationController implements
* screen pixels.
* @param id the ID of the service requesting the change
*/
+ @SuppressWarnings("GuardedBy")
+ // errorprone cannot recognize an inner class guarded by an outer class member.
public void offsetMagnifiedRegion(int displayId, float offsetX, float offsetY, int id) {
synchronized (mLock) {
final DisplayMagnification display = mDisplays.get(displayId);
@@ -1637,9 +1692,12 @@ public class FullScreenMagnificationController implements
* <strong>if scale is >= {@link MagnificationConstants.PERSISTED_SCALE_MIN_VALUE}</strong>.
* We assume if the scale is < {@link MagnificationConstants.PERSISTED_SCALE_MIN_VALUE}, there
* will be no obvious magnification effect.
+ * Only the value of the default display is persisted in user's settings.
*/
public void persistScale(int displayId) {
- final float scale = getScale(Display.DEFAULT_DISPLAY);
+ final float scale = getScale(displayId);
+ notifyScaleForInput(displayId, scale);
+
if (scale < MagnificationConstants.PERSISTED_SCALE_MIN_VALUE) {
return;
}
@@ -1665,6 +1723,8 @@ public class FullScreenMagnificationController implements
*
* @param displayId The logical display id.
*/
+ @SuppressWarnings("GuardedBy")
+ // errorprone cannot recognize an inner class guarded by an outer class member.
private void zoomOutFromService(int displayId) {
synchronized (mLock) {
final DisplayMagnification display = mDisplays.get(displayId);
@@ -1691,6 +1751,20 @@ public class FullScreenMagnificationController implements
}
/**
+ * Notifies input manager that magnification scale changed non-transiently
+ * so that pointer cursor is scaled as well.
+ *
+ * @param displayId The logical display id.
+ * @param scale The new scale factor.
+ */
+ public void notifyScaleForInput(int displayId, float scale) {
+ if (Flags.magnificationEnlargePointerBugfix()) {
+ mControllerCtx.getInputManager()
+ .setAccessibilityPointerIconScaleFactor(displayId, scale);
+ }
+ }
+
+ /**
* Resets all displays' magnification if last magnifying service is disabled.
*
* @param connectionId
@@ -2166,6 +2240,7 @@ public class FullScreenMagnificationController implements
private final Context mContext;
private final AccessibilityTraceManager mTrace;
private final WindowManagerInternal mWindowManager;
+ private final InputManagerInternal mInputManager;
private final Handler mHandler;
private final Long mAnimationDuration;
@@ -2175,11 +2250,13 @@ public class FullScreenMagnificationController implements
public ControllerContext(@NonNull Context context,
@NonNull AccessibilityTraceManager traceManager,
@NonNull WindowManagerInternal windowManager,
+ @NonNull InputManagerInternal inputManager,
@NonNull Handler handler,
long animationDuration) {
mContext = context;
mTrace = traceManager;
mWindowManager = windowManager;
+ mInputManager = inputManager;
mHandler = handler;
mAnimationDuration = animationDuration;
}
@@ -2209,6 +2286,14 @@ public class FullScreenMagnificationController implements
}
/**
+ * @return InputManagerInternal
+ */
+ @NonNull
+ public InputManagerInternal getInputManager() {
+ return mInputManager;
+ }
+
+ /**
* @return Handler for main looper
*/
@NonNull
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java
index a19fdddea49c..d11ae0a6ad97 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java
@@ -58,8 +58,6 @@ import android.util.TypedValue;
import android.view.GestureDetector;
import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.MotionEvent;
-import android.view.MotionEvent.PointerCoords;
-import android.view.MotionEvent.PointerProperties;
import android.view.ScaleGestureDetector;
import android.view.ScaleGestureDetector.OnScaleGestureListener;
import android.view.VelocityTracker;
@@ -155,9 +153,6 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH
@VisibleForTesting State mCurrentState;
@VisibleForTesting State mPreviousState;
- private PointerCoords[] mTempPointerCoords;
- private PointerProperties[] mTempPointerProperties;
-
@VisibleForTesting static final int OVERSCROLL_NONE = 0;
@VisibleForTesting static final int OVERSCROLL_LEFT_EDGE = 1;
@VisibleForTesting static final int OVERSCROLL_RIGHT_EDGE = 2;
@@ -345,7 +340,7 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH
@Override
void handleMouseOrStylusEvent(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
- if (Flags.enableMagnificationFollowsMouse()) {
+ if (Flags.enableMagnificationFollowsMouseBugfix()) {
if (mFullScreenMagnificationController.isActivated(mDisplayId)) {
// TODO(b/354696546): Allow mouse/stylus to activate whichever display they are
// over, rather than only interacting with the current display.
@@ -430,38 +425,6 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH
mPanningScalingState.clear();
}
- private PointerCoords[] getTempPointerCoordsWithMinSize(int size) {
- final int oldSize = (mTempPointerCoords != null) ? mTempPointerCoords.length : 0;
- if (oldSize < size) {
- PointerCoords[] oldTempPointerCoords = mTempPointerCoords;
- mTempPointerCoords = new PointerCoords[size];
- if (oldTempPointerCoords != null) {
- System.arraycopy(oldTempPointerCoords, 0, mTempPointerCoords, 0, oldSize);
- }
- }
- for (int i = oldSize; i < size; i++) {
- mTempPointerCoords[i] = new PointerCoords();
- }
- return mTempPointerCoords;
- }
-
- private PointerProperties[] getTempPointerPropertiesWithMinSize(int size) {
- final int oldSize = (mTempPointerProperties != null) ? mTempPointerProperties.length
- : 0;
- if (oldSize < size) {
- PointerProperties[] oldTempPointerProperties = mTempPointerProperties;
- mTempPointerProperties = new PointerProperties[size];
- if (oldTempPointerProperties != null) {
- System.arraycopy(oldTempPointerProperties, 0, mTempPointerProperties, 0,
- oldSize);
- }
- }
- for (int i = oldSize; i < size; i++) {
- mTempPointerProperties[i] = new PointerProperties();
- }
- return mTempPointerProperties;
- }
-
@VisibleForTesting
void transitionTo(State state) {
if (DEBUG_STATE_TRANSITIONS) {
@@ -617,7 +580,8 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH
}
if (DEBUG_PANNING_SCALING) Slog.i(mLogTag, "Scaled content to: " + scale + "x");
- mFullScreenMagnificationController.setScale(mDisplayId, scale, pivotX, pivotY, false,
+ mFullScreenMagnificationController.setScale(mDisplayId, scale, pivotX, pivotY,
+ /* isScaleTransient= */ true, /* animate= */ false,
AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID);
checkShouldDetectPassPersistedScale();
@@ -1206,7 +1170,7 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH
protected void cacheDelayedMotionEvent(MotionEvent event, MotionEvent rawEvent,
int policyFlags) {
- if (Flags.enableMagnificationFollowsMouse()
+ if (Flags.enableMagnificationFollowsMouseBugfix()
&& !event.isFromSource(SOURCE_TOUCHSCREEN)) {
// Only touch events need to be cached and sent later.
return;
@@ -1974,6 +1938,7 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH
/* scale= */ scale,
/* centerX= */ mPivotEdge.x,
/* centerY= */ mPivotEdge.y,
+ /* isScaleTransient= */ true,
/* animate= */ true,
/* id= */ AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID);
if (scale == 1.0f) {
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java
index 1489d16c3764..058b2be5f4b3 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java
@@ -27,6 +27,7 @@ import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_
import static com.android.server.accessibility.AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID;
import android.accessibilityservice.MagnificationConfig;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
@@ -50,7 +51,6 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.server.LocalServices;
import com.android.server.accessibility.AccessibilityManagerService;
import com.android.server.wm.WindowManagerInternal;
-import com.android.window.flags.Flags;
import java.util.concurrent.Executor;
@@ -101,6 +101,7 @@ public class MagnificationController implements MagnificationConnectionManager.C
private int mMagnificationCapabilities = ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN;
/** Whether the platform supports window magnification feature. */
private final boolean mSupportWindowMagnification;
+ private final MagnificationScaleStepProvider mScaleStepProvider;
private final Executor mBackgroundExecutor;
@@ -131,6 +132,14 @@ public class MagnificationController implements MagnificationConnectionManager.C
.UiChangesForAccessibilityCallbacks> mAccessibilityCallbacksDelegateArray =
new SparseArray<>();
+ // Direction magnifier scale can be altered.
+ public static final int ZOOM_DIRECTION_IN = 0;
+ public static final int ZOOM_DIRECTION_OUT = 1;
+
+ @IntDef({ZOOM_DIRECTION_IN, ZOOM_DIRECTION_OUT})
+ public @interface ZoomDirection {
+ }
+
/**
* A callback to inform the magnification transition result on the given display.
*/
@@ -144,6 +153,41 @@ public class MagnificationController implements MagnificationConnectionManager.C
void onResult(int displayId, boolean success);
}
+
+ /**
+ * An interface to configure how much the magnification scale should be affected when moving in
+ * steps.
+ */
+ public interface MagnificationScaleStepProvider {
+ /**
+ * Calculate the next value given which direction (in/out) to adjust the magnification
+ * scale.
+ *
+ * @param currentScale The current magnification scale value.
+ * @param direction Whether to zoom in or out.
+ * @return The next scale value.
+ */
+ float nextScaleStep(float currentScale, @ZoomDirection int direction);
+ }
+
+ public static class DefaultMagnificationScaleStepProvider implements
+ MagnificationScaleStepProvider {
+ // Factor of magnification scale. For example, when this value is 1.189, scale
+ // value will be changed x1.000, x1.189, x1.414, x1.681, x2.000, ...
+ // Note: this value is 2.0 ^ (1 / 4).
+ public static final float ZOOM_STEP_SCALE_FACTOR = 1.18920712f;
+
+ @Override
+ public float nextScaleStep(float currentScale, @ZoomDirection int direction) {
+ final int stepDelta = direction == ZOOM_DIRECTION_IN ? 1 : -1;
+ final long scaleIndex = Math.round(
+ Math.log(currentScale) / Math.log(ZOOM_STEP_SCALE_FACTOR));
+ final float nextScale = (float) Math.pow(ZOOM_STEP_SCALE_FACTOR,
+ scaleIndex + stepDelta);
+ return MagnificationScaleProvider.constrainScale(nextScale);
+ }
+ }
+
public MagnificationController(AccessibilityManagerService ams, Object lock,
Context context, MagnificationScaleProvider scaleProvider,
Executor backgroundExecutor) {
@@ -156,6 +200,7 @@ public class MagnificationController implements MagnificationConnectionManager.C
.getAccessibilityController().setUiChangesForAccessibilityCallbacks(this);
mSupportWindowMagnification = context.getPackageManager().hasSystemFeature(
FEATURE_WINDOW_MAGNIFICATION);
+ mScaleStepProvider = new DefaultMagnificationScaleStepProvider();
mAlwaysOnMagnificationFeatureFlag = new AlwaysOnMagnificationFeatureFlag(context);
mAlwaysOnMagnificationFeatureFlag.addOnChangedListener(
@@ -176,7 +221,8 @@ public class MagnificationController implements MagnificationConnectionManager.C
public void onPerformScaleAction(int displayId, float scale, boolean updatePersistence) {
if (getFullScreenMagnificationController().isActivated(displayId)) {
getFullScreenMagnificationController().setScaleAndCenter(displayId, scale,
- Float.NaN, Float.NaN, false, MAGNIFICATION_GESTURE_HANDLER_ID);
+ Float.NaN, Float.NaN, /* isScaleTransient= */ !updatePersistence, false,
+ MAGNIFICATION_GESTURE_HANDLER_ID);
if (updatePersistence) {
getFullScreenMagnificationController().persistScale(displayId);
}
@@ -371,7 +417,7 @@ public class MagnificationController implements MagnificationConnectionManager.C
}
screenMagnificationController.setScaleAndCenter(displayId, targetScale,
magnificationCenter.x, magnificationCenter.y,
- magnificationAnimationCallback, id);
+ /* isScaleTransient= */ false, magnificationAnimationCallback, id);
} else {
if (screenMagnificationController.isRegistered(displayId)) {
screenMagnificationController.reset(displayId, false);
@@ -587,10 +633,8 @@ public class MagnificationController implements MagnificationConnectionManager.C
@Override
public void onFullScreenMagnificationActivationState(int displayId, boolean activated) {
- if (Flags.alwaysDrawMagnificationFullscreenBorder()) {
- getMagnificationConnectionManager()
- .onFullscreenMagnificationActivationChanged(displayId, activated);
- }
+ getMagnificationConnectionManager()
+ .onFullscreenMagnificationActivationChanged(displayId, activated);
if (activated) {
synchronized (mLock) {
@@ -890,6 +934,37 @@ public class MagnificationController implements MagnificationConnectionManager.C
return isActivated;
}
+ /**
+ * Scales the magnifier on the given display one step in/out based on the zoomIn param.
+ *
+ * @param displayId The logical display id.
+ * @param direction Whether the scale should be zoomed in or out.
+ * @return {@code true} if the magnification scale was affected.
+ */
+ public boolean scaleMagnificationByStep(int displayId, @ZoomDirection int direction) {
+ if (getFullScreenMagnificationController().isActivated(displayId)) {
+ final float magnificationScale = getFullScreenMagnificationController().getScale(
+ displayId);
+ final float nextMagnificationScale = mScaleStepProvider.nextScaleStep(
+ magnificationScale, direction);
+ getFullScreenMagnificationController().setScaleAndCenter(displayId,
+ nextMagnificationScale,
+ Float.NaN, Float.NaN, true, MAGNIFICATION_GESTURE_HANDLER_ID);
+ return nextMagnificationScale != magnificationScale;
+ }
+
+ if (getMagnificationConnectionManager().isWindowMagnifierEnabled(displayId)) {
+ final float magnificationScale = getMagnificationConnectionManager().getScale(
+ displayId);
+ final float nextMagnificationScale = mScaleStepProvider.nextScaleStep(
+ magnificationScale, direction);
+ getMagnificationConnectionManager().setScale(displayId, nextMagnificationScale);
+ return nextMagnificationScale != magnificationScale;
+ }
+
+ return false;
+ }
+
private final class DisableMagnificationCallback implements
MagnificationAnimationCallback {
private final TransitionCallBack mTransitionCallBack;
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationGestureHandler.java b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationGestureHandler.java
index 446123f07f64..fa86ba39bb1a 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationGestureHandler.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationGestureHandler.java
@@ -146,7 +146,8 @@ public abstract class MagnificationGestureHandler extends BaseEventStreamTransfo
} break;
case SOURCE_MOUSE:
case SOURCE_STYLUS: {
- if (magnificationShortcutExists() && Flags.enableMagnificationFollowsMouse()) {
+ if (magnificationShortcutExists()
+ && Flags.enableMagnificationFollowsMouseBugfix()) {
handleMouseOrStylusEvent(event, rawEvent, policyFlags);
}
}
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/PanningScalingHandler.java b/services/accessibility/java/com/android/server/accessibility/magnification/PanningScalingHandler.java
index 6b48d2bacf9d..a4568aaa7a0d 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/PanningScalingHandler.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/PanningScalingHandler.java
@@ -31,7 +31,6 @@ import android.view.ScaleGestureDetector;
import android.view.ViewConfiguration;
import com.android.internal.R;
-import com.android.server.accessibility.Flags;
/**
* Handles the behavior while receiving scaling and panning gestures if it's enabled.
@@ -73,13 +72,9 @@ class PanningScalingHandler extends
mMaxScale = maxScale;
mMinScale = minScale;
mBlockScroll = blockScroll;
- if (Flags.pinchZoomZeroMinSpan()) {
- mScaleGestureDetector = new ScaleGestureDetector(context,
- ViewConfiguration.get(context).getScaledTouchSlop() * 2,
- /* minSpan= */ 0, Handler.getMain(), this);
- } else {
- mScaleGestureDetector = new ScaleGestureDetector(context, this, Handler.getMain());
- }
+ mScaleGestureDetector = new ScaleGestureDetector(context,
+ ViewConfiguration.get(context).getScaledTouchSlop() * 2,
+ /* minSpan= */ 0, Handler.getMain(), this);
mScrollGestureDetector = new GestureDetector(context, this, Handler.getMain());
mScaleGestureDetector.setQuickScaleEnabled(false);
mMagnificationDelegate = magnificationDelegate;