diff options
| author | 2024-03-16 07:59:04 +0000 | |
|---|---|---|
| committer | 2024-03-16 07:59:04 +0000 | |
| commit | 1ff72183aa24333f210f1aaba80b61b5ca828356 (patch) | |
| tree | c349223f1bc568807ece7ecdc91e45cbd156d35d | |
| parent | 2040daa663051428b19eadf912d8be2b19ee23e7 (diff) | |
| parent | 8128127f35b5b7ae4b776cfeda518d5c7833a11d (diff) | |
Merge "Reland WM Extensions for all devices" into main
10 files changed, 360 insertions, 60 deletions
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java index 71f1c34388c5..86fc6f48a145 100644 --- a/core/java/android/view/WindowManager.java +++ b/core/java/android/view/WindowManager.java @@ -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; @@ -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); } /** diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java index 7af196513cae..5297006880d7 100644 --- a/core/java/com/android/internal/os/ZygoteInit.java +++ b/core/java/com/android/internal/os/ZygoteInit.java @@ -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( diff --git a/core/tests/coretests/src/android/view/WindowManagerTests.java b/core/tests/coretests/src/android/view/WindowManagerTests.java new file mode 100644 index 000000000000..c5a9d480771e --- /dev/null +++ b/core/tests/coretests/src/android/view/WindowManagerTests.java @@ -0,0 +1,77 @@ +/* + * 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; + } +} diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsImpl.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsImpl.java index 6714263ad952..97562783882c 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsImpl.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsImpl.java @@ -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; @@ -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 @@ -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, @@ -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); } @@ -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 (!mIsActivityEmbeddingEnabled) { + return null; + } if (mSplitController == null) { - if (!ActivityTaskManager.supportsMultiWindow(getApplication())) { - // Disable AE for device that doesn't support multi window. - return null; - } synchronized (mLock) { if (mSplitController == null) { mSplitController = new SplitController( @@ -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); + } } diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsProvider.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsProvider.java index f9e1f077cffc..5d4c7cbe60e4 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsProvider.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsProvider.java @@ -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 @@ -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; + } + } } diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java index 1abda4287800..0cc4b1f367d8 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java @@ -88,7 +88,7 @@ import androidx.annotation.Nullable; import androidx.window.common.CommonFoldingFeature; import androidx.window.common.DeviceStateManagerFoldingFeatureProducer; import androidx.window.common.EmptyLifecycleCallbacksAdapter; -import androidx.window.extensions.WindowExtensionsImpl; +import androidx.window.extensions.WindowExtensions; import androidx.window.extensions.core.util.function.Consumer; import androidx.window.extensions.core.util.function.Function; import androidx.window.extensions.core.util.function.Predicate; @@ -410,7 +410,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen * Registers the split organizer callback to notify about changes to active splits. * * @deprecated Use {@link #setSplitInfoCallback(Consumer)} starting with - * {@link WindowExtensionsImpl#getVendorApiLevel()} 2. + * {@link WindowExtensions#getVendorApiLevel()} 2. */ @Deprecated @Override @@ -423,7 +423,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen /** * Registers the split organizer callback to notify about changes to active splits. * - * @since {@link WindowExtensionsImpl#getVendorApiLevel()} 2 + * @since {@link WindowExtensions#getVendorApiLevel()} 2 */ @Override public void setSplitInfoCallback(Consumer<List<SplitInfo>> callback) { diff --git a/libs/WindowManager/Jetpack/src/androidx/window/sidecar/SidecarProvider.java b/libs/WindowManager/Jetpack/src/androidx/window/sidecar/SidecarProvider.java index 62959b7b95e9..686a31b6be04 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/sidecar/SidecarProvider.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/sidecar/SidecarProvider.java @@ -17,25 +17,48 @@ package androidx.window.sidecar; import android.content.Context; +import android.view.WindowManager; + +import androidx.annotation.Nullable; /** * Provider class that will instantiate the library implementation. It must be included in the * vendor library, and the vendor implementation must match the signature of this class. */ public class SidecarProvider { + + private static volatile Boolean sIsWindowExtensionsEnabled; + /** * Provide a simple implementation of {@link SidecarInterface} that can be replaced by * an OEM by overriding this method. */ + @Nullable public static SidecarInterface getSidecarImpl(Context context) { - return new SampleSidecarImpl(context.getApplicationContext()); + return isWindowExtensionsEnabled() + ? new SampleSidecarImpl(context.getApplicationContext()) + : null; } /** * The support library will use this method to check API version compatibility. * @return API version string in MAJOR.MINOR.PATCH-description format. */ + @Nullable public static String getApiVersion() { - return "1.0.0-reference"; + return isWindowExtensionsEnabled() + ? "1.0.0-reference" + : null; + } + + private static boolean isWindowExtensionsEnabled() { + if (sIsWindowExtensionsEnabled == null) { + synchronized (SidecarProvider.class) { + if (sIsWindowExtensionsEnabled == null) { + sIsWindowExtensionsEnabled = WindowManager.hasWindowExtensionsEnabled(); + } + } + } + return sIsWindowExtensionsEnabled; } } diff --git a/libs/WindowManager/Jetpack/src/androidx/window/sidecar/StubSidecar.java b/libs/WindowManager/Jetpack/src/androidx/window/sidecar/StubSidecar.java index b9c808a6569b..46c1f3ba4691 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/sidecar/StubSidecar.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/sidecar/StubSidecar.java @@ -17,6 +17,7 @@ package androidx.window.sidecar; import android.os.IBinder; +import android.util.Log; import androidx.annotation.NonNull; @@ -29,6 +30,8 @@ import java.util.Set; */ abstract class StubSidecar implements SidecarInterface { + private static final String TAG = "WindowManagerSidecar"; + private SidecarCallback mSidecarCallback; final Set<IBinder> mWindowLayoutChangeListenerTokens = new HashSet<>(); private boolean mDeviceStateChangeListenerRegistered; @@ -61,14 +64,22 @@ abstract class StubSidecar implements SidecarInterface { void updateDeviceState(SidecarDeviceState newState) { if (this.mSidecarCallback != null) { - mSidecarCallback.onDeviceStateChanged(newState); + try { + mSidecarCallback.onDeviceStateChanged(newState); + } catch (AbstractMethodError e) { + Log.e(TAG, "App is using an outdated Window Jetpack library", e); + } } } void updateWindowLayout(@NonNull IBinder windowToken, @NonNull SidecarWindowLayoutInfo newLayout) { if (this.mSidecarCallback != null) { - mSidecarCallback.onWindowLayoutChanged(windowToken, newLayout); + try { + mSidecarCallback.onWindowLayoutChanged(windowToken, newLayout); + } catch (AbstractMethodError e) { + Log.e(TAG, "App is using an outdated Window Jetpack library", e); + } } } diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/WindowExtensionsTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/WindowExtensionsTest.java index f471af052bf2..4267749dfa6b 100644 --- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/WindowExtensionsTest.java +++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/WindowExtensionsTest.java @@ -16,12 +16,15 @@ package androidx.window.extensions; -import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; +import static androidx.window.extensions.WindowExtensionsImpl.EXTENSIONS_VERSION_CURRENT_PLATFORM; import static com.google.common.truth.Truth.assertThat; -import android.app.ActivityTaskManager; +import static org.junit.Assume.assumeFalse; +import static org.junit.Assume.assumeTrue; + import android.platform.test.annotations.Presubmit; +import android.view.WindowManager; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; @@ -42,25 +45,61 @@ import org.junit.runner.RunWith; @SmallTest @RunWith(AndroidJUnit4.class) public class WindowExtensionsTest { + private WindowExtensions mExtensions; + private int mVersion; @Before public void setUp() { mExtensions = WindowExtensionsProvider.getWindowExtensions(); + mVersion = mExtensions.getVendorApiLevel(); + } + + @Test + public void testGetVendorApiLevel_extensionsEnabled_matchesCurrentVersion() { + assumeTrue(WindowManager.hasWindowExtensionsEnabled()); + assertThat(mVersion).isEqualTo(EXTENSIONS_VERSION_CURRENT_PLATFORM); } @Test - public void testGetWindowLayoutComponent() { + public void testGetVendorApiLevel_extensionsDisabled_returnsZero() { + assumeFalse(WindowManager.hasWindowExtensionsEnabled()); + assertThat(mVersion).isEqualTo(0); + } + + @Test + public void testGetWindowLayoutComponent_extensionsEnabled_returnsImplementation() { + assumeTrue(WindowManager.hasWindowExtensionsEnabled()); assertThat(mExtensions.getWindowLayoutComponent()).isNotNull(); } @Test - public void testGetActivityEmbeddingComponent() { - if (ActivityTaskManager.supportsMultiWindow(getInstrumentation().getContext())) { - assertThat(mExtensions.getActivityEmbeddingComponent()).isNotNull(); - } else { - assertThat(mExtensions.getActivityEmbeddingComponent()).isNull(); - } + public void testGetWindowLayoutComponent_extensionsDisabled_returnsNull() { + assumeFalse(WindowManager.hasWindowExtensionsEnabled()); + assertThat(mExtensions.getWindowLayoutComponent()).isNull(); + } + @Test + public void testGetActivityEmbeddingComponent_featureDisabled_returnsNull() { + assumeFalse(WindowExtensionsImpl.isActivityEmbeddingEnabled()); + assertThat(mExtensions.getActivityEmbeddingComponent()).isNull(); + } + + @Test + public void testGetActivityEmbeddingComponent_featureEnabled_returnsImplementation() { + assumeTrue(WindowExtensionsImpl.isActivityEmbeddingEnabled()); + assertThat(mExtensions.getActivityEmbeddingComponent()).isNotNull(); + } + + @Test + public void testGetWindowAreaComponent_extensionsEnabled_returnsImplementation() { + assumeTrue(WindowManager.hasWindowExtensionsEnabled()); + assertThat(mExtensions.getWindowAreaComponent()).isNotNull(); + } + + @Test + public void testGetWindowAreaComponent_extensionsDisabled_returnsNull() { + assumeFalse(WindowManager.hasWindowExtensionsEnabled()); + assertThat(mExtensions.getWindowAreaComponent()).isNull(); } @Test diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 6fa6957f2949..23f9743619e3 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -118,6 +118,7 @@ import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; import static android.view.Display.INVALID_DISPLAY; import static android.view.Surface.ROTATION_270; import static android.view.Surface.ROTATION_90; +import static android.view.WindowManager.ACTIVITY_EMBEDDING_GUARD_WITH_ANDROID_15; import static android.view.WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD; import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION; @@ -125,10 +126,12 @@ import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; import static android.view.WindowManager.PROPERTY_ACTIVITY_EMBEDDING_SPLITS_ENABLED; import static android.view.WindowManager.PROPERTY_ALLOW_UNTRUSTED_ACTIVITY_EMBEDDING_STATE_SHARING; +import static android.view.WindowManager.ENABLE_ACTIVITY_EMBEDDING_FOR_ANDROID_15; import static android.view.WindowManager.TRANSIT_CLOSE; import static android.view.WindowManager.TRANSIT_FLAG_OPEN_BEHIND; import static android.view.WindowManager.TRANSIT_OLD_UNSET; import static android.view.WindowManager.TRANSIT_RELAUNCH; +import static android.view.WindowManager.hasWindowExtensionsEnabled; import static android.window.TransitionInfo.FLAGS_IS_OCCLUDED_NO_ANIMATION; import static android.window.TransitionInfo.FLAG_IS_OCCLUDED; import static android.window.TransitionInfo.FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT; @@ -282,6 +285,7 @@ import android.app.WaitResult; import android.app.WindowConfiguration; import android.app.admin.DevicePolicyManager; import android.app.assist.ActivityId; +import android.app.compat.CompatChanges; import android.app.servertransaction.ActivityConfigurationChangeItem; import android.app.servertransaction.ActivityLifecycleItem; import android.app.servertransaction.ActivityRelaunchItem; @@ -2266,16 +2270,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A mActivityRecordInputSink = new ActivityRecordInputSink(this, sourceRecord); - boolean appActivityEmbeddingEnabled = false; - try { - appActivityEmbeddingEnabled = WindowManager.hasWindowExtensionsEnabled() - && mAtmService.mContext.getPackageManager() - .getProperty(PROPERTY_ACTIVITY_EMBEDDING_SPLITS_ENABLED, packageName) - .getBoolean(); - } catch (PackageManager.NameNotFoundException e) { - // No such property name. - } - mAppActivityEmbeddingSplitsEnabled = appActivityEmbeddingEnabled; + mAppActivityEmbeddingSplitsEnabled = isAppActivityEmbeddingSplitsEnabled(); mAllowUntrustedEmbeddingStateSharing = getAllowUntrustedEmbeddingStateSharingProperty(); mOptInOnBackInvoked = WindowOnBackInvokedDispatcher @@ -2294,6 +2289,28 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A mCallerState = new ActivityCallerState(mAtmService); } + private boolean isAppActivityEmbeddingSplitsEnabled() { + if (!hasWindowExtensionsEnabled()) { + // WM Extensions disabled. + return false; + } + if (ACTIVITY_EMBEDDING_GUARD_WITH_ANDROID_15 && !CompatChanges.isChangeEnabled( + ENABLE_ACTIVITY_EMBEDDING_FOR_ANDROID_15, + info.packageName, + UserHandle.getUserHandleForUid(getUid()))) { + // Activity Embedding is guarded with Android 15+, but this app is not qualified. + return false; + } + try { + return mAtmService.mContext.getPackageManager() + .getProperty(PROPERTY_ACTIVITY_EMBEDDING_SPLITS_ENABLED, packageName) + .getBoolean(); + } catch (PackageManager.NameNotFoundException e) { + // No such property name. + return false; + } + } + /** * Generate the task affinity with uid and activity launch mode. For b/35954083, Limit task * affinity to uid to avoid issues associated with sharing affinity across uids. |