Loading core/java/android/view/WindowManager.java +13 −1 Original line number Diff line number Diff line Loading @@ -2725,7 +2725,9 @@ public interface WindowManager extends ViewManager { TYPE_APPLICATION_OVERLAY, TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY, TYPE_NOTIFICATION_SHADE, TYPE_STATUS_BAR_ADDITIONAL TYPE_STATUS_BAR_ADDITIONAL, // TODO(b/398759994): Rename to TYPE_INVALID INVALID_WINDOW_TYPE, }) @Retention(RetentionPolicy.SOURCE) public @interface WindowType {} Loading @@ -2750,6 +2752,16 @@ public interface WindowManager extends ViewManager { return false; } /** * Returns {@code true} if the given {@code type} is a sub-window type. * * @hide */ public static boolean isSubWindowType(@WindowType int type) { return (type >= FIRST_SUB_WINDOW && type <= LAST_SUB_WINDOW) || type == TYPE_STATUS_BAR_SUB_PANEL; } /** @deprecated this is ignored, this value is set automatically when needed. */ @Deprecated public static final int MEMORY_TYPE_NORMAL = 0; Loading core/java/android/view/WindowManagerGlobal.java +22 −0 Original line number Diff line number Diff line Loading @@ -47,6 +47,7 @@ import android.view.inputmethod.InputMethodManager; import android.window.ITrustedPresentationListener; import android.window.InputTransferToken; import android.window.TrustedPresentationThresholds; import android.window.WindowContext; import com.android.internal.R; import com.android.internal.annotations.GuardedBy; Loading Loading @@ -1107,6 +1108,27 @@ public final class WindowManagerGlobal { mInputEventReceiver = inputEventReceiver; } } /** * Checks whether {@link WindowContext#getWindowTypeOverride()} can be applied when * {@link WindowManager#addView} or {@link WindowManager#updateViewLayout}. * * @param windowTypeToOverride the window type to override * @param view the view that applies the window type */ public boolean canApplyWindowTypeOverride( @WindowManager.LayoutParams.WindowType int windowTypeToOverride, @NonNull View view) { final int index = findViewLocked(view, false /* required */); if (index < 0) { // The view has not been added yet. Window type can be overridden. return true; } final WindowManager.LayoutParams params = mParams.get(index); // If the view has been attached, we should make sure the override type matches the existing // one. The window type can't be changed after the view was added. return windowTypeToOverride == params.type; } } final class WindowLeaked extends AndroidRuntimeException { Loading core/java/android/view/WindowManagerImpl.java +42 −11 Original line number Diff line number Diff line Loading @@ -16,8 +16,8 @@ package android.view; import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW; import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW; import static android.view.WindowManager.LayoutParams.INVALID_WINDOW_TYPE; import static android.view.WindowManager.LayoutParams.isSubWindowType; import static android.window.WindowProviderService.isWindowProviderService; import static com.android.window.flags.Flags.screenRecordingCallbacks; Loading Loading @@ -49,6 +49,7 @@ import android.window.WindowProvider; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.os.IResultReceiver; import com.android.window.flags.Flags; import java.util.ArrayList; import java.util.Iterator; Loading Loading @@ -93,7 +94,7 @@ public class WindowManagerImpl implements WindowManager { @UiContext @VisibleForTesting public final Context mContext; private final Window mParentWindow; private Window mParentWindow; /** * If {@link LayoutParams#token} is {@code null} and no parent window is specified, the value Loading Loading @@ -152,8 +153,16 @@ public class WindowManagerImpl implements WindowManager { mDefaultToken = token; } /** * Sets the parent window. */ public void setParentWindow(@NonNull Window parentWindow) { mParentWindow = parentWindow; } @Override public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) { applyWindowTypeOverrideIfNeeded(params, view); applyTokens(params); mGlobal.addView(view, params, mContext.getDisplayNoVerify(), mParentWindow, mContext.getUserId()); Loading @@ -161,6 +170,7 @@ public class WindowManagerImpl implements WindowManager { @Override public void updateViewLayout(@NonNull View view, @NonNull ViewGroup.LayoutParams params) { applyWindowTypeOverrideIfNeeded(params, view); applyTokens(params); mGlobal.updateViewLayout(view, params); } Loading @@ -179,16 +189,10 @@ public class WindowManagerImpl implements WindowManager { } private void assertWindowContextTypeMatches(@LayoutParams.WindowType int windowType) { if (!(mContext instanceof WindowProvider)) { if (!(mContext instanceof WindowProvider windowProvider)) { return; } // Don't need to check sub-window type because sub window should be allowed to be attached // to the parent window. if (windowType >= FIRST_SUB_WINDOW && windowType <= LAST_SUB_WINDOW) { return; } final WindowProvider windowProvider = (WindowProvider) mContext; if (windowProvider.getWindowType() == windowType) { if (windowProvider.isValidWindowType(windowType)) { return; } IllegalArgumentException exception = new IllegalArgumentException("Window type mismatch." Loading @@ -206,6 +210,33 @@ public class WindowManagerImpl implements WindowManager { + " match type in WindowManager.LayoutParams", exception); } private void applyWindowTypeOverrideIfNeeded( @NonNull ViewGroup.LayoutParams params, @NonNull View view) { if (!Flags.enableWindowContextOverrideType()) { return; } if (!(params instanceof WindowManager.LayoutParams wparams)) { throw new IllegalArgumentException("Params must be WindowManager.LayoutParams"); } if (!(mContext instanceof WindowProvider windowProvider)) { return; } final int windowTypeOverride = windowProvider.getWindowTypeOverride(); if (windowTypeOverride == INVALID_WINDOW_TYPE) { return; } if (!mGlobal.canApplyWindowTypeOverride(windowTypeOverride, view)) { return; } if (isSubWindowType(windowTypeOverride) && mParentWindow == null) { throw new IllegalArgumentException("Sub-window must be attached to the parent window." + " Please try to obtain WindowManager from a window class, call " + "WindowContext#attachWindow before adding any sub-windows."); } wparams.type = windowTypeOverride; } @Override public void removeView(View view) { mGlobal.removeView(view, false); Loading core/java/android/window/WindowBase.java 0 → 100644 +226 −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.window; import android.content.Context; import android.content.res.Configuration; import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Bundle; import android.view.InputQueue; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.SurfaceHolder; import android.view.View; import android.view.ViewGroup; import android.view.Window; import androidx.annotation.Nullable; /** * A helper class that has the minimum implementation of {@link Window}. * * @hide */ public abstract class WindowBase extends Window { public WindowBase(Context context) { super(context); } @Override public void takeSurface(SurfaceHolder.Callback2 callback) {} @Override public void takeInputQueue(InputQueue.Callback callback) {} @Override public boolean isFloating() { return false; } @Override public void alwaysReadCloseOnTouchAttr() {} @Override public void setContentView(int layoutResID) {} @Override public void setContentView(View view) {} @Override public void setContentView(View view, ViewGroup.LayoutParams params) {} @Override public void addContentView(View view, ViewGroup.LayoutParams params) {} @Override public void clearContentView() {} @Nullable @Override public View getCurrentFocus() { return null; } @Override public void setTitle(CharSequence title) {} @Override public void setTitleColor(int textColor) {} @Override public void openPanel(int featureId, KeyEvent event) {} @Override public void closePanel(int featureId) {} @Override public void togglePanel(int featureId, KeyEvent event) {} @Override public void invalidatePanelMenu(int featureId) {} @Override public boolean performPanelShortcut(int featureId, int keyCode, KeyEvent event, int flags) { return false; } @Override public boolean performPanelIdentifierAction(int featureId, int id, int flags) { return false; } @Override public void closeAllPanels() {} @Override public boolean performContextMenuIdentifierAction(int id, int flags) { return false; } @Override public void onConfigurationChanged(Configuration newConfig) {} @Override public void setBackgroundDrawable(Drawable drawable) {} @Override public void setFeatureDrawableResource(int featureId, int resId) {} @Override public void setFeatureDrawableUri(int featureId, Uri uri) {} @Override public void setFeatureDrawable(int featureId, Drawable drawable) {} @Override public void setFeatureDrawableAlpha(int featureId, int alpha) {} @Override public void setFeatureInt(int featureId, int value) {} @Override public void takeKeyEvents(boolean get) {} @Override public boolean superDispatchKeyEvent(KeyEvent event) { return false; } @Override public boolean superDispatchKeyShortcutEvent(KeyEvent event) { return false; } @Override public boolean superDispatchTouchEvent(MotionEvent event) { return false; } @Override public boolean superDispatchTrackballEvent(MotionEvent event) { return false; } @Override public boolean superDispatchGenericMotionEvent(MotionEvent event) { return false; } @Override public View peekDecorView() { return null; } @Override public Bundle saveHierarchyState() { return null; } @Override public void restoreHierarchyState(Bundle savedInstanceState) {} @Override protected void onActive() {} @Override public void setChildDrawable(int featureId, Drawable drawable) {} @Override public void setChildInt(int featureId, int value) {} @Override public boolean isShortcutKey(int keyCode, KeyEvent event) { return false; } @Override public void setVolumeControlStream(int streamType) {} @Override public int getVolumeControlStream() { return 0; } @Override public int getStatusBarColor() { return 0; } @Override public void setStatusBarColor(int color) {} @Override public int getNavigationBarColor() { return 0; } @Override public void setNavigationBarColor(int color) {} @Override public void setDecorCaptionShade(int decorCaptionShade) {} @Override public void setResizingCaptionDrawable(Drawable drawable) {} @Override public void onMultiWindowModeChanged() {} @Override public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode) {} } core/java/android/window/WindowContext.java +120 −8 Original line number Diff line number Diff line Loading @@ -15,8 +15,11 @@ */ package android.window; import static android.view.WindowManager.LayoutParams.INVALID_WINDOW_TYPE; import static android.view.WindowManagerImpl.createWindowContextWindowManager; import static java.util.Objects.requireNonNull; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UiContext; Loading @@ -27,7 +30,12 @@ import android.content.ContextWrapper; import android.content.res.Configuration; import android.os.Bundle; import android.view.Display; import android.view.LayoutInflater; import android.view.View; import android.view.Window; import android.view.WindowManager; import android.view.WindowManager.LayoutParams.WindowType; import android.view.WindowManagerImpl; import com.android.internal.annotations.VisibleForTesting; import com.android.window.flags.Flags; Loading @@ -46,15 +54,18 @@ import java.lang.ref.Reference; @UiContext public class WindowContext extends ContextWrapper implements WindowProvider, ConfigurationDispatcher { private final WindowManager mWindowManager; @WindowManager.LayoutParams.WindowType @WindowType private final int mType; @Nullable private final Bundle mOptions; @WindowType private int mWindowTypeOverride = INVALID_WINDOW_TYPE; private final ComponentCallbacksController mCallbacksController = new ComponentCallbacksController(); private final WindowContextController mController; private WindowManager mWindowManager; /** * Default implementation of {@link WindowContext} * <p> Loading @@ -73,14 +84,16 @@ public class WindowContext extends ContextWrapper implements WindowProvider, * @param options A bundle used to pass window-related options. * @see DisplayAreaInfo#rootDisplayAreaId */ public WindowContext(@NonNull Context base, int type, @Nullable Bundle options) { public WindowContext(@NonNull Context base, @WindowType int type, @Nullable Bundle options) { super(base); mType = type; mOptions = options; mWindowManager = createWindowContextWindowManager(this); WindowTokenClient token = (WindowTokenClient) getWindowContextToken(); mController = new WindowContextController(token); mController = new WindowContextController(requireNonNull(token)); Reference.reachabilityFence(this); } Loading Loading @@ -153,12 +166,58 @@ public class WindowContext extends ContextWrapper implements WindowProvider, mCallbacksController.unregisterCallbacks(callback); } /** Dispatch {@link Configuration} to each {@link ComponentCallbacks}. */ @Override public void dispatchConfigurationChanged(@NonNull Configuration newConfig) { mCallbacksController.dispatchConfigurationChanged(newConfig); /** * If set, this {@code WindowContext} will override the window type when * {@link WindowManager#addView} or {@link WindowManager#updateViewLayout}. * <p> * Allowed window types are {@link #getWindowType()} and * any sub-window types. If set to {@link WindowManager.LayoutParams#INVALID_WINDOW_TYPE}, * this {@code WindowContext} won't override the type. * <p> * Note: * <ol> * <li>If a view is attached, the window type won't be overridden to another window type.</li> * <li>If a sub-window override is requested, a parent window must be prepared. It can * be either by using {@link WindowManager} from a {@link Window} or calling * {@link #attachWindow(View)} before adding any sub-windows, or * {@link IllegalArgumentException} throws when {@link WindowManager#addView}. * </li> * </ol> * * @throws IllegalArgumentException if the passed {@code windowTypeOverride} is not an allowed * window type mentioned above. */ public void setWindowTypeOverride(@WindowType int windowTypeOverride) { if (!Flags.enableWindowContextOverrideType()) { return; } if (!isValidWindowType(windowTypeOverride) && windowTypeOverride != INVALID_WINDOW_TYPE) { throw new IllegalArgumentException( "The window type override must be either " + mType + " or a sub window type, but it's " + windowTypeOverride ); } mWindowTypeOverride = windowTypeOverride; } /** * Associates {@code window} to this {@code WindowContext} and attach {@code window} to * associated {@link WindowManager}. * <p> * Note that this method must be called before {@link WindowManager#addView}. */ public void attachWindow(@NonNull View window) { if (!Flags.enableWindowContextOverrideType()) { return; } final Window wrapper = new WindowWrapper(this, window); ((WindowManagerImpl) mWindowManager).setParentWindow(wrapper); } /* === WindowProvider APIs === */ @Override public int getWindowType() { return mType; Loading @@ -170,9 +229,62 @@ public class WindowContext extends ContextWrapper implements WindowProvider, return mOptions; } @WindowType @Override public int getWindowTypeOverride() { return mWindowTypeOverride; } /* === ConfigurationDispatcher APIs === */ @Override public boolean shouldReportPrivateChanges() { // Always dispatch config changes to WindowContext. return true; } /** Dispatch {@link Configuration} to each {@link ComponentCallbacks}. */ @Override public void dispatchConfigurationChanged(@NonNull Configuration newConfig) { mCallbacksController.dispatchConfigurationChanged(newConfig); } /** * A simple {@link Window} wrapper that is used to pass to * {@link WindowManagerImpl#createLocalWindowManager(Window)}. */ private static class WindowWrapper extends WindowBase { @NonNull private final View mDecorView; /** * The {@link WindowWrapper} constructor. * * @param context the associated {@link WindowContext}` * @param decorView the view to be wrapped as {@link Window}'s decor view. */ WindowWrapper(@NonNull @UiContext Context context, @NonNull View decorView) { super(context); mDecorView = requireNonNull(decorView); } @NonNull @Override public LayoutInflater getLayoutInflater() { return LayoutInflater.from(mDecorView.getContext()); } @NonNull @Override public View getDecorView() { return mDecorView; } @Override public View peekDecorView() { return mDecorView; } } } Loading
core/java/android/view/WindowManager.java +13 −1 Original line number Diff line number Diff line Loading @@ -2725,7 +2725,9 @@ public interface WindowManager extends ViewManager { TYPE_APPLICATION_OVERLAY, TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY, TYPE_NOTIFICATION_SHADE, TYPE_STATUS_BAR_ADDITIONAL TYPE_STATUS_BAR_ADDITIONAL, // TODO(b/398759994): Rename to TYPE_INVALID INVALID_WINDOW_TYPE, }) @Retention(RetentionPolicy.SOURCE) public @interface WindowType {} Loading @@ -2750,6 +2752,16 @@ public interface WindowManager extends ViewManager { return false; } /** * Returns {@code true} if the given {@code type} is a sub-window type. * * @hide */ public static boolean isSubWindowType(@WindowType int type) { return (type >= FIRST_SUB_WINDOW && type <= LAST_SUB_WINDOW) || type == TYPE_STATUS_BAR_SUB_PANEL; } /** @deprecated this is ignored, this value is set automatically when needed. */ @Deprecated public static final int MEMORY_TYPE_NORMAL = 0; Loading
core/java/android/view/WindowManagerGlobal.java +22 −0 Original line number Diff line number Diff line Loading @@ -47,6 +47,7 @@ import android.view.inputmethod.InputMethodManager; import android.window.ITrustedPresentationListener; import android.window.InputTransferToken; import android.window.TrustedPresentationThresholds; import android.window.WindowContext; import com.android.internal.R; import com.android.internal.annotations.GuardedBy; Loading Loading @@ -1107,6 +1108,27 @@ public final class WindowManagerGlobal { mInputEventReceiver = inputEventReceiver; } } /** * Checks whether {@link WindowContext#getWindowTypeOverride()} can be applied when * {@link WindowManager#addView} or {@link WindowManager#updateViewLayout}. * * @param windowTypeToOverride the window type to override * @param view the view that applies the window type */ public boolean canApplyWindowTypeOverride( @WindowManager.LayoutParams.WindowType int windowTypeToOverride, @NonNull View view) { final int index = findViewLocked(view, false /* required */); if (index < 0) { // The view has not been added yet. Window type can be overridden. return true; } final WindowManager.LayoutParams params = mParams.get(index); // If the view has been attached, we should make sure the override type matches the existing // one. The window type can't be changed after the view was added. return windowTypeToOverride == params.type; } } final class WindowLeaked extends AndroidRuntimeException { Loading
core/java/android/view/WindowManagerImpl.java +42 −11 Original line number Diff line number Diff line Loading @@ -16,8 +16,8 @@ package android.view; import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW; import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW; import static android.view.WindowManager.LayoutParams.INVALID_WINDOW_TYPE; import static android.view.WindowManager.LayoutParams.isSubWindowType; import static android.window.WindowProviderService.isWindowProviderService; import static com.android.window.flags.Flags.screenRecordingCallbacks; Loading Loading @@ -49,6 +49,7 @@ import android.window.WindowProvider; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.os.IResultReceiver; import com.android.window.flags.Flags; import java.util.ArrayList; import java.util.Iterator; Loading Loading @@ -93,7 +94,7 @@ public class WindowManagerImpl implements WindowManager { @UiContext @VisibleForTesting public final Context mContext; private final Window mParentWindow; private Window mParentWindow; /** * If {@link LayoutParams#token} is {@code null} and no parent window is specified, the value Loading Loading @@ -152,8 +153,16 @@ public class WindowManagerImpl implements WindowManager { mDefaultToken = token; } /** * Sets the parent window. */ public void setParentWindow(@NonNull Window parentWindow) { mParentWindow = parentWindow; } @Override public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) { applyWindowTypeOverrideIfNeeded(params, view); applyTokens(params); mGlobal.addView(view, params, mContext.getDisplayNoVerify(), mParentWindow, mContext.getUserId()); Loading @@ -161,6 +170,7 @@ public class WindowManagerImpl implements WindowManager { @Override public void updateViewLayout(@NonNull View view, @NonNull ViewGroup.LayoutParams params) { applyWindowTypeOverrideIfNeeded(params, view); applyTokens(params); mGlobal.updateViewLayout(view, params); } Loading @@ -179,16 +189,10 @@ public class WindowManagerImpl implements WindowManager { } private void assertWindowContextTypeMatches(@LayoutParams.WindowType int windowType) { if (!(mContext instanceof WindowProvider)) { if (!(mContext instanceof WindowProvider windowProvider)) { return; } // Don't need to check sub-window type because sub window should be allowed to be attached // to the parent window. if (windowType >= FIRST_SUB_WINDOW && windowType <= LAST_SUB_WINDOW) { return; } final WindowProvider windowProvider = (WindowProvider) mContext; if (windowProvider.getWindowType() == windowType) { if (windowProvider.isValidWindowType(windowType)) { return; } IllegalArgumentException exception = new IllegalArgumentException("Window type mismatch." Loading @@ -206,6 +210,33 @@ public class WindowManagerImpl implements WindowManager { + " match type in WindowManager.LayoutParams", exception); } private void applyWindowTypeOverrideIfNeeded( @NonNull ViewGroup.LayoutParams params, @NonNull View view) { if (!Flags.enableWindowContextOverrideType()) { return; } if (!(params instanceof WindowManager.LayoutParams wparams)) { throw new IllegalArgumentException("Params must be WindowManager.LayoutParams"); } if (!(mContext instanceof WindowProvider windowProvider)) { return; } final int windowTypeOverride = windowProvider.getWindowTypeOverride(); if (windowTypeOverride == INVALID_WINDOW_TYPE) { return; } if (!mGlobal.canApplyWindowTypeOverride(windowTypeOverride, view)) { return; } if (isSubWindowType(windowTypeOverride) && mParentWindow == null) { throw new IllegalArgumentException("Sub-window must be attached to the parent window." + " Please try to obtain WindowManager from a window class, call " + "WindowContext#attachWindow before adding any sub-windows."); } wparams.type = windowTypeOverride; } @Override public void removeView(View view) { mGlobal.removeView(view, false); Loading
core/java/android/window/WindowBase.java 0 → 100644 +226 −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.window; import android.content.Context; import android.content.res.Configuration; import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Bundle; import android.view.InputQueue; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.SurfaceHolder; import android.view.View; import android.view.ViewGroup; import android.view.Window; import androidx.annotation.Nullable; /** * A helper class that has the minimum implementation of {@link Window}. * * @hide */ public abstract class WindowBase extends Window { public WindowBase(Context context) { super(context); } @Override public void takeSurface(SurfaceHolder.Callback2 callback) {} @Override public void takeInputQueue(InputQueue.Callback callback) {} @Override public boolean isFloating() { return false; } @Override public void alwaysReadCloseOnTouchAttr() {} @Override public void setContentView(int layoutResID) {} @Override public void setContentView(View view) {} @Override public void setContentView(View view, ViewGroup.LayoutParams params) {} @Override public void addContentView(View view, ViewGroup.LayoutParams params) {} @Override public void clearContentView() {} @Nullable @Override public View getCurrentFocus() { return null; } @Override public void setTitle(CharSequence title) {} @Override public void setTitleColor(int textColor) {} @Override public void openPanel(int featureId, KeyEvent event) {} @Override public void closePanel(int featureId) {} @Override public void togglePanel(int featureId, KeyEvent event) {} @Override public void invalidatePanelMenu(int featureId) {} @Override public boolean performPanelShortcut(int featureId, int keyCode, KeyEvent event, int flags) { return false; } @Override public boolean performPanelIdentifierAction(int featureId, int id, int flags) { return false; } @Override public void closeAllPanels() {} @Override public boolean performContextMenuIdentifierAction(int id, int flags) { return false; } @Override public void onConfigurationChanged(Configuration newConfig) {} @Override public void setBackgroundDrawable(Drawable drawable) {} @Override public void setFeatureDrawableResource(int featureId, int resId) {} @Override public void setFeatureDrawableUri(int featureId, Uri uri) {} @Override public void setFeatureDrawable(int featureId, Drawable drawable) {} @Override public void setFeatureDrawableAlpha(int featureId, int alpha) {} @Override public void setFeatureInt(int featureId, int value) {} @Override public void takeKeyEvents(boolean get) {} @Override public boolean superDispatchKeyEvent(KeyEvent event) { return false; } @Override public boolean superDispatchKeyShortcutEvent(KeyEvent event) { return false; } @Override public boolean superDispatchTouchEvent(MotionEvent event) { return false; } @Override public boolean superDispatchTrackballEvent(MotionEvent event) { return false; } @Override public boolean superDispatchGenericMotionEvent(MotionEvent event) { return false; } @Override public View peekDecorView() { return null; } @Override public Bundle saveHierarchyState() { return null; } @Override public void restoreHierarchyState(Bundle savedInstanceState) {} @Override protected void onActive() {} @Override public void setChildDrawable(int featureId, Drawable drawable) {} @Override public void setChildInt(int featureId, int value) {} @Override public boolean isShortcutKey(int keyCode, KeyEvent event) { return false; } @Override public void setVolumeControlStream(int streamType) {} @Override public int getVolumeControlStream() { return 0; } @Override public int getStatusBarColor() { return 0; } @Override public void setStatusBarColor(int color) {} @Override public int getNavigationBarColor() { return 0; } @Override public void setNavigationBarColor(int color) {} @Override public void setDecorCaptionShade(int decorCaptionShade) {} @Override public void setResizingCaptionDrawable(Drawable drawable) {} @Override public void onMultiWindowModeChanged() {} @Override public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode) {} }
core/java/android/window/WindowContext.java +120 −8 Original line number Diff line number Diff line Loading @@ -15,8 +15,11 @@ */ package android.window; import static android.view.WindowManager.LayoutParams.INVALID_WINDOW_TYPE; import static android.view.WindowManagerImpl.createWindowContextWindowManager; import static java.util.Objects.requireNonNull; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UiContext; Loading @@ -27,7 +30,12 @@ import android.content.ContextWrapper; import android.content.res.Configuration; import android.os.Bundle; import android.view.Display; import android.view.LayoutInflater; import android.view.View; import android.view.Window; import android.view.WindowManager; import android.view.WindowManager.LayoutParams.WindowType; import android.view.WindowManagerImpl; import com.android.internal.annotations.VisibleForTesting; import com.android.window.flags.Flags; Loading @@ -46,15 +54,18 @@ import java.lang.ref.Reference; @UiContext public class WindowContext extends ContextWrapper implements WindowProvider, ConfigurationDispatcher { private final WindowManager mWindowManager; @WindowManager.LayoutParams.WindowType @WindowType private final int mType; @Nullable private final Bundle mOptions; @WindowType private int mWindowTypeOverride = INVALID_WINDOW_TYPE; private final ComponentCallbacksController mCallbacksController = new ComponentCallbacksController(); private final WindowContextController mController; private WindowManager mWindowManager; /** * Default implementation of {@link WindowContext} * <p> Loading @@ -73,14 +84,16 @@ public class WindowContext extends ContextWrapper implements WindowProvider, * @param options A bundle used to pass window-related options. * @see DisplayAreaInfo#rootDisplayAreaId */ public WindowContext(@NonNull Context base, int type, @Nullable Bundle options) { public WindowContext(@NonNull Context base, @WindowType int type, @Nullable Bundle options) { super(base); mType = type; mOptions = options; mWindowManager = createWindowContextWindowManager(this); WindowTokenClient token = (WindowTokenClient) getWindowContextToken(); mController = new WindowContextController(token); mController = new WindowContextController(requireNonNull(token)); Reference.reachabilityFence(this); } Loading Loading @@ -153,12 +166,58 @@ public class WindowContext extends ContextWrapper implements WindowProvider, mCallbacksController.unregisterCallbacks(callback); } /** Dispatch {@link Configuration} to each {@link ComponentCallbacks}. */ @Override public void dispatchConfigurationChanged(@NonNull Configuration newConfig) { mCallbacksController.dispatchConfigurationChanged(newConfig); /** * If set, this {@code WindowContext} will override the window type when * {@link WindowManager#addView} or {@link WindowManager#updateViewLayout}. * <p> * Allowed window types are {@link #getWindowType()} and * any sub-window types. If set to {@link WindowManager.LayoutParams#INVALID_WINDOW_TYPE}, * this {@code WindowContext} won't override the type. * <p> * Note: * <ol> * <li>If a view is attached, the window type won't be overridden to another window type.</li> * <li>If a sub-window override is requested, a parent window must be prepared. It can * be either by using {@link WindowManager} from a {@link Window} or calling * {@link #attachWindow(View)} before adding any sub-windows, or * {@link IllegalArgumentException} throws when {@link WindowManager#addView}. * </li> * </ol> * * @throws IllegalArgumentException if the passed {@code windowTypeOverride} is not an allowed * window type mentioned above. */ public void setWindowTypeOverride(@WindowType int windowTypeOverride) { if (!Flags.enableWindowContextOverrideType()) { return; } if (!isValidWindowType(windowTypeOverride) && windowTypeOverride != INVALID_WINDOW_TYPE) { throw new IllegalArgumentException( "The window type override must be either " + mType + " or a sub window type, but it's " + windowTypeOverride ); } mWindowTypeOverride = windowTypeOverride; } /** * Associates {@code window} to this {@code WindowContext} and attach {@code window} to * associated {@link WindowManager}. * <p> * Note that this method must be called before {@link WindowManager#addView}. */ public void attachWindow(@NonNull View window) { if (!Flags.enableWindowContextOverrideType()) { return; } final Window wrapper = new WindowWrapper(this, window); ((WindowManagerImpl) mWindowManager).setParentWindow(wrapper); } /* === WindowProvider APIs === */ @Override public int getWindowType() { return mType; Loading @@ -170,9 +229,62 @@ public class WindowContext extends ContextWrapper implements WindowProvider, return mOptions; } @WindowType @Override public int getWindowTypeOverride() { return mWindowTypeOverride; } /* === ConfigurationDispatcher APIs === */ @Override public boolean shouldReportPrivateChanges() { // Always dispatch config changes to WindowContext. return true; } /** Dispatch {@link Configuration} to each {@link ComponentCallbacks}. */ @Override public void dispatchConfigurationChanged(@NonNull Configuration newConfig) { mCallbacksController.dispatchConfigurationChanged(newConfig); } /** * A simple {@link Window} wrapper that is used to pass to * {@link WindowManagerImpl#createLocalWindowManager(Window)}. */ private static class WindowWrapper extends WindowBase { @NonNull private final View mDecorView; /** * The {@link WindowWrapper} constructor. * * @param context the associated {@link WindowContext}` * @param decorView the view to be wrapped as {@link Window}'s decor view. */ WindowWrapper(@NonNull @UiContext Context context, @NonNull View decorView) { super(context); mDecorView = requireNonNull(decorView); } @NonNull @Override public LayoutInflater getLayoutInflater() { return LayoutInflater.from(mDecorView.getContext()); } @NonNull @Override public View getDecorView() { return mDecorView; } @Override public View peekDecorView() { return mDecorView; } } }