Loading core/java/android/view/Window.java +1 −1 Original line number Diff line number Diff line Loading @@ -878,7 +878,7 @@ public abstract class Window { if (wm == null) { wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE); } mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this); mWindowManager = wm.createLocalWindowManager(this); } void adjustLayoutParamsForSubWindow(WindowManager.LayoutParams wp) { Loading core/java/android/view/WindowManager.java +26 −0 Original line number Diff line number Diff line Loading @@ -6779,4 +6779,30 @@ public interface WindowManager extends ViewManager { @NonNull Consumer<@ScreenRecordingState Integer> callback) { throw new UnsupportedOperationException(); } /** * Sets the parent window to this {@code WindowManager}. * This is necessary to attach sub-windows. * * @param parentWindow the parent window to be attached. * * @see android.window.WindowContext#attachWindow(View) * * @hide */ default void setParentWindow(@NonNull Window parentWindow) { throw new UnsupportedOperationException(); } /** * Creates a new instance of {@link WindowManager} with {@code parentWindow} attached. * * @param parentWindow the parent window to be attached. * @return a new instance of {@link WindowManager} with {@code parentWindow} attached * * @hide */ default WindowManager createLocalWindowManager(@NonNull Window parentWindow) { throw new UnsupportedOperationException(); } } core/java/android/view/WindowManagerImpl.java +10 −9 Original line number Diff line number Diff line Loading @@ -81,12 +81,18 @@ import java.util.function.IntConsumer; * provides a window manager for adding windows that are associated with that * activity -- the window manager will not normally allow you to add arbitrary * windows that are not associated with an activity. * <p> * Note that extending {@code WindowManagerImpl} for {@link WindowManager} customization may lead to * crashes since {@link Window} and {@link WindowContext} may also customize * {@code WindowManagerImpl}, such as providing {@link #mParentWindow} * or {@link #mWindowContextToken}. Users should customize {@link WindowManager} via * {@link WindowManagerWrapper}. * * @see WindowManager * @see WindowManagerGlobal * @hide */ public class WindowManagerImpl implements WindowManager { public final class WindowManagerImpl implements WindowManager { private static final String TAG = "WindowManager"; @UnsupportedAppUsage Loading Loading @@ -129,14 +135,11 @@ public class WindowManagerImpl implements WindowManager { mWindowMetricsController = new WindowMetricsController(mContext); } public WindowManagerImpl createLocalWindowManager(Window parentWindow) { @Override public WindowManager createLocalWindowManager(Window parentWindow) { return new WindowManagerImpl(mContext, parentWindow, mWindowContextToken); } public WindowManagerImpl createPresentationWindowManager(Context displayContext) { return new WindowManagerImpl(displayContext, mParentWindow, mWindowContextToken); } /** Creates a {@link WindowManager} for a {@link WindowContext}. */ public static WindowManager createWindowContextWindowManager(Context context) { final IBinder clientToken = context.getWindowContextToken(); Loading @@ -153,9 +156,7 @@ public class WindowManagerImpl implements WindowManager { mDefaultToken = token; } /** * Sets the parent window. */ @Override public void setParentWindow(@NonNull Window parentWindow) { mParentWindow = parentWindow; } Loading core/java/android/view/WindowManagerWrapper.java 0 → 100644 +328 −0 Original line number Diff line number Diff line /* * Copyright (C) 2025 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; import static com.android.server.display.feature.flags.Flags.FLAG_ENABLE_DISPLAY_CONTENT_MODE_MANAGEMENT; import android.Manifest; import android.annotation.FlaggedApi; import android.annotation.RequiresPermission; import android.content.ComponentName; import android.graphics.Bitmap; import android.graphics.Region; import android.os.IBinder; import android.os.Looper; import android.window.InputTransferToken; import android.window.TaskFpsCallback; import android.window.TrustedPresentationThresholds; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.android.window.flags.Flags; import java.util.List; import java.util.Set; import java.util.concurrent.Executor; import java.util.function.Consumer; import java.util.function.IntConsumer; /** * A wrapper that wraps a base {@link WindowManager}. * <p> * Similar to {@link android.content.ContextWrapper}, it enables to customize behavior without * touching the original {@link WindowManager}. * * @hide */ public class WindowManagerWrapper implements WindowManager { @NonNull private final WindowManager mBase; public WindowManagerWrapper(@NonNull WindowManager base) { mBase = base; } @Override public void addView(View view, ViewGroup.LayoutParams params) { mBase.addView(view, params); } @Override public void updateViewLayout(View view, ViewGroup.LayoutParams params) { mBase.updateViewLayout(view, params); } @Override public void removeView(View view) { mBase.removeView(view); } @Deprecated @Override public Display getDefaultDisplay() { return mBase.getDefaultDisplay(); } @Override public void removeViewImmediate(View view) { mBase.removeViewImmediate(view); } @NonNull @Override public WindowMetrics getCurrentWindowMetrics() { return mBase.getCurrentWindowMetrics(); } @NonNull @Override public WindowMetrics getMaximumWindowMetrics() { return mBase.getMaximumWindowMetrics(); } @NonNull @Override public Set<WindowMetrics> getPossibleMaximumWindowMetrics(int displayId) { return mBase.getPossibleMaximumWindowMetrics(displayId); } @Override public void requestAppKeyboardShortcuts(KeyboardShortcutsReceiver receiver, int deviceId) { mBase.requestAppKeyboardShortcuts(receiver, deviceId); } @Override public KeyboardShortcutGroup getApplicationLaunchKeyboardShortcuts(int deviceId) { return mBase.getApplicationLaunchKeyboardShortcuts(deviceId); } @Override public void requestImeKeyboardShortcuts(KeyboardShortcutsReceiver receiver, int deviceId) { mBase.requestImeKeyboardShortcuts(receiver, deviceId); } @RequiresPermission(android.Manifest.permission.RESTRICTED_VR_ACCESS) @Override public Region getCurrentImeTouchRegion() { return mBase.getCurrentImeTouchRegion(); } @Override public void setShouldShowWithInsecureKeyguard(int displayId, boolean shouldShow) { mBase.setShouldShowWithInsecureKeyguard(displayId, shouldShow); } @Override public void setShouldShowSystemDecors(int displayId, boolean shouldShow) { mBase.setShouldShowSystemDecors(displayId, shouldShow); } @Override public boolean shouldShowSystemDecors(int displayId) { return mBase.shouldShowSystemDecors(displayId); } @Override public void setDisplayImePolicy(int displayId, int imePolicy) { mBase.setDisplayImePolicy(displayId, imePolicy); } @FlaggedApi(FLAG_ENABLE_DISPLAY_CONTENT_MODE_MANAGEMENT) @Override public boolean isEligibleForDesktopMode(int displayId) { return mBase.isEligibleForDesktopMode(displayId); } @Override public int getDisplayImePolicy(int displayId) { return mBase.getDisplayImePolicy(displayId); } @Override public boolean isGlobalKey(int keyCode) { return mBase.isGlobalKey(keyCode); } @Override public boolean isCrossWindowBlurEnabled() { return mBase.isCrossWindowBlurEnabled(); } @Override public void addCrossWindowBlurEnabledListener(@NonNull Consumer<Boolean> listener) { mBase.addCrossWindowBlurEnabledListener(listener); } @Override public void addCrossWindowBlurEnabledListener(@NonNull Executor executor, @NonNull Consumer<Boolean> listener) { mBase.addCrossWindowBlurEnabledListener(executor, listener); } @Override public void removeCrossWindowBlurEnabledListener(@NonNull Consumer<Boolean> listener) { mBase.removeCrossWindowBlurEnabledListener(listener); } @Override public void addProposedRotationListener(@NonNull Executor executor, @NonNull IntConsumer listener) { mBase.addProposedRotationListener(executor, listener); } @Override public void removeProposedRotationListener(@NonNull IntConsumer listener) { mBase.removeProposedRotationListener(listener); } @Override public void holdLock(IBinder token, int durationMs) { mBase.holdLock(token, durationMs); } @Override public boolean isTaskSnapshotSupported() { return mBase.isTaskSnapshotSupported(); } @Override public void registerTaskFpsCallback(int taskId, @NonNull Executor executor, @NonNull TaskFpsCallback callback) { mBase.registerTaskFpsCallback(taskId, executor, callback); } @Override public void unregisterTaskFpsCallback(@NonNull TaskFpsCallback callback) { mBase.unregisterTaskFpsCallback(callback); } @Nullable @Override public Bitmap snapshotTaskForRecents(int taskId) { return mBase.snapshotTaskForRecents(taskId); } @NonNull @Override public List<ComponentName> notifyScreenshotListeners(int displayId) { return mBase.notifyScreenshotListeners(displayId); } @RequiresPermission(Manifest.permission.ACCESS_SURFACE_FLINGER) @Override public boolean replaceContentOnDisplayWithMirror(int displayId, @NonNull Window window) { return mBase.replaceContentOnDisplayWithMirror(displayId, window); } @RequiresPermission(Manifest.permission.ACCESS_SURFACE_FLINGER) @Override public boolean replaceContentOnDisplayWithSc(int displayId, @NonNull SurfaceControl sc) { return mBase.replaceContentOnDisplayWithSc(displayId, sc); } @FlaggedApi(Flags.FLAG_TRUSTED_PRESENTATION_LISTENER_FOR_WINDOW) @Override public void registerTrustedPresentationListener(@NonNull IBinder window, @NonNull TrustedPresentationThresholds thresholds, @NonNull Executor executor, @NonNull Consumer<Boolean> listener) { mBase.registerTrustedPresentationListener(window, thresholds, executor, listener); } @FlaggedApi(Flags.FLAG_TRUSTED_PRESENTATION_LISTENER_FOR_WINDOW) @Override public void unregisterTrustedPresentationListener(@NonNull Consumer<Boolean> listener) { mBase.unregisterTrustedPresentationListener(listener); } @FlaggedApi(Flags.FLAG_SURFACE_CONTROL_INPUT_RECEIVER) @NonNull @Override public InputTransferToken registerBatchedSurfaceControlInputReceiver( @NonNull InputTransferToken hostInputTransferToken, @NonNull SurfaceControl surfaceControl, @NonNull Choreographer choreographer, @NonNull SurfaceControlInputReceiver receiver) { return mBase.registerBatchedSurfaceControlInputReceiver( hostInputTransferToken, surfaceControl, choreographer, receiver); } @FlaggedApi(Flags.FLAG_SURFACE_CONTROL_INPUT_RECEIVER) @NonNull @Override public InputTransferToken registerUnbatchedSurfaceControlInputReceiver( @NonNull InputTransferToken hostInputTransferToken, @NonNull SurfaceControl surfaceControl, @NonNull Looper looper, @NonNull SurfaceControlInputReceiver receiver) { return mBase.registerUnbatchedSurfaceControlInputReceiver( hostInputTransferToken, surfaceControl, looper, receiver); } @FlaggedApi(Flags.FLAG_SURFACE_CONTROL_INPUT_RECEIVER) @Override public void unregisterSurfaceControlInputReceiver(@NonNull SurfaceControl surfaceControl) { mBase.unregisterSurfaceControlInputReceiver(surfaceControl); } @FlaggedApi(Flags.FLAG_SURFACE_CONTROL_INPUT_RECEIVER) @Nullable @Override public IBinder getSurfaceControlInputClientToken(@NonNull SurfaceControl surfaceControl) { return mBase.getSurfaceControlInputClientToken(surfaceControl); } @FlaggedApi(Flags.FLAG_SURFACE_CONTROL_INPUT_RECEIVER) @Override public boolean transferTouchGesture(@NonNull InputTransferToken transferFromToken, @NonNull InputTransferToken transferToToken) { return mBase.transferTouchGesture(transferFromToken, transferToToken); } @NonNull @Override public IBinder getDefaultToken() { return mBase.getDefaultToken(); } @FlaggedApi(Flags.FLAG_SCREEN_RECORDING_CALLBACKS) @RequiresPermission(Manifest.permission.DETECT_SCREEN_RECORDING) @Override public @ScreenRecordingState int addScreenRecordingCallback(@NonNull Executor executor, @NonNull Consumer<@ScreenRecordingState Integer> callback) { return mBase.addScreenRecordingCallback(executor, callback); } @FlaggedApi(Flags.FLAG_SCREEN_RECORDING_CALLBACKS) @RequiresPermission(Manifest.permission.DETECT_SCREEN_RECORDING) @Override public void removeScreenRecordingCallback( @NonNull Consumer<@ScreenRecordingState Integer> callback) { mBase.removeScreenRecordingCallback(callback); } @Override public WindowManager createLocalWindowManager(@NonNull Window parentWindow) { final WindowManager newBase = mBase.createLocalWindowManager(parentWindow); return new WindowManagerWrapper(newBase); } @Override public void setParentWindow(@NonNull Window parentWindow) { mBase.setParentWindow(parentWindow); } } core/tests/coretests/src/android/view/WindowManagerWrapperTest.kt 0 → 100644 +60 −0 Original line number Diff line number Diff line /* * Copyright (C) 2025 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 import android.platform.test.annotations.Presubmit import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.google.common.truth.Truth.assertThat import org.junit.Test import org.junit.runner.RunWith /** * Tests for the [WindowManagerWrapper]. * * Build/Install/Run: * atest FrameworksCoreTests:WindowManagerWrapperTest */ @RunWith(AndroidJUnit4::class) @SmallTest @Presubmit class WindowManagerWrapperTest { /** * Tests that all default methods from [WindowManager] are implemented. */ @Test fun testWindowManagerWrapperImplementation() { val windowManagerInterface = WindowManager::class.java val wmInterfaceMethods = windowManagerInterface.methods val windowManagerWrapperClass = WindowManagerWrapper::class.java val wrapperMethodsFromWm = windowManagerWrapperClass.declaredMethods .filter { m -> windowManagerInterface.isAssignableFrom(m.declaringClass) } .map { m -> m.name } .toSet() // Only checks the default methods in WM interface. Missing implementation of non-default // methods should be caught at compile time. val wmDefaultMethods = wmInterfaceMethods .filter { m -> m.isDefault } .map { m -> m.name } .toList() for (defaultMethod in wmDefaultMethods) { assertThat(wrapperMethodsFromWm).contains(defaultMethod) } } } Loading
core/java/android/view/Window.java +1 −1 Original line number Diff line number Diff line Loading @@ -878,7 +878,7 @@ public abstract class Window { if (wm == null) { wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE); } mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this); mWindowManager = wm.createLocalWindowManager(this); } void adjustLayoutParamsForSubWindow(WindowManager.LayoutParams wp) { Loading
core/java/android/view/WindowManager.java +26 −0 Original line number Diff line number Diff line Loading @@ -6779,4 +6779,30 @@ public interface WindowManager extends ViewManager { @NonNull Consumer<@ScreenRecordingState Integer> callback) { throw new UnsupportedOperationException(); } /** * Sets the parent window to this {@code WindowManager}. * This is necessary to attach sub-windows. * * @param parentWindow the parent window to be attached. * * @see android.window.WindowContext#attachWindow(View) * * @hide */ default void setParentWindow(@NonNull Window parentWindow) { throw new UnsupportedOperationException(); } /** * Creates a new instance of {@link WindowManager} with {@code parentWindow} attached. * * @param parentWindow the parent window to be attached. * @return a new instance of {@link WindowManager} with {@code parentWindow} attached * * @hide */ default WindowManager createLocalWindowManager(@NonNull Window parentWindow) { throw new UnsupportedOperationException(); } }
core/java/android/view/WindowManagerImpl.java +10 −9 Original line number Diff line number Diff line Loading @@ -81,12 +81,18 @@ import java.util.function.IntConsumer; * provides a window manager for adding windows that are associated with that * activity -- the window manager will not normally allow you to add arbitrary * windows that are not associated with an activity. * <p> * Note that extending {@code WindowManagerImpl} for {@link WindowManager} customization may lead to * crashes since {@link Window} and {@link WindowContext} may also customize * {@code WindowManagerImpl}, such as providing {@link #mParentWindow} * or {@link #mWindowContextToken}. Users should customize {@link WindowManager} via * {@link WindowManagerWrapper}. * * @see WindowManager * @see WindowManagerGlobal * @hide */ public class WindowManagerImpl implements WindowManager { public final class WindowManagerImpl implements WindowManager { private static final String TAG = "WindowManager"; @UnsupportedAppUsage Loading Loading @@ -129,14 +135,11 @@ public class WindowManagerImpl implements WindowManager { mWindowMetricsController = new WindowMetricsController(mContext); } public WindowManagerImpl createLocalWindowManager(Window parentWindow) { @Override public WindowManager createLocalWindowManager(Window parentWindow) { return new WindowManagerImpl(mContext, parentWindow, mWindowContextToken); } public WindowManagerImpl createPresentationWindowManager(Context displayContext) { return new WindowManagerImpl(displayContext, mParentWindow, mWindowContextToken); } /** Creates a {@link WindowManager} for a {@link WindowContext}. */ public static WindowManager createWindowContextWindowManager(Context context) { final IBinder clientToken = context.getWindowContextToken(); Loading @@ -153,9 +156,7 @@ public class WindowManagerImpl implements WindowManager { mDefaultToken = token; } /** * Sets the parent window. */ @Override public void setParentWindow(@NonNull Window parentWindow) { mParentWindow = parentWindow; } Loading
core/java/android/view/WindowManagerWrapper.java 0 → 100644 +328 −0 Original line number Diff line number Diff line /* * Copyright (C) 2025 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; import static com.android.server.display.feature.flags.Flags.FLAG_ENABLE_DISPLAY_CONTENT_MODE_MANAGEMENT; import android.Manifest; import android.annotation.FlaggedApi; import android.annotation.RequiresPermission; import android.content.ComponentName; import android.graphics.Bitmap; import android.graphics.Region; import android.os.IBinder; import android.os.Looper; import android.window.InputTransferToken; import android.window.TaskFpsCallback; import android.window.TrustedPresentationThresholds; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.android.window.flags.Flags; import java.util.List; import java.util.Set; import java.util.concurrent.Executor; import java.util.function.Consumer; import java.util.function.IntConsumer; /** * A wrapper that wraps a base {@link WindowManager}. * <p> * Similar to {@link android.content.ContextWrapper}, it enables to customize behavior without * touching the original {@link WindowManager}. * * @hide */ public class WindowManagerWrapper implements WindowManager { @NonNull private final WindowManager mBase; public WindowManagerWrapper(@NonNull WindowManager base) { mBase = base; } @Override public void addView(View view, ViewGroup.LayoutParams params) { mBase.addView(view, params); } @Override public void updateViewLayout(View view, ViewGroup.LayoutParams params) { mBase.updateViewLayout(view, params); } @Override public void removeView(View view) { mBase.removeView(view); } @Deprecated @Override public Display getDefaultDisplay() { return mBase.getDefaultDisplay(); } @Override public void removeViewImmediate(View view) { mBase.removeViewImmediate(view); } @NonNull @Override public WindowMetrics getCurrentWindowMetrics() { return mBase.getCurrentWindowMetrics(); } @NonNull @Override public WindowMetrics getMaximumWindowMetrics() { return mBase.getMaximumWindowMetrics(); } @NonNull @Override public Set<WindowMetrics> getPossibleMaximumWindowMetrics(int displayId) { return mBase.getPossibleMaximumWindowMetrics(displayId); } @Override public void requestAppKeyboardShortcuts(KeyboardShortcutsReceiver receiver, int deviceId) { mBase.requestAppKeyboardShortcuts(receiver, deviceId); } @Override public KeyboardShortcutGroup getApplicationLaunchKeyboardShortcuts(int deviceId) { return mBase.getApplicationLaunchKeyboardShortcuts(deviceId); } @Override public void requestImeKeyboardShortcuts(KeyboardShortcutsReceiver receiver, int deviceId) { mBase.requestImeKeyboardShortcuts(receiver, deviceId); } @RequiresPermission(android.Manifest.permission.RESTRICTED_VR_ACCESS) @Override public Region getCurrentImeTouchRegion() { return mBase.getCurrentImeTouchRegion(); } @Override public void setShouldShowWithInsecureKeyguard(int displayId, boolean shouldShow) { mBase.setShouldShowWithInsecureKeyguard(displayId, shouldShow); } @Override public void setShouldShowSystemDecors(int displayId, boolean shouldShow) { mBase.setShouldShowSystemDecors(displayId, shouldShow); } @Override public boolean shouldShowSystemDecors(int displayId) { return mBase.shouldShowSystemDecors(displayId); } @Override public void setDisplayImePolicy(int displayId, int imePolicy) { mBase.setDisplayImePolicy(displayId, imePolicy); } @FlaggedApi(FLAG_ENABLE_DISPLAY_CONTENT_MODE_MANAGEMENT) @Override public boolean isEligibleForDesktopMode(int displayId) { return mBase.isEligibleForDesktopMode(displayId); } @Override public int getDisplayImePolicy(int displayId) { return mBase.getDisplayImePolicy(displayId); } @Override public boolean isGlobalKey(int keyCode) { return mBase.isGlobalKey(keyCode); } @Override public boolean isCrossWindowBlurEnabled() { return mBase.isCrossWindowBlurEnabled(); } @Override public void addCrossWindowBlurEnabledListener(@NonNull Consumer<Boolean> listener) { mBase.addCrossWindowBlurEnabledListener(listener); } @Override public void addCrossWindowBlurEnabledListener(@NonNull Executor executor, @NonNull Consumer<Boolean> listener) { mBase.addCrossWindowBlurEnabledListener(executor, listener); } @Override public void removeCrossWindowBlurEnabledListener(@NonNull Consumer<Boolean> listener) { mBase.removeCrossWindowBlurEnabledListener(listener); } @Override public void addProposedRotationListener(@NonNull Executor executor, @NonNull IntConsumer listener) { mBase.addProposedRotationListener(executor, listener); } @Override public void removeProposedRotationListener(@NonNull IntConsumer listener) { mBase.removeProposedRotationListener(listener); } @Override public void holdLock(IBinder token, int durationMs) { mBase.holdLock(token, durationMs); } @Override public boolean isTaskSnapshotSupported() { return mBase.isTaskSnapshotSupported(); } @Override public void registerTaskFpsCallback(int taskId, @NonNull Executor executor, @NonNull TaskFpsCallback callback) { mBase.registerTaskFpsCallback(taskId, executor, callback); } @Override public void unregisterTaskFpsCallback(@NonNull TaskFpsCallback callback) { mBase.unregisterTaskFpsCallback(callback); } @Nullable @Override public Bitmap snapshotTaskForRecents(int taskId) { return mBase.snapshotTaskForRecents(taskId); } @NonNull @Override public List<ComponentName> notifyScreenshotListeners(int displayId) { return mBase.notifyScreenshotListeners(displayId); } @RequiresPermission(Manifest.permission.ACCESS_SURFACE_FLINGER) @Override public boolean replaceContentOnDisplayWithMirror(int displayId, @NonNull Window window) { return mBase.replaceContentOnDisplayWithMirror(displayId, window); } @RequiresPermission(Manifest.permission.ACCESS_SURFACE_FLINGER) @Override public boolean replaceContentOnDisplayWithSc(int displayId, @NonNull SurfaceControl sc) { return mBase.replaceContentOnDisplayWithSc(displayId, sc); } @FlaggedApi(Flags.FLAG_TRUSTED_PRESENTATION_LISTENER_FOR_WINDOW) @Override public void registerTrustedPresentationListener(@NonNull IBinder window, @NonNull TrustedPresentationThresholds thresholds, @NonNull Executor executor, @NonNull Consumer<Boolean> listener) { mBase.registerTrustedPresentationListener(window, thresholds, executor, listener); } @FlaggedApi(Flags.FLAG_TRUSTED_PRESENTATION_LISTENER_FOR_WINDOW) @Override public void unregisterTrustedPresentationListener(@NonNull Consumer<Boolean> listener) { mBase.unregisterTrustedPresentationListener(listener); } @FlaggedApi(Flags.FLAG_SURFACE_CONTROL_INPUT_RECEIVER) @NonNull @Override public InputTransferToken registerBatchedSurfaceControlInputReceiver( @NonNull InputTransferToken hostInputTransferToken, @NonNull SurfaceControl surfaceControl, @NonNull Choreographer choreographer, @NonNull SurfaceControlInputReceiver receiver) { return mBase.registerBatchedSurfaceControlInputReceiver( hostInputTransferToken, surfaceControl, choreographer, receiver); } @FlaggedApi(Flags.FLAG_SURFACE_CONTROL_INPUT_RECEIVER) @NonNull @Override public InputTransferToken registerUnbatchedSurfaceControlInputReceiver( @NonNull InputTransferToken hostInputTransferToken, @NonNull SurfaceControl surfaceControl, @NonNull Looper looper, @NonNull SurfaceControlInputReceiver receiver) { return mBase.registerUnbatchedSurfaceControlInputReceiver( hostInputTransferToken, surfaceControl, looper, receiver); } @FlaggedApi(Flags.FLAG_SURFACE_CONTROL_INPUT_RECEIVER) @Override public void unregisterSurfaceControlInputReceiver(@NonNull SurfaceControl surfaceControl) { mBase.unregisterSurfaceControlInputReceiver(surfaceControl); } @FlaggedApi(Flags.FLAG_SURFACE_CONTROL_INPUT_RECEIVER) @Nullable @Override public IBinder getSurfaceControlInputClientToken(@NonNull SurfaceControl surfaceControl) { return mBase.getSurfaceControlInputClientToken(surfaceControl); } @FlaggedApi(Flags.FLAG_SURFACE_CONTROL_INPUT_RECEIVER) @Override public boolean transferTouchGesture(@NonNull InputTransferToken transferFromToken, @NonNull InputTransferToken transferToToken) { return mBase.transferTouchGesture(transferFromToken, transferToToken); } @NonNull @Override public IBinder getDefaultToken() { return mBase.getDefaultToken(); } @FlaggedApi(Flags.FLAG_SCREEN_RECORDING_CALLBACKS) @RequiresPermission(Manifest.permission.DETECT_SCREEN_RECORDING) @Override public @ScreenRecordingState int addScreenRecordingCallback(@NonNull Executor executor, @NonNull Consumer<@ScreenRecordingState Integer> callback) { return mBase.addScreenRecordingCallback(executor, callback); } @FlaggedApi(Flags.FLAG_SCREEN_RECORDING_CALLBACKS) @RequiresPermission(Manifest.permission.DETECT_SCREEN_RECORDING) @Override public void removeScreenRecordingCallback( @NonNull Consumer<@ScreenRecordingState Integer> callback) { mBase.removeScreenRecordingCallback(callback); } @Override public WindowManager createLocalWindowManager(@NonNull Window parentWindow) { final WindowManager newBase = mBase.createLocalWindowManager(parentWindow); return new WindowManagerWrapper(newBase); } @Override public void setParentWindow(@NonNull Window parentWindow) { mBase.setParentWindow(parentWindow); } }
core/tests/coretests/src/android/view/WindowManagerWrapperTest.kt 0 → 100644 +60 −0 Original line number Diff line number Diff line /* * Copyright (C) 2025 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 import android.platform.test.annotations.Presubmit import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.google.common.truth.Truth.assertThat import org.junit.Test import org.junit.runner.RunWith /** * Tests for the [WindowManagerWrapper]. * * Build/Install/Run: * atest FrameworksCoreTests:WindowManagerWrapperTest */ @RunWith(AndroidJUnit4::class) @SmallTest @Presubmit class WindowManagerWrapperTest { /** * Tests that all default methods from [WindowManager] are implemented. */ @Test fun testWindowManagerWrapperImplementation() { val windowManagerInterface = WindowManager::class.java val wmInterfaceMethods = windowManagerInterface.methods val windowManagerWrapperClass = WindowManagerWrapper::class.java val wrapperMethodsFromWm = windowManagerWrapperClass.declaredMethods .filter { m -> windowManagerInterface.isAssignableFrom(m.declaringClass) } .map { m -> m.name } .toSet() // Only checks the default methods in WM interface. Missing implementation of non-default // methods should be caught at compile time. val wmDefaultMethods = wmInterfaceMethods .filter { m -> m.isDefault } .map { m -> m.name } .toList() for (defaultMethod in wmDefaultMethods) { assertThat(wrapperMethodsFromWm).contains(defaultMethod) } } }