summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Vladimir Komsiyski <vladokom@google.com> 2023-08-26 14:13:57 +0200
committer Vladimir Komsiyski <vladokom@google.com> 2023-09-21 09:29:28 +0200
commit71f58eb5334089fc65e4a0dce18bc5ce1e703323 (patch)
tree3c3b0dcd3b81535c6566d090ab635137f8dbbcab
parent6182bc4ad4415c9a2cc018ec8baae9ec37ba3a67 (diff)
VDM API for specifying custom home component.
That component is respected whenever a virtual display is created by the device and that display supports showing home activities. Using `VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS` for now and adding a TODO to reference whatever API lands for creating displays with home support. Test: atest VirtualDeviceHomeTest Fix: 297168328 Change-Id: Iced6d176fac39b7cdf375c40de1898c9090a79a3
-rw-r--r--core/api/system-current.txt2
-rw-r--r--core/java/android/companion/virtual/VirtualDeviceParams.java40
-rw-r--r--core/java/android/companion/virtual/flags.aconfig7
-rw-r--r--core/java/android/window/DisplayWindowPolicyController.java6
-rw-r--r--services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java14
-rw-r--r--services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java5
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java10
-rw-r--r--services/core/java/com/android/server/wm/DisplayWindowPolicyControllerHelper.java12
-rw-r--r--services/core/java/com/android/server/wm/RootWindowContainer.java24
-rw-r--r--services/tests/servicestests/src/com/android/server/companion/virtual/audio/VirtualAudioControllerTest.java3
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayWindowPolicyControllerTests.java5
11 files changed, 122 insertions, 6 deletions
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 5c48b21ad35e..fc2063e9e8a5 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -3232,6 +3232,7 @@ package android.companion.virtual {
method public int getDefaultActivityPolicy();
method public int getDefaultNavigationPolicy();
method public int getDevicePolicy(int);
+ method @FlaggedApi(Flags.FLAG_VDM_CUSTOM_HOME) @Nullable public android.content.ComponentName getHomeComponent();
method public int getLockState();
method @Nullable public String getName();
method @NonNull public java.util.Set<android.os.UserHandle> getUsersWithMatchingAccounts();
@@ -3263,6 +3264,7 @@ package android.companion.virtual {
method @NonNull public android.companion.virtual.VirtualDeviceParams.Builder setBlockedActivities(@NonNull java.util.Set<android.content.ComponentName>);
method @NonNull public android.companion.virtual.VirtualDeviceParams.Builder setBlockedCrossTaskNavigations(@NonNull java.util.Set<android.content.ComponentName>);
method @NonNull public android.companion.virtual.VirtualDeviceParams.Builder setDevicePolicy(int, int);
+ method @FlaggedApi(Flags.FLAG_VDM_CUSTOM_HOME) @NonNull public android.companion.virtual.VirtualDeviceParams.Builder setHomeComponent(@Nullable android.content.ComponentName);
method @NonNull @RequiresPermission(value=android.Manifest.permission.ADD_ALWAYS_UNLOCKED_DISPLAY, conditional=true) public android.companion.virtual.VirtualDeviceParams.Builder setLockState(int);
method @NonNull public android.companion.virtual.VirtualDeviceParams.Builder setName(@NonNull String);
method @NonNull public android.companion.virtual.VirtualDeviceParams.Builder setUsersWithMatchingAccounts(@NonNull java.util.Set<android.os.UserHandle>);
diff --git a/core/java/android/companion/virtual/VirtualDeviceParams.java b/core/java/android/companion/virtual/VirtualDeviceParams.java
index b4c740ec5599..0fa78c88c863 100644
--- a/core/java/android/companion/virtual/VirtualDeviceParams.java
+++ b/core/java/android/companion/virtual/VirtualDeviceParams.java
@@ -229,6 +229,7 @@ public final class VirtualDeviceParams implements Parcelable {
@Nullable private final String mName;
// Mapping of @PolicyType to @DevicePolicy
@NonNull private final SparseIntArray mDevicePolicies;
+ @Nullable private final ComponentName mHomeComponent;
@NonNull private final List<VirtualSensorConfig> mVirtualSensorConfigs;
@Nullable private final IVirtualSensorCallback mVirtualSensorCallback;
private final int mAudioPlaybackSessionId;
@@ -243,6 +244,7 @@ public final class VirtualDeviceParams implements Parcelable {
@NonNull Set<ComponentName> activityPolicyExemptions,
@Nullable String name,
@NonNull SparseIntArray devicePolicies,
+ @Nullable ComponentName homeComponent,
@NonNull List<VirtualSensorConfig> virtualSensorConfigs,
@Nullable IVirtualSensorCallback virtualSensorCallback,
int audioPlaybackSessionId,
@@ -258,6 +260,7 @@ public final class VirtualDeviceParams implements Parcelable {
new ArraySet<>(Objects.requireNonNull(activityPolicyExemptions));
mName = name;
mDevicePolicies = Objects.requireNonNull(devicePolicies);
+ mHomeComponent = homeComponent;
mVirtualSensorConfigs = Objects.requireNonNull(virtualSensorConfigs);
mVirtualSensorCallback = virtualSensorCallback;
mAudioPlaybackSessionId = audioPlaybackSessionId;
@@ -280,6 +283,7 @@ public final class VirtualDeviceParams implements Parcelable {
IVirtualSensorCallback.Stub.asInterface(parcel.readStrongBinder());
mAudioPlaybackSessionId = parcel.readInt();
mAudioRecordingSessionId = parcel.readInt();
+ mHomeComponent = parcel.readTypedObject(ComponentName.CREATOR);
}
/**
@@ -291,6 +295,19 @@ public final class VirtualDeviceParams implements Parcelable {
}
/**
+ * Returns the custom component used as home on all displays owned by this virtual device that
+ * support home activities.
+ *
+ * @see Builder#setHomeComponent
+ */
+ // TODO(b/297168328): Link to the relevant API for creating displays with home support.
+ @FlaggedApi(Flags.FLAG_VDM_CUSTOM_HOME)
+ @Nullable
+ public ComponentName getHomeComponent() {
+ return mHomeComponent;
+ }
+
+ /**
* Returns the user handles with matching managed accounts on the remote device to which
* this virtual device is streaming.
*
@@ -468,6 +485,7 @@ public final class VirtualDeviceParams implements Parcelable {
mVirtualSensorCallback != null ? mVirtualSensorCallback.asBinder() : null);
dest.writeInt(mAudioPlaybackSessionId);
dest.writeInt(mAudioRecordingSessionId);
+ dest.writeTypedObject(mHomeComponent, flags);
}
@Override
@@ -508,7 +526,7 @@ public final class VirtualDeviceParams implements Parcelable {
int hashCode = Objects.hash(
mLockState, mUsersWithMatchingAccounts, mCrossTaskNavigationExemptions,
mDefaultNavigationPolicy, mActivityPolicyExemptions, mDefaultActivityPolicy, mName,
- mDevicePolicies, mAudioPlaybackSessionId, mAudioRecordingSessionId);
+ mDevicePolicies, mHomeComponent, mAudioPlaybackSessionId, mAudioRecordingSessionId);
for (int i = 0; i < mDevicePolicies.size(); i++) {
hashCode = 31 * hashCode + mDevicePolicies.keyAt(i);
hashCode = 31 * hashCode + mDevicePolicies.valueAt(i);
@@ -528,6 +546,7 @@ public final class VirtualDeviceParams implements Parcelable {
+ " mActivityPolicyExemptions=" + mActivityPolicyExemptions
+ " mName=" + mName
+ " mDevicePolicies=" + mDevicePolicies
+ + " mHomeComponent=" + mHomeComponent
+ " mAudioPlaybackSessionId=" + mAudioPlaybackSessionId
+ " mAudioRecordingSessionId=" + mAudioRecordingSessionId
+ ")";
@@ -588,6 +607,7 @@ public final class VirtualDeviceParams implements Parcelable {
@Nullable private VirtualSensorCallback mVirtualSensorCallback;
@Nullable private Executor mVirtualSensorDirectChannelCallbackExecutor;
@Nullable private VirtualSensorDirectChannelCallback mVirtualSensorDirectChannelCallback;
+ @Nullable private ComponentName mHomeComponent;
private static class VirtualSensorCallbackDelegate extends IVirtualSensorCallback.Stub {
@NonNull
@@ -665,6 +685,23 @@ public final class VirtualDeviceParams implements Parcelable {
}
/**
+ * Specifies a component to be used as home on all displays owned by this virtual device
+ * that support home activities.
+ * *
+ * <p>Note: Only relevant for virtual displays that support home activities.</p>
+ *
+ * @param homeComponent The component name to be used as home. If unset, then the system-
+ * default secondary home activity will be used.
+ */
+ // TODO(b/297168328): Link to the relevant API for creating displays with home support.
+ @FlaggedApi(Flags.FLAG_VDM_CUSTOM_HOME)
+ @NonNull
+ public Builder setHomeComponent(@Nullable ComponentName homeComponent) {
+ mHomeComponent = homeComponent;
+ return this;
+ }
+
+ /**
* Sets the user handles with matching managed accounts on the remote device to which
* this virtual device is streaming. The caller is responsible for verifying the presence
* and legitimacy of a matching managed account on the remote device.
@@ -1031,6 +1068,7 @@ public final class VirtualDeviceParams implements Parcelable {
mActivityPolicyExemptions,
mName,
mDevicePolicies,
+ mHomeComponent,
mVirtualSensorConfigs,
virtualSensorCallbackDelegate,
mAudioPlaybackSessionId,
diff --git a/core/java/android/companion/virtual/flags.aconfig b/core/java/android/companion/virtual/flags.aconfig
index ee36f187b729..3e96c96d8d17 100644
--- a/core/java/android/companion/virtual/flags.aconfig
+++ b/core/java/android/companion/virtual/flags.aconfig
@@ -15,6 +15,13 @@ flag {
}
flag {
+ name: "vdm_custom_home"
+ namespace: "virtual_devices"
+ description: "Enable custom home API"
+ bug: "297168328"
+}
+
+flag {
name: "vdm_public_apis"
namespace: "virtual_devices"
description: "Enable public VDM API for device capabilities"
diff --git a/core/java/android/window/DisplayWindowPolicyController.java b/core/java/android/window/DisplayWindowPolicyController.java
index 2747233a4bf1..8d71a8e998bd 100644
--- a/core/java/android/window/DisplayWindowPolicyController.java
+++ b/core/java/android/window/DisplayWindowPolicyController.java
@@ -109,6 +109,12 @@ public abstract class DisplayWindowPolicyController {
}
/**
+ * @return the custom home component specified for the relevant display, if any.
+ */
+ @Nullable
+ public abstract ComponentName getCustomHomeComponent();
+
+ /**
* Returns {@code true} if all of the given activities can be launched on this virtual display
* in the configuration defined by the rest of the arguments.
*
diff --git a/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java b/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java
index 102c26245dc3..a3ccb168aa4e 100644
--- a/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java
+++ b/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java
@@ -133,6 +133,7 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController
@GuardedBy("mGenericWindowPolicyControllerLock")
private boolean mShowTasksInHostDeviceRecents;
+ @Nullable private final ComponentName mCustomHomeComponent;
/**
* Creates a window policy controller that is generic to the different use cases of virtual
@@ -157,6 +158,10 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController
* @param intentListenerCallback Callback that is called to intercept intents when matching
* passed in filters.
* @param showTasksInHostDeviceRecents whether to show activities in recents on the host device.
+ * @param customHomeComponent The component acting as a home activity on the virtual display. If
+ * {@code null}, then the system-default secondary home activity will be used. This is only
+ * applicable to displays that support home activities, i.e. they're created with the relevant
+ * virtual display flag.
*/
public GenericWindowPolicyController(
int windowFlags,
@@ -172,7 +177,8 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController
@Nullable SecureWindowCallback secureWindowCallback,
@Nullable IntentListenerCallback intentListenerCallback,
@NonNull Set<String> displayCategories,
- boolean showTasksInHostDeviceRecents) {
+ boolean showTasksInHostDeviceRecents,
+ @Nullable ComponentName customHomeComponent) {
super();
mAllowedUsers = allowedUsers;
mActivityLaunchAllowedByDefault = activityLaunchAllowedByDefault;
@@ -187,6 +193,7 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController
mIntentListenerCallback = intentListenerCallback;
mDisplayCategories = displayCategories;
mShowTasksInHostDeviceRecents = showTasksInHostDeviceRecents;
+ mCustomHomeComponent = customHomeComponent;
}
/**
@@ -384,6 +391,11 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController
return false;
}
+ @Override
+ public @Nullable ComponentName getCustomHomeComponent() {
+ return mCustomHomeComponent;
+ }
+
/**
* Returns true if an app with the given UID has an activity running on the virtual display for
* this controller.
diff --git a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
index 3b13410720af..78d55df9e935 100644
--- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
+++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
@@ -905,6 +905,8 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
mParams.getDefaultNavigationPolicy() == NAVIGATION_POLICY_DEFAULT_ALLOWED;
final boolean showTasksInHostDeviceRecents =
getDevicePolicy(POLICY_TYPE_RECENTS) == DEVICE_POLICY_DEFAULT;
+ final ComponentName homeComponent =
+ Flags.vdmCustomHome() ? mParams.getHomeComponent() : null;
final GenericWindowPolicyController gwpc = new GenericWindowPolicyController(
FLAG_SECURE,
@@ -922,7 +924,8 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
this::onSecureWindowShown,
this::shouldInterceptIntent,
displayCategories,
- showTasksInHostDeviceRecents);
+ showTasksInHostDeviceRecents,
+ homeComponent);
gwpc.registerRunningAppsChangedListener(/* listener= */ this);
return gwpc;
}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 4309e72c30d7..ca42400dad26 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -2160,6 +2160,16 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
}
/**
+ * @see DisplayWindowPolicyController#getCustomHomeComponent() ()
+ */
+ @Nullable ComponentName getCustomHomeComponent() {
+ if (!supportsSystemDecorations() || mDwpcHelper == null) {
+ return null;
+ }
+ return mDwpcHelper.getCustomHomeComponent();
+ }
+
+ /**
* Applies the rotation transaction. This must be called after {@link #updateRotationUnchecked}
* (if it returned {@code true}) to actually finish the rotation.
*
diff --git a/services/core/java/com/android/server/wm/DisplayWindowPolicyControllerHelper.java b/services/core/java/com/android/server/wm/DisplayWindowPolicyControllerHelper.java
index 6b33746ad3c4..e0d69b063573 100644
--- a/services/core/java/com/android/server/wm/DisplayWindowPolicyControllerHelper.java
+++ b/services/core/java/com/android/server/wm/DisplayWindowPolicyControllerHelper.java
@@ -19,6 +19,7 @@ package com.android.server.wm;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.WindowConfiguration;
+import android.content.ComponentName;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.os.Process;
@@ -200,6 +201,17 @@ class DisplayWindowPolicyControllerHelper {
return mDisplayWindowPolicyController.isEnteringPipAllowed(uid);
}
+ /**
+ * @see DisplayWindowPolicyController#getCustomHomeComponent
+ */
+ @Nullable
+ public ComponentName getCustomHomeComponent() {
+ if (mDisplayWindowPolicyController == null) {
+ return null;
+ }
+ return mDisplayWindowPolicyController.getCustomHomeComponent();
+ }
+
void dump(String prefix, PrintWriter pw) {
if (mDisplayWindowPolicyController != null) {
pw.println();
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 2fdfec04b895..2a3391807a2c 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -1513,10 +1513,30 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
throw new IllegalArgumentException(
"resolveSecondaryHomeActivity: Should not be default task container");
}
- // Resolve activities in the same package as currently selected primary home activity.
+
Intent homeIntent = mService.getHomeIntent();
ActivityInfo aInfo = resolveHomeActivity(userId, homeIntent);
- if (aInfo != null) {
+ boolean lookForSecondaryHomeActivityInPrimaryHomePackage = aInfo != null;
+
+ if (android.companion.virtual.flags.Flags.vdmCustomHome()) {
+ // Resolve the externally set home activity for this display, if any. If it is unset or
+ // we fail to resolve it, fallback to the default secondary home activity.
+ final ComponentName customHomeComponent =
+ taskDisplayArea.getDisplayContent() != null
+ ? taskDisplayArea.getDisplayContent().getCustomHomeComponent()
+ : null;
+ if (customHomeComponent != null) {
+ homeIntent.setComponent(customHomeComponent);
+ ActivityInfo customHomeActivityInfo = resolveHomeActivity(userId, homeIntent);
+ if (customHomeActivityInfo != null) {
+ aInfo = customHomeActivityInfo;
+ lookForSecondaryHomeActivityInPrimaryHomePackage = false;
+ }
+ }
+ }
+
+ if (lookForSecondaryHomeActivityInPrimaryHomePackage) {
+ // Resolve activities in the same package as currently selected primary home activity.
if (ResolverActivity.class.getName().equals(aInfo.name)) {
// Always fallback to secondary home component if default home is not set.
aInfo = null;
diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/audio/VirtualAudioControllerTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/audio/VirtualAudioControllerTest.java
index c40ad2840501..1c48b8aa79f9 100644
--- a/services/tests/servicestests/src/com/android/server/companion/virtual/audio/VirtualAudioControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/companion/virtual/audio/VirtualAudioControllerTest.java
@@ -88,7 +88,8 @@ public class VirtualAudioControllerTest {
/* secureWindowCallback= */ null,
/* intentListenerCallback= */ null,
/* displayCategories= */ new ArraySet<>(),
- /* showTasksInHostDeviceRecents= */ true);
+ /* showTasksInHostDeviceRecents= */ true,
+ /* customHomeComponent= */ null);
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowPolicyControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowPolicyControllerTests.java
index 30a89412d946..cf620fe605c6 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowPolicyControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowPolicyControllerTests.java
@@ -275,5 +275,10 @@ public class DisplayWindowPolicyControllerTests extends WindowTestsBase {
public boolean isEnteringPipAllowed(int uid) {
return true;
}
+
+ @Override
+ public ComponentName getCustomHomeComponent() {
+ return null;
+ }
}
}