summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Chris Li <lihongyu@google.com> 2024-03-16 07:59:04 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2024-03-16 07:59:04 +0000
commit1ff72183aa24333f210f1aaba80b61b5ca828356 (patch)
treec349223f1bc568807ece7ecdc91e45cbd156d35d
parent2040daa663051428b19eadf912d8be2b19ee23e7 (diff)
parent8128127f35b5b7ae4b776cfeda518d5c7833a11d (diff)
Merge "Reland WM Extensions for all devices" into main
-rw-r--r--core/java/android/view/WindowManager.java62
-rw-r--r--core/java/com/android/internal/os/ZygoteInit.java2
-rw-r--r--core/tests/coretests/src/android/view/WindowManagerTests.java77
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsImpl.java89
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsProvider.java48
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java6
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/sidecar/SidecarProvider.java27
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/sidecar/StubSidecar.java15
-rw-r--r--libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/WindowExtensionsTest.java57
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java37
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.