Loading core/java/android/view/AccessibilityInteractionController.java +20 −0 Original line number Diff line number Diff line Loading @@ -50,6 +50,7 @@ import android.view.accessibility.AccessibilityNodeProvider; import android.view.accessibility.AccessibilityRequestPreparer; import android.view.accessibility.Flags; import android.view.accessibility.IAccessibilityInteractionConnectionCallback; import android.view.accessibility.IWindowSurfaceInfoCallback; import android.window.ScreenCapture; import com.android.internal.R; Loading Loading @@ -631,6 +632,25 @@ public final class AccessibilityInteractionController { } } /** * Provide info for taking a screenshot of this app window. */ public void getWindowSurfaceInfoClientThread(IWindowSurfaceInfoCallback callback) { Message message = PooledLambda.obtainMessage( AccessibilityInteractionController::getWindowSurfaceInfoUiThread, this, callback); mHandler.sendMessage(message); } private void getWindowSurfaceInfoUiThread(IWindowSurfaceInfoCallback callback) { try { callback.provideWindowSurfaceInfo(mViewRootImpl.getWindowFlags(), Process.myUid(), mViewRootImpl.getSurfaceControl()); } catch (RemoteException re) { // ignore - the other side will time out } } public void findFocusClientThread(long accessibilityNodeId, int focusType, Region interactiveRegion, int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid, Loading core/java/android/view/ViewRootImpl.java +10 −0 Original line number Diff line number Diff line Loading @@ -254,6 +254,7 @@ import android.view.accessibility.AccessibilityWindowInfo; import android.view.accessibility.IAccessibilityEmbeddedConnection; import android.view.accessibility.IAccessibilityInteractionConnection; import android.view.accessibility.IAccessibilityInteractionConnectionCallback; import android.view.accessibility.IWindowSurfaceInfoCallback; import android.view.animation.AccelerateDecelerateInterpolator; import android.view.animation.Interpolator; import android.view.autofill.AutofillManager; Loading Loading @@ -12285,6 +12286,15 @@ public final class ViewRootImpl implements ViewParent, } } @Override public void getWindowSurfaceInfo(IWindowSurfaceInfoCallback callback) { ViewRootImpl viewRootImpl = mViewRootImpl.get(); if (viewRootImpl != null && viewRootImpl.mView != null) { viewRootImpl.getAccessibilityInteractionController() .getWindowSurfaceInfoClientThread(callback); } } public void attachAccessibilityOverlayToWindow( SurfaceControl sc, int interactionId, core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl +3 −0 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ import android.view.MagnificationSpec; import android.view.SurfaceControl; import android.view.accessibility.AccessibilityNodeInfo; import android.view.accessibility.IAccessibilityInteractionConnectionCallback; import android.view.accessibility.IWindowSurfaceInfoCallback; import android.window.ScreenCapture; /** Loading Loading @@ -67,5 +68,7 @@ oneway interface IAccessibilityInteractionConnection { in ScreenCapture.ScreenCaptureListener listener, IAccessibilityInteractionConnectionCallback callback); void getWindowSurfaceInfo(IWindowSurfaceInfoCallback callback); void attachAccessibilityOverlayToWindow(in SurfaceControl sc, int interactionId, in IAccessibilityInteractionConnectionCallback callback); } core/java/android/view/accessibility/IWindowSurfaceInfoCallback.aidl 0 → 100644 +39 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.view.accessibility; import android.view.SurfaceControl; /** * Callback for an app to provide AbstractAccessibilityServiceConnection with window and surface * information necessary for system_server to take a screenshot of the app window. * @hide */ oneway interface IWindowSurfaceInfoCallback { /** * Provide info from ViewRootImpl for taking a screenshot of this app window. * * @param windowFlags the window flags of ViewRootImpl * @param processUid the process (kernel) uid, NOT the user ID, required for SurfaceFlinger screenshots * @param surfaceControl the surface of ViewRootImpl */ @RequiresNoPermission void provideWindowSurfaceInfo(int windowFlags, int processUid, in SurfaceControl surfaceControl); } core/tests/coretests/src/android/view/AccessibilityInteractionControllerTest.java +17 −0 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ import android.app.Instrumentation; import android.app.Service; import android.app.UiAutomation; import android.graphics.Rect; import android.os.Process; import android.os.SystemClock; import android.text.TextUtils; import android.view.accessibility.AccessibilityEvent; Loading @@ -32,6 +33,7 @@ import android.view.accessibility.AccessibilityManager; import android.view.accessibility.AccessibilityNodeInfo; import android.view.accessibility.AccessibilityTestActivity; import android.view.accessibility.AccessibilityWindowInfo; import android.view.accessibility.IWindowSurfaceInfoCallback; import androidx.test.InstrumentationRegistry; import androidx.test.ext.junit.runners.AndroidJUnit4; Loading @@ -47,6 +49,7 @@ import org.junit.BeforeClass; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mockito; import java.util.List; import java.util.concurrent.TimeoutException; Loading Loading @@ -136,6 +139,20 @@ public class AccessibilityInteractionControllerTest { } } @Test public void getWindowSurfaceInfo_shouldCallCallbackWithWindowSurfaceDataFromVri() throws Exception { final ViewRootImpl vri = mButton.getRootView().getViewRootImpl(); IWindowSurfaceInfoCallback callback = Mockito.mock(IWindowSurfaceInfoCallback.class); sInstrumentation.runOnMainSync(() -> mAccessibilityInteractionController.getWindowSurfaceInfoClientThread(callback)); sInstrumentation.waitForIdleSync(); Mockito.verify(callback).provideWindowSurfaceInfo( vri.getWindowFlags(), Process.myUid(), vri.getSurfaceControl()); } private void launchActivity() { final Object waitObject = new Object(); final int[] location = new int[2]; Loading Loading
core/java/android/view/AccessibilityInteractionController.java +20 −0 Original line number Diff line number Diff line Loading @@ -50,6 +50,7 @@ import android.view.accessibility.AccessibilityNodeProvider; import android.view.accessibility.AccessibilityRequestPreparer; import android.view.accessibility.Flags; import android.view.accessibility.IAccessibilityInteractionConnectionCallback; import android.view.accessibility.IWindowSurfaceInfoCallback; import android.window.ScreenCapture; import com.android.internal.R; Loading Loading @@ -631,6 +632,25 @@ public final class AccessibilityInteractionController { } } /** * Provide info for taking a screenshot of this app window. */ public void getWindowSurfaceInfoClientThread(IWindowSurfaceInfoCallback callback) { Message message = PooledLambda.obtainMessage( AccessibilityInteractionController::getWindowSurfaceInfoUiThread, this, callback); mHandler.sendMessage(message); } private void getWindowSurfaceInfoUiThread(IWindowSurfaceInfoCallback callback) { try { callback.provideWindowSurfaceInfo(mViewRootImpl.getWindowFlags(), Process.myUid(), mViewRootImpl.getSurfaceControl()); } catch (RemoteException re) { // ignore - the other side will time out } } public void findFocusClientThread(long accessibilityNodeId, int focusType, Region interactiveRegion, int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid, Loading
core/java/android/view/ViewRootImpl.java +10 −0 Original line number Diff line number Diff line Loading @@ -254,6 +254,7 @@ import android.view.accessibility.AccessibilityWindowInfo; import android.view.accessibility.IAccessibilityEmbeddedConnection; import android.view.accessibility.IAccessibilityInteractionConnection; import android.view.accessibility.IAccessibilityInteractionConnectionCallback; import android.view.accessibility.IWindowSurfaceInfoCallback; import android.view.animation.AccelerateDecelerateInterpolator; import android.view.animation.Interpolator; import android.view.autofill.AutofillManager; Loading Loading @@ -12285,6 +12286,15 @@ public final class ViewRootImpl implements ViewParent, } } @Override public void getWindowSurfaceInfo(IWindowSurfaceInfoCallback callback) { ViewRootImpl viewRootImpl = mViewRootImpl.get(); if (viewRootImpl != null && viewRootImpl.mView != null) { viewRootImpl.getAccessibilityInteractionController() .getWindowSurfaceInfoClientThread(callback); } } public void attachAccessibilityOverlayToWindow( SurfaceControl sc, int interactionId,
core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl +3 −0 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ import android.view.MagnificationSpec; import android.view.SurfaceControl; import android.view.accessibility.AccessibilityNodeInfo; import android.view.accessibility.IAccessibilityInteractionConnectionCallback; import android.view.accessibility.IWindowSurfaceInfoCallback; import android.window.ScreenCapture; /** Loading Loading @@ -67,5 +68,7 @@ oneway interface IAccessibilityInteractionConnection { in ScreenCapture.ScreenCaptureListener listener, IAccessibilityInteractionConnectionCallback callback); void getWindowSurfaceInfo(IWindowSurfaceInfoCallback callback); void attachAccessibilityOverlayToWindow(in SurfaceControl sc, int interactionId, in IAccessibilityInteractionConnectionCallback callback); }
core/java/android/view/accessibility/IWindowSurfaceInfoCallback.aidl 0 → 100644 +39 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.view.accessibility; import android.view.SurfaceControl; /** * Callback for an app to provide AbstractAccessibilityServiceConnection with window and surface * information necessary for system_server to take a screenshot of the app window. * @hide */ oneway interface IWindowSurfaceInfoCallback { /** * Provide info from ViewRootImpl for taking a screenshot of this app window. * * @param windowFlags the window flags of ViewRootImpl * @param processUid the process (kernel) uid, NOT the user ID, required for SurfaceFlinger screenshots * @param surfaceControl the surface of ViewRootImpl */ @RequiresNoPermission void provideWindowSurfaceInfo(int windowFlags, int processUid, in SurfaceControl surfaceControl); }
core/tests/coretests/src/android/view/AccessibilityInteractionControllerTest.java +17 −0 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ import android.app.Instrumentation; import android.app.Service; import android.app.UiAutomation; import android.graphics.Rect; import android.os.Process; import android.os.SystemClock; import android.text.TextUtils; import android.view.accessibility.AccessibilityEvent; Loading @@ -32,6 +33,7 @@ import android.view.accessibility.AccessibilityManager; import android.view.accessibility.AccessibilityNodeInfo; import android.view.accessibility.AccessibilityTestActivity; import android.view.accessibility.AccessibilityWindowInfo; import android.view.accessibility.IWindowSurfaceInfoCallback; import androidx.test.InstrumentationRegistry; import androidx.test.ext.junit.runners.AndroidJUnit4; Loading @@ -47,6 +49,7 @@ import org.junit.BeforeClass; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mockito; import java.util.List; import java.util.concurrent.TimeoutException; Loading Loading @@ -136,6 +139,20 @@ public class AccessibilityInteractionControllerTest { } } @Test public void getWindowSurfaceInfo_shouldCallCallbackWithWindowSurfaceDataFromVri() throws Exception { final ViewRootImpl vri = mButton.getRootView().getViewRootImpl(); IWindowSurfaceInfoCallback callback = Mockito.mock(IWindowSurfaceInfoCallback.class); sInstrumentation.runOnMainSync(() -> mAccessibilityInteractionController.getWindowSurfaceInfoClientThread(callback)); sInstrumentation.waitForIdleSync(); Mockito.verify(callback).provideWindowSurfaceInfo( vri.getWindowFlags(), Process.myUid(), vri.getSurfaceControl()); } private void launchActivity() { final Object waitObject = new Object(); final int[] location = new int[2]; Loading