diff --git a/core/api/current.txt b/core/api/current.txt
index f80c09596fb11..e7194df0f97d5 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -3087,6 +3087,7 @@ package android.accessibilityservice {
public abstract class AccessibilityService extends android.app.Service {
ctor public AccessibilityService();
+ method public void attachAccessibilityOverlayToDisplay(int, @NonNull android.view.SurfaceControl);
method public boolean clearCache();
method public boolean clearCachedSubtree(@NonNull android.view.accessibility.AccessibilityNodeInfo);
method public final void disableSelf();
@@ -49980,6 +49981,7 @@ package android.view {
public static final class SurfaceControlViewHost.SurfacePackage implements android.os.Parcelable {
ctor public SurfaceControlViewHost.SurfacePackage(@NonNull android.view.SurfaceControlViewHost.SurfacePackage);
method public int describeContents();
+ method @NonNull public android.view.SurfaceControl getSurfaceControl();
method public void notifyConfigurationChanged(@NonNull android.content.res.Configuration);
method public void notifyDetachedFromWindow();
method public void release();
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index 2fe5d5140371a..02a81acf791a0 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -56,7 +56,7 @@ import android.util.SparseArray;
import android.view.Display;
import android.view.KeyEvent;
import android.view.MotionEvent;
-import android.view.SurfaceView;
+import android.view.SurfaceControl;
import android.view.WindowManager;
import android.view.WindowManagerImpl;
import android.view.accessibility.AccessibilityCache;
@@ -2467,8 +2467,8 @@ public abstract class AccessibilityService extends Service {
*
*
* Note: If the view with {@link AccessibilityNodeInfo#FOCUS_INPUT}
- * is on an embedded view hierarchy which is embedded in a {@link SurfaceView} via
- * {@link SurfaceView#setChildSurfacePackage}, there is a limitation that this API
+ * is on an embedded view hierarchy which is embedded in a {@link android.view.SurfaceView} via
+ * {@link android.view.SurfaceView#setChildSurfacePackage}, there is a limitation that this API
* won't be able to find the node for the view. It's because views don't know about
* the embedded hierarchies. Instead, you could traverse all the nodes to find the
* focus.
@@ -3379,4 +3379,28 @@ public abstract class AccessibilityService extends Service {
controller.onStateChanged(state);
}
}
+
+ /**
+ * Attaches a {@link android.view.SurfaceControl} containing an accessibility overlay to the
+ * specified display. This type of overlay should be used for content that does not need to
+ * track the location and size of Views in the currently active app e.g. service configuration
+ * or general service UI. To remove this overlay and free the associated resources, use
+ * new SurfaceControl.Transaction().reparent(sc, null).apply();.
+ *
+ * @param displayId the display to which the SurfaceControl should be attached.
+ * @param sc the SurfaceControl containing the overlay content
+ */
+ public void attachAccessibilityOverlayToDisplay(int displayId, @NonNull SurfaceControl sc) {
+ Preconditions.checkNotNull(sc, "SurfaceControl cannot be null");
+ final IAccessibilityServiceConnection connection =
+ AccessibilityInteractionClient.getConnection(mConnectionId);
+ if (connection == null) {
+ return;
+ }
+ try {
+ connection.attachAccessibilityOverlayToDisplay(displayId, sc);
+ } catch (RemoteException re) {
+ throw new RuntimeException(re);
+ }
+ }
}
diff --git a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
index da14b50e64817..da13e7353056d 100644
--- a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
+++ b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
@@ -25,6 +25,7 @@ import android.os.Bundle;
import android.os.RemoteCallback;
import android.view.MagnificationSpec;
import android.view.MotionEvent;
+import android.view.SurfaceControl;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
import android.view.accessibility.IAccessibilityInteractionConnectionCallback;
@@ -155,4 +156,5 @@ interface IAccessibilityServiceConnection {
void setInstalledAndEnabledServices(in List infos);
List getInstalledAndEnabledServices();
+ void attachAccessibilityOverlayToDisplay(int displayId, in SurfaceControl sc);
}
diff --git a/core/java/android/view/SurfaceControlViewHost.java b/core/java/android/view/SurfaceControlViewHost.java
index 3acb0534e388e..18897725e98f5 100644
--- a/core/java/android/view/SurfaceControlViewHost.java
+++ b/core/java/android/view/SurfaceControlViewHost.java
@@ -159,9 +159,11 @@ public class SurfaceControlViewHost {
}
/**
- * Use {@link SurfaceView#setChildSurfacePackage} or manually fix
- * accessibility (see SurfaceView implementation).
- * @hide
+ * Returns the {@link android.view.SurfaceControl} associated with this SurfacePackage for
+ * cases where more control is required.
+ *
+ * @return the SurfaceControl associated with this SurfacePackage and its containing
+ * SurfaceControlViewHost
*/
public @NonNull SurfaceControl getSurfaceControl() {
return mSurfaceControl;
diff --git a/core/tests/coretests/src/android/view/accessibility/AccessibilityServiceConnectionImpl.java b/core/tests/coretests/src/android/view/accessibility/AccessibilityServiceConnectionImpl.java
index 7a5ab0458406a..6443ac18e7dce 100644
--- a/core/tests/coretests/src/android/view/accessibility/AccessibilityServiceConnectionImpl.java
+++ b/core/tests/coretests/src/android/view/accessibility/AccessibilityServiceConnectionImpl.java
@@ -27,6 +27,7 @@ import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteCallback;
import android.os.RemoteException;
+import android.view.SurfaceControl;
import android.window.ScreenCapture;
import java.util.Collections;
@@ -222,4 +223,7 @@ public class AccessibilityServiceConnectionImpl extends IAccessibilityServiceCon
public List getInstalledAndEnabledServices() throws RemoteException {
return null;
}
+
+ @Override
+ public void attachAccessibilityOverlayToDisplay(int displayId, SurfaceControl sc) {}
}
diff --git a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
index c77b59717678c..786d4076191e5 100644
--- a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
@@ -76,6 +76,7 @@ import android.util.SparseArray;
import android.view.Display;
import android.view.KeyEvent;
import android.view.MagnificationSpec;
+import android.view.SurfaceControl;
import android.view.View;
import android.view.WindowInfo;
import android.view.accessibility.AccessibilityCache;
@@ -289,6 +290,8 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
void requestImeLocked(AbstractAccessibilityServiceConnection connection);
void unbindImeLocked(AbstractAccessibilityServiceConnection connection);
+
+ void attachAccessibilityOverlayToDisplay(int displayId, SurfaceControl sc);
}
public AbstractAccessibilityServiceConnection(Context context, ComponentName componentName,
@@ -2486,4 +2489,9 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
}
-}
\ No newline at end of file
+
+ @Override
+ public void attachAccessibilityOverlayToDisplay(int displayId, SurfaceControl sc) {
+ mSystemSupport.attachAccessibilityOverlayToDisplay(displayId, sc);
+ }
+}
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index e3ae03cbcdd80..87d166815323d 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -109,6 +109,7 @@ import android.view.IWindow;
import android.view.KeyEvent;
import android.view.MagnificationSpec;
import android.view.MotionEvent;
+import android.view.SurfaceControl;
import android.view.WindowInfo;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityEvent;
@@ -291,12 +292,12 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
private Point mTempPoint = new Point();
private boolean mIsAccessibilityButtonShown;
-
private boolean mInputBound;
IRemoteAccessibilityInputConnection mRemoteInputConnection;
EditorInfo mEditorInfo;
boolean mRestarting;
boolean mInputSessionRequested;
+ private SparseArray mA11yOverlayLayers = new SparseArray<>();
private AccessibilityUserState getCurrentUserStateLocked() {
return getUserStateLocked(mCurrentUserId);
@@ -3967,6 +3968,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
synchronized (mLock) {
mDisplaysList.add(display);
+ mA11yOverlayLayers.put(
+ displayId, mWindowManagerService.getA11yOverlayLayer(displayId));
if (mInputFilter != null) {
mInputFilter.onDisplayAdded(display);
}
@@ -3990,6 +3993,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
if (!removeDisplayFromList(displayId)) {
return;
}
+ mA11yOverlayLayers.remove(displayId);
if (mInputFilter != null) {
mInputFilter.onDisplayRemoved(displayId);
}
@@ -4691,4 +4695,30 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
return true;
}
}
+
+ @Override
+ public void attachAccessibilityOverlayToDisplay(int displayId, SurfaceControl sc) {
+ mMainHandler.sendMessage(
+ obtainMessage(
+ AccessibilityManagerService::attachAccessibilityOverlayToDisplayInternal,
+ this,
+ displayId,
+ sc));
+ }
+
+ void attachAccessibilityOverlayToDisplayInternal(int displayId, SurfaceControl sc) {
+ if (!mA11yOverlayLayers.contains(displayId)) {
+ mA11yOverlayLayers.put(displayId, mWindowManagerService.getA11yOverlayLayer(displayId));
+ }
+ SurfaceControl parent = mA11yOverlayLayers.get(displayId);
+ if (parent == null) {
+ Slog.e(LOG_TAG, "Unable to get accessibility overlay SurfaceControl.");
+ mA11yOverlayLayers.remove(displayId);
+ return;
+ }
+ SurfaceControl.Transaction transaction = new SurfaceControl.Transaction();
+ transaction.reparent(sc, parent);
+ transaction.apply();
+ transaction.close();
+ }
}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 12efe0dc074f7..e65ea53ac4599 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -311,6 +311,9 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
*/
private SurfaceControl mOverlayLayer;
+ /** A surfaceControl specifically for accessibility overlays. */
+ private SurfaceControl mA11yOverlayLayer;
+
/**
* The direct child layer of the display to put all non-overlay windows. This is also used for
* screen rotation animation so that there is a parent layer to put the animation leash.
@@ -1269,12 +1272,21 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
transaction.reparent(mOverlayLayer, mSurfaceControl);
}
+ if (mA11yOverlayLayer == null) {
+ mA11yOverlayLayer =
+ b.setName("Accessibility Overlays").setParent(mSurfaceControl).build();
+ } else {
+ transaction.reparent(mA11yOverlayLayer, mSurfaceControl);
+ }
+
transaction
.setLayer(mSurfaceControl, 0)
.setLayerStack(mSurfaceControl, mDisplayId)
.show(mSurfaceControl)
.setLayer(mOverlayLayer, Integer.MAX_VALUE)
- .show(mOverlayLayer);
+ .show(mOverlayLayer)
+ .setLayer(mA11yOverlayLayer, Integer.MAX_VALUE - 1)
+ .show(mA11yOverlayLayer);
}
boolean isReady() {
@@ -3250,6 +3262,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
setRemoteInsetsController(null);
mWmService.mAnimator.removeDisplayLocked(mDisplayId);
mOverlayLayer.release();
+ mA11yOverlayLayer.release();
mWindowingLayer.release();
mInputMonitor.onDisplayRemoved();
mWmService.mDisplayNotificationController.dispatchDisplayRemoved(this);
@@ -5502,6 +5515,10 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
return mOverlayLayer;
}
+ SurfaceControl getA11yOverlayLayer() {
+ return mA11yOverlayLayer;
+ }
+
SurfaceControl[] findRoundedCornerOverlays() {
List roundedCornerOverlays = new ArrayList<>();
for (WindowToken token : mTokenMap.values()) {
diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java
index bab3a0553e63c..1282acbc9e5a2 100644
--- a/services/core/java/com/android/server/wm/WindowManagerInternal.java
+++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java
@@ -903,4 +903,7 @@ public abstract class WindowManagerInternal {
* could not be prepared and the session needs to be torn down.
*/
public abstract boolean setContentRecordingSession(ContentRecordingSession incomingSession);
+
+ /** Returns the SurfaceControl accessibility services should use for accessibility overlays. */
+ public abstract SurfaceControl getA11yOverlayLayer(int displayId);
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index df343db8b3bf4..1289634d0a1d3 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -736,7 +736,6 @@ public class WindowManagerService extends IWindowManager.Stub
@VisibleForTesting
final ContentRecordingController mContentRecordingController = new ContentRecordingController();
-
@VisibleForTesting
final class SettingsObserver extends ContentObserver {
private final Uri mDisplayInversionEnabledUri =
@@ -8301,6 +8300,17 @@ public class WindowManagerService extends IWindowManager.Stub
return true;
}
}
+
+ @Override
+ public SurfaceControl getA11yOverlayLayer(int displayId) {
+ synchronized (mGlobalLock) {
+ DisplayContent dc = mRoot.getDisplayContent(displayId);
+ if (dc != null) {
+ return dc.getA11yOverlayLayer();
+ }
+ }
+ return null;
+ }
}
void registerAppFreezeListener(AppFreezeListener listener) {