diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 27980a3bdefe5..f71ef8dffdb46 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -16545,6 +16545,7 @@ package android.view.accessibility { method public void interrupt(); method public void onAccessibilityEvent(@NonNull android.view.accessibility.AccessibilityEvent); method public void onProxyConnected(); + method public void setAccessibilityFocusAppearance(int, @ColorInt int); method public void setInstalledAndEnabledServices(@NonNull java.util.List); } diff --git a/core/java/android/view/accessibility/AccessibilityDisplayProxy.java b/core/java/android/view/accessibility/AccessibilityDisplayProxy.java index dd320e196e8b6..12e08148a6516 100644 --- a/core/java/android/view/accessibility/AccessibilityDisplayProxy.java +++ b/core/java/android/view/accessibility/AccessibilityDisplayProxy.java @@ -22,6 +22,7 @@ import android.accessibilityservice.AccessibilityServiceInfo; import android.accessibilityservice.IAccessibilityServiceClient; import android.accessibilityservice.IAccessibilityServiceConnection; import android.accessibilityservice.MagnificationConfig; +import android.annotation.ColorInt; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; @@ -239,6 +240,27 @@ public abstract class AccessibilityDisplayProxy { return Collections.emptyList(); } + /** + * Sets the strokeWidth and color of the accessibility focus rectangle. + * + * @param strokeWidth The stroke width of the rectangle in pixels. + * Setting this value to zero results in no focus rectangle being drawn. + * @param color The color of the rectangle. + */ + public void setAccessibilityFocusAppearance(int strokeWidth, @ColorInt int color) { + IAccessibilityServiceConnection connection = + AccessibilityInteractionClient.getInstance().getConnection(mConnectionId); + if (connection != null) { + try { + connection.setFocusAppearance(strokeWidth, color); + } catch (RemoteException re) { + Log.w(LOG_TAG, "Error while setting the strokeWidth and color of the " + + "accessibility focus rectangle", re); + re.rethrowFromSystemServer(); + } + } + } + /** * An IAccessibilityServiceClient that handles interrupts, accessibility events, and system * connection. diff --git a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java index f4c6cc3de0b1e..0926f8ab5147c 100644 --- a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java +++ b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java @@ -314,6 +314,9 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ void unbindImeLocked(AbstractAccessibilityServiceConnection connection); void attachAccessibilityOverlayToDisplay(int displayId, SurfaceControl sc); + + void setCurrentUserFocusAppearance(int strokeWidth, int color); + } public AbstractAccessibilityServiceConnection(Context context, ComponentName componentName, diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java index 010189a245e58..2929cf8032f47 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java @@ -4876,4 +4876,11 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub transaction.apply(); transaction.close(); } + + @Override + public void setCurrentUserFocusAppearance(int strokeWidth, int color) { + synchronized (mLock) { + getCurrentUserStateLocked().setFocusAppearanceLocked(strokeWidth, color); + } + } } diff --git a/services/accessibility/java/com/android/server/accessibility/ProxyAccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/ProxyAccessibilityServiceConnection.java index d53a080fd5859..df913aaf4893a 100644 --- a/services/accessibility/java/com/android/server/accessibility/ProxyAccessibilityServiceConnection.java +++ b/services/accessibility/java/com/android/server/accessibility/ProxyAccessibilityServiceConnection.java @@ -43,6 +43,7 @@ import android.view.accessibility.AccessibilityWindowInfo; import androidx.annotation.Nullable; +import com.android.internal.R; import com.android.server.wm.WindowManagerInternal; import java.util.Arrays; @@ -63,6 +64,11 @@ public class ProxyAccessibilityServiceConnection extends AccessibilityServiceCon private int mDisplayId; private List mInstalledAndEnabledServices; + /** The stroke width of the focus rectangle in pixels */ + private int mFocusStrokeWidth; + /** The color of the focus rectangle */ + private int mFocusColor; + ProxyAccessibilityServiceConnection( Context context, ComponentName componentName, @@ -77,6 +83,10 @@ public class ProxyAccessibilityServiceConnection extends AccessibilityServiceCon /* systemActionPerformer= */ null, awm, /* activityTaskManagerService= */ null); mDisplayId = displayId; setDisplayTypes(DISPLAY_TYPE_PROXY); + mFocusStrokeWidth = mContext.getResources().getDimensionPixelSize( + R.dimen.accessibility_focus_highlight_stroke_width); + mFocusColor = mContext.getResources().getColor( + R.color.accessibility_focus_highlight_color); } /** @@ -202,6 +212,48 @@ public class ProxyAccessibilityServiceConnection extends AccessibilityServiceCon return displayWindows; } + @Override + public void setFocusAppearance(int strokeWidth, int color) { + synchronized (mLock) { + if (!hasRightsToCurrentUserLocked()) { + return; + } + + if (!mSecurityPolicy.checkAccessibilityAccess(this)) { + return; + } + + if (getFocusStrokeWidthLocked() == strokeWidth && getFocusColorLocked() == color) { + return; + } + + mFocusStrokeWidth = strokeWidth; + mFocusColor = color; + // Sets the appearance data in the A11yUserState for now, since the A11yManagers are not + // separated. + // TODO(254545943): Separate proxy and non-proxy states so the focus appearance on the + // phone is not affected by the appearance of a proxy-ed app. + mSystemSupport.setCurrentUserFocusAppearance(mFocusStrokeWidth, mFocusColor); + mSystemSupport.onClientChangeLocked(false); + } + } + + /** + * Gets the stroke width of the focus rectangle. + * @return The stroke width. + */ + public int getFocusStrokeWidthLocked() { + return mFocusStrokeWidth; + } + + /** + * Gets the color of the focus rectangle. + * @return The color. + */ + public int getFocusColorLocked() { + return mFocusColor; + } + @Override public void binderDied() { } diff --git a/services/accessibility/java/com/android/server/accessibility/ProxyManager.java b/services/accessibility/java/com/android/server/accessibility/ProxyManager.java index fed0932df2178..54cdb04b56f53 100644 --- a/services/accessibility/java/com/android/server/accessibility/ProxyManager.java +++ b/services/accessibility/java/com/android/server/accessibility/ProxyManager.java @@ -178,9 +178,15 @@ public class ProxyManager { if (a11yEnabled) { clientState |= AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED; } + for (int i = 0; i < mProxyA11yServiceConnections.size(); i++) { + final ProxyAccessibilityServiceConnection proxy = + mProxyA11yServiceConnections.valueAt(i); + if (proxy.mRequestTouchExplorationMode) { + clientState |= AccessibilityManager.STATE_FLAG_TOUCH_EXPLORATION_ENABLED; + } + } return clientState; - // TODO(b/254545943): When A11yManager is separated, include support for other properties - // like isTouchExplorationEnabled. + // TODO(b/254545943): When A11yManager is separated, include support for other properties. } /** diff --git a/services/tests/servicestests/src/com/android/server/accessibility/ProxyAccessibilityServiceConnectionTest.java b/services/tests/servicestests/src/com/android/server/accessibility/ProxyAccessibilityServiceConnectionTest.java index c84c2c287679c..b5e0e0730a58a 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/ProxyAccessibilityServiceConnectionTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/ProxyAccessibilityServiceConnectionTest.java @@ -28,6 +28,7 @@ import android.accessibilityservice.AccessibilityServiceInfo; import android.accessibilityservice.AccessibilityTrace; import android.content.ComponentName; import android.content.Context; +import android.content.res.Resources; import android.os.Handler; import android.view.accessibility.AccessibilityEvent; @@ -35,6 +36,7 @@ import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertThrows; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import com.android.server.wm.WindowManagerInternal; @@ -79,7 +81,10 @@ public class ProxyAccessibilityServiceConnectionTest { @Before public void setup() { + final Resources resources = getInstrumentation().getContext().getResources(); MockitoAnnotations.initMocks(this); + when(mMockContext.getResources()).thenReturn(resources); + mAccessibilityServiceInfo = new AccessibilityServiceInfo(); mProxyConnection = new ProxyAccessibilityServiceConnection(mMockContext, COMPONENT_NAME, mAccessibilityServiceInfo, CONNECTION_ID , new Handler(