Migrate LauncherAppsTests.

Test: btest android.devicepolicy.cts.LauncherAppsTest
Fixes: 231910384
Fixes: 231910553
Fixes: 231910717
Fixes: 231910528
Change-Id: I28a655a28e15dfb31340c74434df44a54cfae327
diff --git a/common/device-side/bedstead/harrier/common/src/main/java/com/android/bedstead/harrier/annotations/parameterized/IncludeRunOnPrimaryUserWithNoDpc.java b/common/device-side/bedstead/harrier/common/src/main/java/com/android/bedstead/harrier/annotations/parameterized/IncludeRunOnPrimaryUserWithNoDpc.java
new file mode 100644
index 0000000..8d89a62
--- /dev/null
+++ b/common/device-side/bedstead/harrier/common/src/main/java/com/android/bedstead/harrier/annotations/parameterized/IncludeRunOnPrimaryUserWithNoDpc.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2021 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 com.android.bedstead.harrier.annotations.parameterized;
+
+import static com.android.bedstead.harrier.annotations.AnnotationRunPrecedence.EARLY;
+
+import com.android.bedstead.harrier.annotations.AnnotationRunPrecedence;
+import com.android.bedstead.harrier.annotations.RequireRunOnPrimaryUser;
+import com.android.bedstead.harrier.annotations.enterprise.EnsureHasNoDpc;
+import com.android.bedstead.harrier.annotations.meta.ParameterizedAnnotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Parameterize a test so that it runs on the primary user and has no device owner or profile
+ * owners.
+ */
+@Target({ElementType.METHOD, ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+@ParameterizedAnnotation
+@RequireRunOnPrimaryUser
+@EnsureHasNoDpc
+public @interface IncludeRunOnPrimaryUserWithNoDpc {
+    /**
+     * Weight sets the order that annotations will be resolved.
+     *
+     * <p>Annotations with a lower weight will be resolved before annotations with a higher weight.
+     *
+     * <p>If there is an order requirement between annotations, ensure that the weight of the
+     * annotation which must be resolved first is lower than the one which must be resolved later.
+     *
+     * <p>Weight can be set to a {@link AnnotationRunPrecedence} constant, or to any {@link int}.
+     */
+    int weight() default EARLY;
+}
diff --git a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/activities/ActivityReference.java b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/activities/ActivityReference.java
index 4915f67..97f77a8 100644
--- a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/activities/ActivityReference.java
+++ b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/activities/ActivityReference.java
@@ -17,9 +17,13 @@
 package com.android.bedstead.nene.activities;
 
 import android.content.ComponentName;
+import android.content.pm.PackageManager;
 
+import com.android.bedstead.nene.TestApis;
+import com.android.bedstead.nene.exceptions.NeneException;
 import com.android.bedstead.nene.packages.ComponentReference;
 import com.android.bedstead.nene.packages.Package;
+import com.android.bedstead.nene.users.UserReference;
 
 /**
  * A representation of an activity on device which may or may not exist.
@@ -37,6 +41,52 @@
         super(component.componentName());
     }
 
+    /**
+     * Is this activity enabled.
+     */
+    public boolean isEnabled(UserReference user) {
+        // This currently uses activity-specific methods - it'd be great to have this at the top
+        // level and work for any component
+        try {
+            return TestApis.context().androidContextAsUser(user)
+                    .getPackageManager()
+                    .getActivityInfo(componentName(), 0)
+                    .enabled;
+        } catch (PackageManager.NameNotFoundException e) {
+            throw new NeneException("Activity does not exist or is not activity " + this, e);
+        }
+    }
+
+    /**
+     * Is this activity enabled.
+     */
+    public boolean isEnabled() {
+        return isEnabled(TestApis.users().instrumented());
+    }
+
+    /**
+     * Is this activity exported.
+     */
+    public boolean isExported(UserReference user) {
+        // This currently uses activity-specific methods - it'd be great to have this at the top
+        // level and work for any component
+        try {
+            return TestApis.context().androidContextAsUser(user)
+                    .getPackageManager()
+                    .getActivityInfo(componentName(), 0)
+                    .exported;
+        } catch (PackageManager.NameNotFoundException e) {
+            throw new NeneException("Activity does not exist or is not activity " + this, e);
+        }
+    }
+
+    /**
+     * Is this activity exported.
+     */
+    public boolean isExported() {
+        return isExported(TestApis.users().instrumented());
+    }
+
     @Override
     public String toString() {
         return "ActivityReference{component=" + super.toString() + "}";
diff --git a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/packages/Package.java b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/packages/Package.java
index 5698da2..59166c5 100644
--- a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/packages/Package.java
+++ b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/packages/Package.java
@@ -30,6 +30,8 @@
 import static android.os.Build.VERSION_CODES.S;
 import static android.os.Process.myUid;
 
+import static com.android.bedstead.nene.permissions.CommonPermissions.CHANGE_COMPONENT_ENABLED_STATE;
+
 import static com.google.common.truth.Truth.assertWithMessage;
 
 import android.annotation.TargetApi;
@@ -849,6 +851,43 @@
         return packageInfo.sharedUserId;
     }
 
+    /**
+     * See {@link PackageManager#setSyntheticAppDetailsActivityEnabled(String, boolean)}.
+     */
+    @Experimental
+    public void setSyntheticAppDetailsActivityEnabled(UserReference user, boolean enabled) {
+        try (PermissionContext p = TestApis.permissions()
+                .withPermission(CHANGE_COMPONENT_ENABLED_STATE)) {
+            TestApis.context().androidContextAsUser(user).getPackageManager()
+                    .setSyntheticAppDetailsActivityEnabled(packageName(), enabled);
+        }
+    }
+
+    /**
+     * See {@link PackageManager#setSyntheticAppDetailsActivityEnabled(String, boolean)}.
+     */
+    @Experimental
+    public void setSyntheticAppDetailsActivityEnabled(boolean enabled) {
+        setSyntheticAppDetailsActivityEnabled(TestApis.users().instrumented(), enabled);
+    }
+
+    /**
+     * See {@link PackageManager#getSyntheticAppDetailsActivityEnabled(String)}.
+     */
+    @Experimental
+    public boolean syntheticAppDetailsActivityEnabled(UserReference user) {
+        return TestApis.context().androidContextAsUser(user).getPackageManager()
+                .getSyntheticAppDetailsActivityEnabled(packageName());
+    }
+
+    /**
+     * See {@link PackageManager#getSyntheticAppDetailsActivityEnabled(String)}.
+     */
+    @Experimental
+    public boolean syntheticAppDetailsActivityEnabled() {
+        return syntheticAppDetailsActivityEnabled(TestApis.users().instrumented());
+    }
+
     private static final class ProcessInfo {
         final String mPackageName;
         final int mPid;
diff --git a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/packages/Packages.java b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/packages/Packages.java
index f6ce364..3d1188a 100644
--- a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/packages/Packages.java
+++ b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/packages/Packages.java
@@ -44,6 +44,7 @@
 import androidx.annotation.RequiresApi;
 
 import com.android.bedstead.nene.TestApis;
+import com.android.bedstead.nene.activities.ActivityReference;
 import com.android.bedstead.nene.annotations.Experimental;
 import com.android.bedstead.nene.exceptions.AdbException;
 import com.android.bedstead.nene.exceptions.AdbParseException;
@@ -536,6 +537,21 @@
     }
 
     /**
+     * Get a reference to a given {@code componentName} activity.
+     *
+     * <p>This does not guarantee that the component exists - nor that it is actually an activity.
+     */
+    @Experimental
+    public ActivityReference activity(ComponentName componentName) {
+        if (componentName == null) {
+            throw new NullPointerException();
+        }
+
+        return new ActivityReference(
+                find(componentName.getPackageName()), componentName.getClassName());
+    }
+
+    /**
      * Get a reference to a given {@code componentName}.
      *
      * <p>This does not guarantee that the component exists.
diff --git a/hostsidetests/devicepolicy/app/LauncherTests/src/com/android/cts/launchertests/LauncherAppsTests.java b/hostsidetests/devicepolicy/app/LauncherTests/src/com/android/cts/launchertests/LauncherAppsTests.java
index d994d21..b7be8d9 100644
--- a/hostsidetests/devicepolicy/app/LauncherTests/src/com/android/cts/launchertests/LauncherAppsTests.java
+++ b/hostsidetests/devicepolicy/app/LauncherTests/src/com/android/cts/launchertests/LauncherAppsTests.java
@@ -254,56 +254,6 @@
     }
 
     @Test
-    public void testHasLauncherActivityAppHasAppDetailsActivityInjected() throws Exception {
-        assumeNotHeadlessSystemUserMode();
-
-        // HasLauncherActivityApp is installed for duration of this test - make sure
-        // it's present on the activity list, has the synthetic activity generated, and it's
-        // enabled and exported
-        disableLauncherActivity();
-        assertActivityInjected(HAS_LAUNCHER_ACTIVITY_APP_PACKAGE);
-    }
-
-    @Test
-    public void testGetSetSyntheticAppDetailsActivityEnabled() throws Exception {
-        assumeNotHeadlessSystemUserMode();
-
-        disableLauncherActivity();
-        assertActivityInjected(HAS_LAUNCHER_ACTIVITY_APP_PACKAGE);
-        PackageManager pm = mContext.getPackageManager();
-        try {
-            pm.setSyntheticAppDetailsActivityEnabled(mContext.getPackageName(), false);
-            fail("Should not able to change current app's app details activity state");
-        } catch (SecurityException e) {
-            // Expected: No permission
-        }
-        try {
-            pm.setSyntheticAppDetailsActivityEnabled(HAS_LAUNCHER_ACTIVITY_APP_PACKAGE, false);
-            fail("Should not able to change other app's app details activity state");
-        } catch (SecurityException e) {
-            // Expected: No permission
-        }
-        mInstrumentation.getUiAutomation().adoptShellPermissionIdentity();
-        try {
-            assertThat(pm.getSyntheticAppDetailsActivityEnabled(HAS_LAUNCHER_ACTIVITY_APP_PACKAGE))
-                    .isTrue();
-            // Disable app details activity and assert if the change is applied
-            pm.setSyntheticAppDetailsActivityEnabled(HAS_LAUNCHER_ACTIVITY_APP_PACKAGE, false);
-            assertThat(pm.getSyntheticAppDetailsActivityEnabled(HAS_LAUNCHER_ACTIVITY_APP_PACKAGE))
-                    .isFalse();
-            assertInjectedActivityNotFound(HAS_LAUNCHER_ACTIVITY_APP_PACKAGE);
-            // Enable app details activity and assert if the change is applied
-            pm.setSyntheticAppDetailsActivityEnabled(HAS_LAUNCHER_ACTIVITY_APP_PACKAGE, true);
-            assertThat(pm.getSyntheticAppDetailsActivityEnabled(HAS_LAUNCHER_ACTIVITY_APP_PACKAGE))
-                    .isTrue();
-            assertActivityInjected(HAS_LAUNCHER_ACTIVITY_APP_PACKAGE);
-        } finally {
-            mInstrumentation.getUiAutomation().dropShellPermissionIdentity();
-        }
-    }
-
-
-    @Test
     public void testProfileOwnerLauncherActivityInjected() throws Exception {
         assertActivityInjected(MANAGED_PROFILE_PKG);
     }
@@ -322,14 +272,7 @@
         assertInjectedActivityNotFound(NO_PERMISSION_APP_PACKAGE);
     }
 
-    @Test
-    public void testDoPoNoTestAppInjectedActivityFound() throws Exception {
-        // HasLauncherActivityApp is installed for duration of this test - make sure
-        // it's NOT present on the activity list For example, DO / PO mode won't show icons.
-        // This test is being called by DeviceOwnerTest.
-        disableLauncherActivity();
-        assertInjectedActivityNotFound(HAS_LAUNCHER_ACTIVITY_APP_PACKAGE);
-    }
+
 
     @Test
     public void testProfileOwnerInjectedActivityNotFound() throws Exception {
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
index c3ac137..48038c1 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
@@ -816,28 +816,6 @@
     }
 
     @Test
-    public void testNoHiddenActivityFoundTest() throws Exception {
-        try {
-            // Install app to primary user
-            installAppAsUser(BaseLauncherAppsTest.LAUNCHER_TESTS_APK, mPrimaryUserId);
-            installAppAsUser(BaseLauncherAppsTest.LAUNCHER_TESTS_SUPPORT_APK, mPrimaryUserId);
-            installAppAsUser(LAUNCHER_TESTS_HAS_LAUNCHER_ACTIVITY_APK, mPrimaryUserId);
-
-            // Run test to check if launcher api shows hidden app
-            String mSerialNumber = Integer.toString(getUserSerialNumber(mPrimaryUserId));
-            runDeviceTestsAsUser(BaseLauncherAppsTest.LAUNCHER_TESTS_PKG,
-                    BaseLauncherAppsTest.LAUNCHER_TESTS_CLASS,
-                    "testDoPoNoTestAppInjectedActivityFound",
-                    mPrimaryUserId, Collections.singletonMap(BaseLauncherAppsTest.PARAM_TEST_USER,
-                            mSerialNumber));
-        } finally {
-            getDevice().uninstallPackage(LAUNCHER_TESTS_HAS_LAUNCHER_ACTIVITY_APK);
-            getDevice().uninstallPackage(BaseLauncherAppsTest.LAUNCHER_TESTS_SUPPORT_APK);
-            getDevice().uninstallPackage(BaseLauncherAppsTest.LAUNCHER_TESTS_APK);
-        }
-    }
-
-    @Test
     public void testSetGlobalSettingLogged() throws Exception {
         assertMetricsLogged(getDevice(), () -> {
             executeDeviceTestMethod(".DevicePolicyLoggingTest", "testSetGlobalSettingLogged");
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/LauncherAppsProfileTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/LauncherAppsProfileTest.java
index fd267c0..cac30db 100755
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/LauncherAppsProfileTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/LauncherAppsProfileTest.java
@@ -116,21 +116,6 @@
                 mParentUserId, Collections.singletonMap(PARAM_TEST_USER, mMainUserSerialNumber));
     }
 
-    @Test
-    public void testNoHiddenActivityInProfile() throws Exception {
-        // Install app for all users.
-        installAppAsUser(LAUNCHER_TESTS_HAS_LAUNCHER_ACTIVITY_APK, mParentUserId);
-        installAppAsUser(LAUNCHER_TESTS_HAS_LAUNCHER_ACTIVITY_APK, mProfileUserId);
-
-        // Run tests to check SimpleApp exists in both profile and main user.
-        runDeviceTestsAsUser(LAUNCHER_TESTS_PKG,
-                LAUNCHER_TESTS_CLASS, "testDoPoNoTestAppInjectedActivityFound",
-                mParentUserId, Collections.singletonMap(PARAM_TEST_USER, mProfileSerialNumber));
-        runDeviceTestsAsUser(LAUNCHER_TESTS_PKG,
-                LAUNCHER_TESTS_CLASS, "testHasLauncherActivityAppHasAppDetailsActivityInjected",
-                mParentUserId, Collections.singletonMap(PARAM_TEST_USER, mMainUserSerialNumber));
-    }
-
     @FlakyTest
     @Test
     public void testLauncherCallbackPackageAddedProfile() throws Exception {
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/LimitAppIconHidingTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/LimitAppIconHidingTest.java
index 29f3d04..b823a94 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/LimitAppIconHidingTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/LimitAppIconHidingTest.java
@@ -74,13 +74,6 @@
     }
 
     @Test
-    public void testHasLauncherActivityAppHasAppDetailsActivityInjected() throws Exception {
-        runDeviceTestsAsUser(LAUNCHER_TESTS_PKG,
-                LAUNCHER_TESTS_CLASS, "testHasLauncherActivityAppHasAppDetailsActivityInjected",
-                mCurrentUserId, Collections.singletonMap(PARAM_TEST_USER, mSerialNumber));
-    }
-
-    @Test
     public void testNoSystemAppHasSyntheticAppDetailsActivityInjected() throws Exception {
         runDeviceTestsAsUser(LAUNCHER_TESTS_PKG,
                 LAUNCHER_TESTS_CLASS, "testNoSystemAppHasSyntheticAppDetailsActivityInjected",
@@ -100,11 +93,4 @@
                 LAUNCHER_TESTS_CLASS, "testNoPermissionAppNotInjected",
                 mCurrentUserId, Collections.singletonMap(PARAM_TEST_USER, mSerialNumber));
     }
-
-    @Test
-    public void testGetSetSyntheticAppDetailsActivityEnabled() throws Exception {
-        runDeviceTestsAsUser(LAUNCHER_TESTS_PKG,
-                LAUNCHER_TESTS_CLASS, "testGetSetSyntheticAppDetailsActivityEnabled",
-                mCurrentUserId, Collections.singletonMap(PARAM_TEST_USER, mSerialNumber));
-    }
 }
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/LauncherAppsTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/LauncherAppsTest.java
index d6793ba..48e6767 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/LauncherAppsTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/LauncherAppsTest.java
@@ -16,31 +16,206 @@
 
 package android.devicepolicy.cts;
 
-import static org.junit.Assert.assertNull;
+import static com.android.bedstead.nene.permissions.CommonPermissions.CHANGE_COMPONENT_ENABLED_STATE;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.testng.Assert.assertThrows;
 
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.LauncherActivityInfo;
 import android.content.pm.LauncherApps;
+import android.content.pm.PackageManager;
 import android.os.Process;
 
 import com.android.bedstead.harrier.BedsteadJUnit4;
+import com.android.bedstead.harrier.DeviceState;
+import com.android.bedstead.harrier.annotations.EnsureDoesNotHavePermission;
+import com.android.bedstead.harrier.annotations.EnsureHasPermission;
+import com.android.bedstead.harrier.annotations.RequireNotHeadlessSystemUserMode;
+import com.android.bedstead.harrier.annotations.parameterized.IncludeRunOnDeviceOwnerUser;
+import com.android.bedstead.harrier.annotations.parameterized.IncludeRunOnParentOfProfileOwnerWithNoDeviceOwner;
+import com.android.bedstead.harrier.annotations.parameterized.IncludeRunOnPrimaryUserWithNoDpc;
+import com.android.bedstead.harrier.annotations.parameterized.IncludeRunOnProfileOwnerProfileWithNoDeviceOwner;
 import com.android.bedstead.nene.TestApis;
+import com.android.bedstead.testapp.TestApp;
+import com.android.bedstead.testapp.TestAppActivityReference;
+import com.android.bedstead.testapp.TestAppInstance;
+import com.android.queryable.queries.ActivityQuery;
+import com.android.queryable.queries.IntentFilterQuery;
 
+import org.junit.ClassRule;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.List;
+
 @RunWith(BedsteadJUnit4.class)
 public final class LauncherAppsTest {
-    private final Context sContext = TestApis.context().instrumentedContext();
-    private final LauncherApps sLauncherApps = sContext.getSystemService(LauncherApps.class);
+    private static final Context sContext = TestApis.context().instrumentedContext();
+    private static final LauncherApps sLauncherApps = sContext.getSystemService(LauncherApps.class);
+    private static final String SYNTHETIC_APP_DETAILS_ACTIVITY = "android.app.AppDetailsActivity";
+    private static final PackageManager sPackageManager = sContext.getPackageManager();
 
+
+    @ClassRule @Rule
+    public static DeviceState sDeviceState = new DeviceState();
+
+
+    private static final ActivityQuery<?> MAIN_ACTIVITY_QUERY = ActivityQuery.activity()
+            .exported().isTrue()
+            .intentFilters().contains(
+                    IntentFilterQuery.intentFilter()
+                            .actions().contains(Intent.ACTION_MAIN)
+                            .categories().contains(Intent.CATEGORY_LAUNCHER)
+            );
+
+    private static final TestApp sTestApp = sDeviceState.testApps().query()
+            .whereActivities().contains(MAIN_ACTIVITY_QUERY).get();
+
+    // TODO(257215214): Unrelated to device policy - move to PackageManager module
     @Test
     public void resolveActivity_invalid_doesNotCrash() {
-        final Intent intent = new Intent();
+        Intent intent = new Intent();
         intent.setComponent(new ComponentName("invalidPackage", "invalidClass"));
 
         // Test that resolving invalid intent does not crash launcher
-        assertNull(sLauncherApps.resolveActivity(intent, Process.myUserHandle()));
+        assertThat(sLauncherApps.resolveActivity(intent, Process.myUserHandle())).isNull();
+    }
+
+    @Test
+    @IncludeRunOnDeviceOwnerUser // Device Owner devices should not show hidden apps
+    @IncludeRunOnProfileOwnerProfileWithNoDeviceOwner // Work profiles should not show hidden apps
+    public void getActivityList_activityIsDisabled_isNotIncludedInList() {
+        // We install on the DPC user so that this installs in the work profile when there is one
+        try (TestAppInstance app = sTestApp.install(sDeviceState.dpc().user())) {
+            disableMainActivity(app);
+
+            List<LauncherActivityInfo> launcherActivities = sLauncherApps.getActivityList(
+                    app.packageName(), app.user().userHandle());
+
+            assertThat(launcherActivities).isEmpty();
+        }
+    }
+
+
+    @Test
+    @IncludeRunOnPrimaryUserWithNoDpc // Synthetic activities should be injected in general
+    @IncludeRunOnParentOfProfileOwnerWithNoDeviceOwner // Should be injected for personal users with a work profile
+    @RequireNotHeadlessSystemUserMode(reason = "b/257217938 functionality is broken on headless")
+    public void getActivityList_launcherActivityIsDisabled_syntheticActivityIsIncluded() {
+        try (TestAppInstance app = sTestApp.install()) {
+            disableMainActivity(app);
+
+            List<LauncherActivityInfo> activities = sLauncherApps.getActivityList(
+                    app.packageName(), app.user().userHandle());
+
+            assertSyntheticActivityIsIncluded(activities);
+        }
+    }
+
+    // TODO(257215214): Unrelated to device policy - move to PackageManager module
+    @Test
+    @EnsureDoesNotHavePermission(CHANGE_COMPONENT_ENABLED_STATE)
+    public void setSyntheticAppDetailsActivityEnabled_noPermission_throwsException() {
+        try (TestAppInstance app = sTestApp.install()) {
+            assertThrows(SecurityException.class, () ->
+                    sPackageManager.setSyntheticAppDetailsActivityEnabled(
+                            app.packageName(), /* enabled= */ false));
+        }
+    }
+
+    // TODO(257215214): Unrelated to device policy - move to PackageManager module
+    @Test
+    @EnsureHasPermission(CHANGE_COMPONENT_ENABLED_STATE)
+    public void setSyntheticAppDetailsActivityEnabled_true_isEnabled() {
+        try (TestAppInstance app = sTestApp.install()) {
+            disableMainActivity(app);
+
+            sPackageManager.setSyntheticAppDetailsActivityEnabled(
+                    app.packageName(), /* enabled= */ true);
+
+            assertThat(app.testApp().pkg().syntheticAppDetailsActivityEnabled()).isTrue();
+        }
+    }
+
+    // TODO(257215214): Unrelated to device policy - move to PackageManager module
+    @Test
+    @EnsureHasPermission(CHANGE_COMPONENT_ENABLED_STATE)
+    @RequireNotHeadlessSystemUserMode(reason = "b/257217938 functionality is broken on headless")
+    public void setSyntheticAppDetailsActivityEnabled_true_activityListIncludesSyntheticActivity() {
+        try (TestAppInstance app = sTestApp.install()) {
+            disableMainActivity(app);
+
+            sPackageManager.setSyntheticAppDetailsActivityEnabled(
+                    app.packageName(), /* enabled= */ true);
+
+            List<LauncherActivityInfo> activities = sLauncherApps.getActivityList(
+                    app.packageName(), app.user().userHandle());
+            assertSyntheticActivityIsIncluded(activities);
+        }
+    }
+
+    // TODO(257215214): Unrelated to device policy - move to PackageManager module
+    @Test
+    @EnsureHasPermission(CHANGE_COMPONENT_ENABLED_STATE)
+    public void setSyntheticAppDetailsActivityEnabled_false_isNotEnabled() {
+        try (TestAppInstance app = sTestApp.install()) {
+            try {
+                disableMainActivity(app);
+
+                sPackageManager.setSyntheticAppDetailsActivityEnabled(
+                        app.packageName(), /* enabled= */ false);
+
+                assertThat(app.testApp().pkg().syntheticAppDetailsActivityEnabled()).isFalse();
+            } finally {
+                app.testApp().pkg().setSyntheticAppDetailsActivityEnabled(true);
+            }
+        }
+    }
+
+    // TODO(257215214): Unrelated to device policy - move to PackageManager module
+    @Test
+    @EnsureHasPermission(CHANGE_COMPONENT_ENABLED_STATE)
+    public void setSyntheticAppDetailsActivityEnabled_false_activityListDoesNotIncludeSyntheticActivity() {
+        try (TestAppInstance app = sTestApp.install()) {
+            try {
+                disableMainActivity(app);
+
+                sPackageManager.setSyntheticAppDetailsActivityEnabled(
+                        app.packageName(), /* enabled= */ false);
+
+                List<LauncherActivityInfo> activities = sLauncherApps.getActivityList(
+                        app.packageName(), app.user().userHandle());
+                assertThat(activities).isEmpty();
+            } finally {
+                app.testApp().pkg().setSyntheticAppDetailsActivityEnabled(true);
+            }
+        }
+    }
+
+    private void disableMainActivity(TestAppInstance testApp) {
+        TestAppActivityReference activity = testApp.activities().query()
+                .whereActivity().exported().isTrue()
+                .whereActivity().intentFilters().contains(
+                        IntentFilterQuery.intentFilter()
+                                .actions().contains(Intent.ACTION_MAIN)
+                                .categories().contains(Intent.CATEGORY_LAUNCHER)
+                ).get();
+        activity.component().disable();
+    }
+
+    private void assertSyntheticActivityIsIncluded(List<LauncherActivityInfo> activities) {
+        assertThat(activities).isNotEmpty();
+        for (LauncherActivityInfo info : activities) {
+            assertThat(info.getName()).isEqualTo(SYNTHETIC_APP_DETAILS_ACTIVITY);
+            assertThat(TestApis.packages().activity(info.getComponentName()).isEnabled())
+                    .isTrue();
+            assertThat(TestApis.packages().activity(info.getComponentName()).isExported())
+                    .isTrue();
+        }
     }
 }