Loading core/java/android/view/WindowManager.java +57 −5 Original line number Diff line number Diff line Loading @@ -93,8 +93,12 @@ import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.TestApi; import android.app.ActivityTaskManager; import android.app.ActivityThread; import android.app.KeyguardManager; import android.app.Presentation; import android.compat.annotation.ChangeId; import android.compat.annotation.EnabledSince; import android.compat.annotation.UnsupportedAppUsage; import android.content.ClipData; import android.content.ComponentName; Loading Loading @@ -1416,23 +1420,71 @@ public interface WindowManager extends ViewManager { public static final String PARCEL_KEY_SHORTCUTS_ARRAY = "shortcuts_array"; /** * Whether the device supports the WindowManager Extensions. * OEMs can enable this by having their device config to inherit window_extensions.mk, such as: * Whether the WindowManager Extensions - Activity Embedding feature should be guarded by * the app's target SDK on Android 15. * * WindowManager Extensions are only required for foldable and large screen before Android 15, * so we want to guard the Activity Embedding feature since it can have app compat impact on * devices with a compact size display. * * <p>If {@code true}, the feature is only enabled if the app's target SDK is Android 15 or * above. * * <p>If {@code false}, the feature is enabled for all apps. * * <p>The default value is {@code true}. OEMs can set to {@code false} by having their device * config to inherit window_extensions.mk. This is also required for large screen devices. * <pre> * $(call inherit-product, $(SRC_TARGET_DIR)/product/window_extensions.mk) * </pre> * * @hide */ boolean ACTIVITY_EMBEDDING_GUARD_WITH_ANDROID_15 = SystemProperties.getBoolean( "persist.wm.extensions.activity_embedding_guard_with_android_15", true); /** * For devices with {@link #ACTIVITY_EMBEDDING_GUARD_WITH_ANDROID_15} as {@code true}, * the Activity Embedding feature is enabled if the app's target SDK is Android 15+. * * @see #ACTIVITY_EMBEDDING_GUARD_WITH_ANDROID_15 * @hide */ @ChangeId @EnabledSince(targetSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM) long ENABLE_ACTIVITY_EMBEDDING_FOR_ANDROID_15 = 306666082L; /** * Whether the device contains the WindowManager Extensions shared library. * This is enabled for all devices through window_extensions_base.mk, but can be dropped if the * device doesn't support multi window. * * <p>Note: Large screen devices must also inherit window_extensions.mk to enable the Activity * Embedding feature by default for all apps. * * @see #ACTIVITY_EMBEDDING_GUARD_WITH_ANDROID_15 * @hide */ boolean WINDOW_EXTENSIONS_ENABLED = boolean HAS_WINDOW_EXTENSIONS_ON_DEVICE = SystemProperties.getBoolean("persist.wm.extensions.enabled", false); /** * @see #WINDOW_EXTENSIONS_ENABLED * Whether the WindowManager Extensions are enabled. * If {@code false}, the WM Jetpack will report most of its features as disabled. * @see #HAS_WINDOW_EXTENSIONS_ON_DEVICE * @hide */ @TestApi static boolean hasWindowExtensionsEnabled() { return WINDOW_EXTENSIONS_ENABLED; return HAS_WINDOW_EXTENSIONS_ON_DEVICE && ActivityTaskManager.supportsMultiWindow(ActivityThread.currentApplication()) // Since enableWmExtensionsForAllFlag, HAS_WINDOW_EXTENSIONS_ON_DEVICE is now true // on all devices by default as a build file property. // Until finishing flag ramp up, only return true when // ACTIVITY_EMBEDDING_GUARD_WITH_ANDROID_15 is false, which is set per device by // OEMs. && (Flags.enableWmExtensionsForAllFlag() || !ACTIVITY_EMBEDDING_GUARD_WITH_ANDROID_15); } /** Loading core/java/com/android/internal/os/ZygoteInit.java +1 −1 Original line number Diff line number Diff line Loading @@ -400,7 +400,7 @@ public class ZygoteInit { // WindowManager Extensions is an optional shared library that is required for WindowManager // Jetpack to fully function. Since it is a widely used library, preload it to improve apps // startup performance. if (WindowManager.hasWindowExtensionsEnabled()) { if (WindowManager.HAS_WINDOW_EXTENSIONS_ON_DEVICE) { final String systemExtFrameworkPath = new File(Environment.getSystemExtDirectory(), "framework").getPath(); libs.add(new SharedLibraryInfo( Loading core/tests/coretests/src/android/view/WindowManagerTests.java 0 → 100644 +77 −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; import static com.android.window.flags.Flags.FLAG_ENABLE_WM_EXTENSIONS_FOR_ALL_FLAG; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.junit.Assume.assumeTrue; import android.platform.test.annotations.Presubmit; import android.platform.test.flag.junit.SetFlagsRule; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; /** * Tests for the {@link WindowManager}. * * Build/Install/Run: * atest FrameworksCoreTests:WindowManagerTests */ @RunWith(AndroidJUnit4.class) @SmallTest @Presubmit public class WindowManagerTests { @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); @Test public void testHasWindowExtensionsEnabled_flagDisabled() { mSetFlagsRule.disableFlags(FLAG_ENABLE_WM_EXTENSIONS_FOR_ALL_FLAG); // Before FLAG_ENABLE_WM_EXTENSIONS_FOR_ALL_FLAG, Extensions are always bundled with AE. assertEquals(isActivityEmbeddingEnableForAll(), WindowManager.hasWindowExtensionsEnabled()); } @Test public void testHasWindowExtensionsEnabled_flagEnabled() { mSetFlagsRule.enableFlags(FLAG_ENABLE_WM_EXTENSIONS_FOR_ALL_FLAG); // Extensions should be enabled on all devices. assertTrue(WindowManager.hasWindowExtensionsEnabled()); } @Test public void testActivityEmbeddingAvailability() { assumeTrue(isActivityEmbeddingEnableForAll()); // AE can only be enabled when extensions is enabled. assertTrue(WindowManager.hasWindowExtensionsEnabled()); } private static boolean isActivityEmbeddingEnableForAll() { return !WindowManager.ACTIVITY_EMBEDDING_GUARD_WITH_ANDROID_15; } } libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsImpl.java +63 −26 Original line number Diff line number Diff line Loading @@ -16,15 +16,19 @@ package androidx.window.extensions; import android.app.ActivityTaskManager; import static android.view.WindowManager.ACTIVITY_EMBEDDING_GUARD_WITH_ANDROID_15; import static android.view.WindowManager.ENABLE_ACTIVITY_EMBEDDING_FOR_ANDROID_15; import android.app.ActivityThread; import android.app.Application; import android.app.compat.CompatChanges; import android.content.Context; import android.hardware.devicestate.DeviceStateManager; import android.util.Log; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import androidx.window.common.DeviceStateManagerFoldingFeatureProducer; import androidx.window.common.RawFoldingFeatureProducer; import androidx.window.extensions.area.WindowAreaComponent; Loading @@ -38,25 +42,38 @@ import java.util.Objects; /** * The reference implementation of {@link WindowExtensions} that implements the initial API version. * The reference implementation of {@link WindowExtensions} that implements the latest WindowManager * Extensions APIs. */ public class WindowExtensionsImpl implements WindowExtensions { class WindowExtensionsImpl implements WindowExtensions { private static final String TAG = "WindowExtensionsImpl"; /** * The min version of the WM Extensions that must be supported in the current platform version. */ @VisibleForTesting static final int EXTENSIONS_VERSION_CURRENT_PLATFORM = 5; private final Object mLock = new Object(); private volatile DeviceStateManagerFoldingFeatureProducer mFoldingFeatureProducer; private volatile WindowLayoutComponentImpl mWindowLayoutComponent; private volatile SplitController mSplitController; private volatile WindowAreaComponent mWindowAreaComponent; public WindowExtensionsImpl() { Log.i(TAG, "Initializing Window Extensions."); private final int mVersion = EXTENSIONS_VERSION_CURRENT_PLATFORM; private final boolean mIsActivityEmbeddingEnabled; WindowExtensionsImpl() { mIsActivityEmbeddingEnabled = isActivityEmbeddingEnabled(); Log.i(TAG, "Initializing Window Extensions, vendor API level=" + mVersion + ", activity embedding enabled=" + mIsActivityEmbeddingEnabled); } // TODO(b/241126279) Introduce constants to better version functionality @Override public int getVendorApiLevel() { return 5; return mVersion; } @NonNull Loading @@ -74,8 +91,8 @@ public class WindowExtensionsImpl implements WindowExtensions { if (mFoldingFeatureProducer == null) { synchronized (mLock) { if (mFoldingFeatureProducer == null) { Context context = getApplication(); RawFoldingFeatureProducer foldingFeatureProducer = final Context context = getApplication(); final RawFoldingFeatureProducer foldingFeatureProducer = new RawFoldingFeatureProducer(context); mFoldingFeatureProducer = new DeviceStateManagerFoldingFeatureProducer(context, Loading @@ -91,8 +108,8 @@ public class WindowExtensionsImpl implements WindowExtensions { if (mWindowLayoutComponent == null) { synchronized (mLock) { if (mWindowLayoutComponent == null) { Context context = getApplication(); DeviceStateManagerFoldingFeatureProducer producer = final Context context = getApplication(); final DeviceStateManagerFoldingFeatureProducer producer = getFoldingFeatureProducer(); mWindowLayoutComponent = new WindowLayoutComponentImpl(context, producer); } Loading @@ -102,29 +119,35 @@ public class WindowExtensionsImpl implements WindowExtensions { } /** * Returns a reference implementation of {@link WindowLayoutComponent} if available, * {@code null} otherwise. The implementation must match the API level reported in * {@link WindowExtensions#getWindowLayoutComponent()}. * Returns a reference implementation of the latest {@link WindowLayoutComponent}. * * The implementation must match the API level reported in * {@link WindowExtensions#getVendorApiLevel()}. * * @return {@link WindowLayoutComponent} OEM implementation */ @NonNull @Override public WindowLayoutComponent getWindowLayoutComponent() { return getWindowLayoutComponentImpl(); } /** * Returns a reference implementation of {@link ActivityEmbeddingComponent} if available, * {@code null} otherwise. The implementation must match the API level reported in * {@link WindowExtensions#getWindowLayoutComponent()}. * Returns a reference implementation of the latest {@link ActivityEmbeddingComponent} if the * device supports this feature, {@code null} otherwise. * * The implementation must match the API level reported in * {@link WindowExtensions#getVendorApiLevel()}. * * @return {@link ActivityEmbeddingComponent} OEM implementation. */ @Nullable @Override public ActivityEmbeddingComponent getActivityEmbeddingComponent() { if (mSplitController == null) { if (!ActivityTaskManager.supportsMultiWindow(getApplication())) { // Disable AE for device that doesn't support multi window. if (!mIsActivityEmbeddingEnabled) { return null; } if (mSplitController == null) { synchronized (mLock) { if (mSplitController == null) { mSplitController = new SplitController( Loading @@ -138,21 +161,35 @@ public class WindowExtensionsImpl implements WindowExtensions { } /** * Returns a reference implementation of {@link WindowAreaComponent} if available, * {@code null} otherwise. The implementation must match the API level reported in * {@link WindowExtensions#getWindowAreaComponent()}. * Returns a reference implementation of the latest {@link WindowAreaComponent} * * The implementation must match the API level reported in * {@link WindowExtensions#getVendorApiLevel()}. * * @return {@link WindowAreaComponent} OEM implementation. */ @Nullable @Override public WindowAreaComponent getWindowAreaComponent() { if (mWindowAreaComponent == null) { synchronized (mLock) { if (mWindowAreaComponent == null) { Context context = ActivityThread.currentApplication(); mWindowAreaComponent = new WindowAreaComponentImpl(context); final Context context = getApplication(); mWindowAreaComponent = new WindowAreaComponentImpl(context); } } } return mWindowAreaComponent; } @VisibleForTesting static boolean isActivityEmbeddingEnabled() { if (!ACTIVITY_EMBEDDING_GUARD_WITH_ANDROID_15) { // Device enables it for all apps without targetSDK check. // This must be true for all large screen devices. return true; } // Use compat framework to guard the feature with targetSDK 15. return CompatChanges.isChangeEnabled(ENABLE_ACTIVITY_EMBEDDING_FOR_ANDROID_15); } } libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsProvider.java +46 −2 Original line number Diff line number Diff line Loading @@ -16,14 +16,20 @@ package androidx.window.extensions; import android.annotation.NonNull; import android.view.WindowManager; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.window.extensions.area.WindowAreaComponent; import androidx.window.extensions.embedding.ActivityEmbeddingComponent; import androidx.window.extensions.layout.WindowLayoutComponent; /** * Provides the OEM implementation of {@link WindowExtensions}. */ public class WindowExtensionsProvider { private static final WindowExtensions sWindowExtensions = new WindowExtensionsImpl(); private static volatile WindowExtensions sWindowExtensions; /** * Returns the OEM implementation of {@link WindowExtensions}. This method is implemented in Loading @@ -33,6 +39,44 @@ public class WindowExtensionsProvider { */ @NonNull public static WindowExtensions getWindowExtensions() { if (sWindowExtensions == null) { synchronized (WindowExtensionsProvider.class) { if (sWindowExtensions == null) { sWindowExtensions = WindowManager.hasWindowExtensionsEnabled() ? new WindowExtensionsImpl() : new DisabledWindowExtensions(); } } } return sWindowExtensions; } /** * The stub version to return when the WindowManager Extensions is disabled * @see WindowManager#hasWindowExtensionsEnabled */ private static class DisabledWindowExtensions implements WindowExtensions { @Override public int getVendorApiLevel() { return 0; } @Nullable @Override public WindowLayoutComponent getWindowLayoutComponent() { return null; } @Nullable @Override public ActivityEmbeddingComponent getActivityEmbeddingComponent() { return null; } @Nullable @Override public WindowAreaComponent getWindowAreaComponent() { return null; } } } Loading
core/java/android/view/WindowManager.java +57 −5 Original line number Diff line number Diff line Loading @@ -93,8 +93,12 @@ import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.TestApi; import android.app.ActivityTaskManager; import android.app.ActivityThread; import android.app.KeyguardManager; import android.app.Presentation; import android.compat.annotation.ChangeId; import android.compat.annotation.EnabledSince; import android.compat.annotation.UnsupportedAppUsage; import android.content.ClipData; import android.content.ComponentName; Loading Loading @@ -1416,23 +1420,71 @@ public interface WindowManager extends ViewManager { public static final String PARCEL_KEY_SHORTCUTS_ARRAY = "shortcuts_array"; /** * Whether the device supports the WindowManager Extensions. * OEMs can enable this by having their device config to inherit window_extensions.mk, such as: * Whether the WindowManager Extensions - Activity Embedding feature should be guarded by * the app's target SDK on Android 15. * * WindowManager Extensions are only required for foldable and large screen before Android 15, * so we want to guard the Activity Embedding feature since it can have app compat impact on * devices with a compact size display. * * <p>If {@code true}, the feature is only enabled if the app's target SDK is Android 15 or * above. * * <p>If {@code false}, the feature is enabled for all apps. * * <p>The default value is {@code true}. OEMs can set to {@code false} by having their device * config to inherit window_extensions.mk. This is also required for large screen devices. * <pre> * $(call inherit-product, $(SRC_TARGET_DIR)/product/window_extensions.mk) * </pre> * * @hide */ boolean ACTIVITY_EMBEDDING_GUARD_WITH_ANDROID_15 = SystemProperties.getBoolean( "persist.wm.extensions.activity_embedding_guard_with_android_15", true); /** * For devices with {@link #ACTIVITY_EMBEDDING_GUARD_WITH_ANDROID_15} as {@code true}, * the Activity Embedding feature is enabled if the app's target SDK is Android 15+. * * @see #ACTIVITY_EMBEDDING_GUARD_WITH_ANDROID_15 * @hide */ @ChangeId @EnabledSince(targetSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM) long ENABLE_ACTIVITY_EMBEDDING_FOR_ANDROID_15 = 306666082L; /** * Whether the device contains the WindowManager Extensions shared library. * This is enabled for all devices through window_extensions_base.mk, but can be dropped if the * device doesn't support multi window. * * <p>Note: Large screen devices must also inherit window_extensions.mk to enable the Activity * Embedding feature by default for all apps. * * @see #ACTIVITY_EMBEDDING_GUARD_WITH_ANDROID_15 * @hide */ boolean WINDOW_EXTENSIONS_ENABLED = boolean HAS_WINDOW_EXTENSIONS_ON_DEVICE = SystemProperties.getBoolean("persist.wm.extensions.enabled", false); /** * @see #WINDOW_EXTENSIONS_ENABLED * Whether the WindowManager Extensions are enabled. * If {@code false}, the WM Jetpack will report most of its features as disabled. * @see #HAS_WINDOW_EXTENSIONS_ON_DEVICE * @hide */ @TestApi static boolean hasWindowExtensionsEnabled() { return WINDOW_EXTENSIONS_ENABLED; return HAS_WINDOW_EXTENSIONS_ON_DEVICE && ActivityTaskManager.supportsMultiWindow(ActivityThread.currentApplication()) // Since enableWmExtensionsForAllFlag, HAS_WINDOW_EXTENSIONS_ON_DEVICE is now true // on all devices by default as a build file property. // Until finishing flag ramp up, only return true when // ACTIVITY_EMBEDDING_GUARD_WITH_ANDROID_15 is false, which is set per device by // OEMs. && (Flags.enableWmExtensionsForAllFlag() || !ACTIVITY_EMBEDDING_GUARD_WITH_ANDROID_15); } /** Loading
core/java/com/android/internal/os/ZygoteInit.java +1 −1 Original line number Diff line number Diff line Loading @@ -400,7 +400,7 @@ public class ZygoteInit { // WindowManager Extensions is an optional shared library that is required for WindowManager // Jetpack to fully function. Since it is a widely used library, preload it to improve apps // startup performance. if (WindowManager.hasWindowExtensionsEnabled()) { if (WindowManager.HAS_WINDOW_EXTENSIONS_ON_DEVICE) { final String systemExtFrameworkPath = new File(Environment.getSystemExtDirectory(), "framework").getPath(); libs.add(new SharedLibraryInfo( Loading
core/tests/coretests/src/android/view/WindowManagerTests.java 0 → 100644 +77 −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; import static com.android.window.flags.Flags.FLAG_ENABLE_WM_EXTENSIONS_FOR_ALL_FLAG; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.junit.Assume.assumeTrue; import android.platform.test.annotations.Presubmit; import android.platform.test.flag.junit.SetFlagsRule; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; /** * Tests for the {@link WindowManager}. * * Build/Install/Run: * atest FrameworksCoreTests:WindowManagerTests */ @RunWith(AndroidJUnit4.class) @SmallTest @Presubmit public class WindowManagerTests { @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); @Test public void testHasWindowExtensionsEnabled_flagDisabled() { mSetFlagsRule.disableFlags(FLAG_ENABLE_WM_EXTENSIONS_FOR_ALL_FLAG); // Before FLAG_ENABLE_WM_EXTENSIONS_FOR_ALL_FLAG, Extensions are always bundled with AE. assertEquals(isActivityEmbeddingEnableForAll(), WindowManager.hasWindowExtensionsEnabled()); } @Test public void testHasWindowExtensionsEnabled_flagEnabled() { mSetFlagsRule.enableFlags(FLAG_ENABLE_WM_EXTENSIONS_FOR_ALL_FLAG); // Extensions should be enabled on all devices. assertTrue(WindowManager.hasWindowExtensionsEnabled()); } @Test public void testActivityEmbeddingAvailability() { assumeTrue(isActivityEmbeddingEnableForAll()); // AE can only be enabled when extensions is enabled. assertTrue(WindowManager.hasWindowExtensionsEnabled()); } private static boolean isActivityEmbeddingEnableForAll() { return !WindowManager.ACTIVITY_EMBEDDING_GUARD_WITH_ANDROID_15; } }
libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsImpl.java +63 −26 Original line number Diff line number Diff line Loading @@ -16,15 +16,19 @@ package androidx.window.extensions; import android.app.ActivityTaskManager; import static android.view.WindowManager.ACTIVITY_EMBEDDING_GUARD_WITH_ANDROID_15; import static android.view.WindowManager.ENABLE_ACTIVITY_EMBEDDING_FOR_ANDROID_15; import android.app.ActivityThread; import android.app.Application; import android.app.compat.CompatChanges; import android.content.Context; import android.hardware.devicestate.DeviceStateManager; import android.util.Log; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import androidx.window.common.DeviceStateManagerFoldingFeatureProducer; import androidx.window.common.RawFoldingFeatureProducer; import androidx.window.extensions.area.WindowAreaComponent; Loading @@ -38,25 +42,38 @@ import java.util.Objects; /** * The reference implementation of {@link WindowExtensions} that implements the initial API version. * The reference implementation of {@link WindowExtensions} that implements the latest WindowManager * Extensions APIs. */ public class WindowExtensionsImpl implements WindowExtensions { class WindowExtensionsImpl implements WindowExtensions { private static final String TAG = "WindowExtensionsImpl"; /** * The min version of the WM Extensions that must be supported in the current platform version. */ @VisibleForTesting static final int EXTENSIONS_VERSION_CURRENT_PLATFORM = 5; private final Object mLock = new Object(); private volatile DeviceStateManagerFoldingFeatureProducer mFoldingFeatureProducer; private volatile WindowLayoutComponentImpl mWindowLayoutComponent; private volatile SplitController mSplitController; private volatile WindowAreaComponent mWindowAreaComponent; public WindowExtensionsImpl() { Log.i(TAG, "Initializing Window Extensions."); private final int mVersion = EXTENSIONS_VERSION_CURRENT_PLATFORM; private final boolean mIsActivityEmbeddingEnabled; WindowExtensionsImpl() { mIsActivityEmbeddingEnabled = isActivityEmbeddingEnabled(); Log.i(TAG, "Initializing Window Extensions, vendor API level=" + mVersion + ", activity embedding enabled=" + mIsActivityEmbeddingEnabled); } // TODO(b/241126279) Introduce constants to better version functionality @Override public int getVendorApiLevel() { return 5; return mVersion; } @NonNull Loading @@ -74,8 +91,8 @@ public class WindowExtensionsImpl implements WindowExtensions { if (mFoldingFeatureProducer == null) { synchronized (mLock) { if (mFoldingFeatureProducer == null) { Context context = getApplication(); RawFoldingFeatureProducer foldingFeatureProducer = final Context context = getApplication(); final RawFoldingFeatureProducer foldingFeatureProducer = new RawFoldingFeatureProducer(context); mFoldingFeatureProducer = new DeviceStateManagerFoldingFeatureProducer(context, Loading @@ -91,8 +108,8 @@ public class WindowExtensionsImpl implements WindowExtensions { if (mWindowLayoutComponent == null) { synchronized (mLock) { if (mWindowLayoutComponent == null) { Context context = getApplication(); DeviceStateManagerFoldingFeatureProducer producer = final Context context = getApplication(); final DeviceStateManagerFoldingFeatureProducer producer = getFoldingFeatureProducer(); mWindowLayoutComponent = new WindowLayoutComponentImpl(context, producer); } Loading @@ -102,29 +119,35 @@ public class WindowExtensionsImpl implements WindowExtensions { } /** * Returns a reference implementation of {@link WindowLayoutComponent} if available, * {@code null} otherwise. The implementation must match the API level reported in * {@link WindowExtensions#getWindowLayoutComponent()}. * Returns a reference implementation of the latest {@link WindowLayoutComponent}. * * The implementation must match the API level reported in * {@link WindowExtensions#getVendorApiLevel()}. * * @return {@link WindowLayoutComponent} OEM implementation */ @NonNull @Override public WindowLayoutComponent getWindowLayoutComponent() { return getWindowLayoutComponentImpl(); } /** * Returns a reference implementation of {@link ActivityEmbeddingComponent} if available, * {@code null} otherwise. The implementation must match the API level reported in * {@link WindowExtensions#getWindowLayoutComponent()}. * Returns a reference implementation of the latest {@link ActivityEmbeddingComponent} if the * device supports this feature, {@code null} otherwise. * * The implementation must match the API level reported in * {@link WindowExtensions#getVendorApiLevel()}. * * @return {@link ActivityEmbeddingComponent} OEM implementation. */ @Nullable @Override public ActivityEmbeddingComponent getActivityEmbeddingComponent() { if (mSplitController == null) { if (!ActivityTaskManager.supportsMultiWindow(getApplication())) { // Disable AE for device that doesn't support multi window. if (!mIsActivityEmbeddingEnabled) { return null; } if (mSplitController == null) { synchronized (mLock) { if (mSplitController == null) { mSplitController = new SplitController( Loading @@ -138,21 +161,35 @@ public class WindowExtensionsImpl implements WindowExtensions { } /** * Returns a reference implementation of {@link WindowAreaComponent} if available, * {@code null} otherwise. The implementation must match the API level reported in * {@link WindowExtensions#getWindowAreaComponent()}. * Returns a reference implementation of the latest {@link WindowAreaComponent} * * The implementation must match the API level reported in * {@link WindowExtensions#getVendorApiLevel()}. * * @return {@link WindowAreaComponent} OEM implementation. */ @Nullable @Override public WindowAreaComponent getWindowAreaComponent() { if (mWindowAreaComponent == null) { synchronized (mLock) { if (mWindowAreaComponent == null) { Context context = ActivityThread.currentApplication(); mWindowAreaComponent = new WindowAreaComponentImpl(context); final Context context = getApplication(); mWindowAreaComponent = new WindowAreaComponentImpl(context); } } } return mWindowAreaComponent; } @VisibleForTesting static boolean isActivityEmbeddingEnabled() { if (!ACTIVITY_EMBEDDING_GUARD_WITH_ANDROID_15) { // Device enables it for all apps without targetSDK check. // This must be true for all large screen devices. return true; } // Use compat framework to guard the feature with targetSDK 15. return CompatChanges.isChangeEnabled(ENABLE_ACTIVITY_EMBEDDING_FOR_ANDROID_15); } }
libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsProvider.java +46 −2 Original line number Diff line number Diff line Loading @@ -16,14 +16,20 @@ package androidx.window.extensions; import android.annotation.NonNull; import android.view.WindowManager; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.window.extensions.area.WindowAreaComponent; import androidx.window.extensions.embedding.ActivityEmbeddingComponent; import androidx.window.extensions.layout.WindowLayoutComponent; /** * Provides the OEM implementation of {@link WindowExtensions}. */ public class WindowExtensionsProvider { private static final WindowExtensions sWindowExtensions = new WindowExtensionsImpl(); private static volatile WindowExtensions sWindowExtensions; /** * Returns the OEM implementation of {@link WindowExtensions}. This method is implemented in Loading @@ -33,6 +39,44 @@ public class WindowExtensionsProvider { */ @NonNull public static WindowExtensions getWindowExtensions() { if (sWindowExtensions == null) { synchronized (WindowExtensionsProvider.class) { if (sWindowExtensions == null) { sWindowExtensions = WindowManager.hasWindowExtensionsEnabled() ? new WindowExtensionsImpl() : new DisabledWindowExtensions(); } } } return sWindowExtensions; } /** * The stub version to return when the WindowManager Extensions is disabled * @see WindowManager#hasWindowExtensionsEnabled */ private static class DisabledWindowExtensions implements WindowExtensions { @Override public int getVendorApiLevel() { return 0; } @Nullable @Override public WindowLayoutComponent getWindowLayoutComponent() { return null; } @Nullable @Override public ActivityEmbeddingComponent getActivityEmbeddingComponent() { return null; } @Nullable @Override public WindowAreaComponent getWindowAreaComponent() { return null; } } }