diff options
Diffstat (limited to 'tests')
18 files changed, 1102 insertions, 26 deletions
diff --git a/tests/FlickerTests/ActivityEmbedding/Android.bp b/tests/FlickerTests/ActivityEmbedding/Android.bp index e09fbf6adc02..c681ce96a269 100644 --- a/tests/FlickerTests/ActivityEmbedding/Android.bp +++ b/tests/FlickerTests/ActivityEmbedding/Android.bp @@ -24,6 +24,9 @@ package { default_applicable_licenses: ["frameworks_base_license"], } +//////////////////////////////////////////////////////////////////////////////// +// Begin to cleanup after CL merges + filegroup { name: "FlickerTestsOtherCommon-src", srcs: ["src/**/ActivityEmbeddingTestBase.kt"], @@ -82,3 +85,123 @@ android_test { ":FlickerTestsOtherCommon-src", ], } + +// End to cleanup after CL merges +//////////////////////////////////////////////////////////////////////////////// + +android_test { + name: "FlickerTestsActivityEmbedding", + defaults: ["FlickerTestsDefault"], + manifest: "AndroidManifest.xml", + package_name: "com.android.server.wm.flicker", + instrumentation_target_package: "com.android.server.wm.flicker", + test_config_template: "AndroidTestTemplate.xml", + srcs: ["src/**/*"], + static_libs: [ + "FlickerTestsBase", + "FlickerTestsOtherCommon", + ], + data: ["trace_config/*"], +} + +//////////////////////////////////////////////////////////////////////////////// +// Begin breakdowns for FlickerTestsActivityEmbedding module + +test_module_config { + name: "FlickerTestsActivityEmbedding-CatchAll", + base: "FlickerTestsActivityEmbedding", + exclude_filters: [ + "com.android.server.wm.flicker.activityembedding.close.CloseSecondaryActivityInSplitTest", + "com.android.server.wm.flicker.activityembedding.layoutchange.HorizontalSplitChangeRatioTest", + "com.android.server.wm.flicker.activityembedding.open.MainActivityStartsSecondaryWithAlwaysExpandTest", + "com.android.server.wm.flicker.activityembedding.open.OpenActivityEmbeddingPlaceholderSplitTest", + "com.android.server.wm.flicker.activityembedding.open.OpenActivityEmbeddingSecondaryToSplitTest", + "com.android.server.wm.flicker.activityembedding.open.OpenThirdActivityOverSplitTest", + "com.android.server.wm.flicker.activityembedding.open.OpenTrampolineActivityTest", + "com.android.server.wm.flicker.activityembedding.pip.SecondaryActivityEnterPipTest", + "com.android.server.wm.flicker.activityembedding.rotation.RotateSplitNoChangeTest", + "com.android.server.wm.flicker.activityembedding.rtl.RTLStartSecondaryWithPlaceholderTest", + "com.android.server.wm.flicker.activityembedding.splitscreen.EnterSystemSplitTest", + ], + test_suites: ["device-tests"], +} + +test_module_config { + name: "FlickerTestsActivityEmbedding-Close-CloseSecondaryActivityInSplitTest", + base: "FlickerTestsActivityEmbedding", + include_filters: ["com.android.server.wm.flicker.activityembedding.close.CloseSecondaryActivityInSplitTest"], + test_suites: ["device-tests"], +} + +test_module_config { + name: "FlickerTestsActivityEmbedding-LayoutChange-HorizontalSplitChangeRatioTest", + base: "FlickerTestsActivityEmbedding", + include_filters: ["com.android.server.wm.flicker.activityembedding.layoutchange.HorizontalSplitChangeRatioTest"], + test_suites: ["device-tests"], +} + +test_module_config { + name: "FlickerTestsActivityEmbedding-Open-MainActivityStartsSecondaryWithAlwaysExpandTest", + base: "FlickerTestsActivityEmbedding", + include_filters: ["com.android.server.wm.flicker.activityembedding.open.MainActivityStartsSecondaryWithAlwaysExpandTest"], + test_suites: ["device-tests"], +} + +test_module_config { + name: "FlickerTestsActivityEmbedding-Open-OpenActivityEmbeddingPlaceholderSplitTest", + base: "FlickerTestsActivityEmbedding", + include_filters: ["com.android.server.wm.flicker.activityembedding.open.OpenActivityEmbeddingPlaceholderSplitTest"], + test_suites: ["device-tests"], +} + +test_module_config { + name: "FlickerTestsActivityEmbedding-Open-OpenActivityEmbeddingSecondaryToSplitTest", + base: "FlickerTestsActivityEmbedding", + include_filters: ["com.android.server.wm.flicker.activityembedding.open.OpenActivityEmbeddingSecondaryToSplitTest"], + test_suites: ["device-tests"], +} + +test_module_config { + name: "FlickerTestsActivityEmbedding-Open-OpenThirdActivityOverSplitTest", + base: "FlickerTestsActivityEmbedding", + include_filters: ["com.android.server.wm.flicker.activityembedding.open.OpenThirdActivityOverSplitTest"], + test_suites: ["device-tests"], +} + +test_module_config { + name: "FlickerTestsActivityEmbedding-Open-OpenTrampolineActivityTest", + base: "FlickerTestsActivityEmbedding", + include_filters: ["com.android.server.wm.flicker.activityembedding.open.OpenTrampolineActivityTest"], + test_suites: ["device-tests"], +} + +test_module_config { + name: "FlickerTestsActivityEmbedding-Pip-SecondaryActivityEnterPipTest", + base: "FlickerTestsActivityEmbedding", + include_filters: ["com.android.server.wm.flicker.activityembedding.pip.SecondaryActivityEnterPipTest"], + test_suites: ["device-tests"], +} + +test_module_config { + name: "FlickerTestsActivityEmbedding-Rotation-RotateSplitNoChangeTest", + base: "FlickerTestsActivityEmbedding", + include_filters: ["com.android.server.wm.flicker.activityembedding.rotation.RotateSplitNoChangeTest"], + test_suites: ["device-tests"], +} + +test_module_config { + name: "FlickerTestsActivityEmbedding-Rtl-RTLStartSecondaryWithPlaceholderTest", + base: "FlickerTestsActivityEmbedding", + include_filters: ["com.android.server.wm.flicker.activityembedding.rtl.RTLStartSecondaryWithPlaceholderTest"], + test_suites: ["device-tests"], +} + +test_module_config { + name: "FlickerTestsActivityEmbedding-SplitScreen-EnterSystemSplitTest", + base: "FlickerTestsActivityEmbedding", + include_filters: ["com.android.server.wm.flicker.activityembedding.splitscreen.EnterSystemSplitTest"], + test_suites: ["device-tests"], +} + +// End breakdowns for FlickerTestsActivityEmbedding module +//////////////////////////////////////////////////////////////////////////////// diff --git a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/rotation/RotationTransition.kt b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/rotation/RotationTransition.kt index ee2c05e82d51..06326f8cc8d2 100644 --- a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/rotation/RotationTransition.kt +++ b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/rotation/RotationTransition.kt @@ -36,7 +36,7 @@ abstract class RotationTransition(flicker: LegacyFlickerTest) : ActivityEmbeddin teardown { testApp.exit(wmHelper) } transitions { this.setRotation(flicker.scenario.endRotation) - if (!flicker.scenario.isTablet) { + if (!usesTaskbar) { wmHelper.StateSyncBuilder() .add(navBarInPosition(flicker.scenario.isGesturalNavigation)) .waitForAndVerify() diff --git a/tests/FlickerTests/AppLaunch/Android.bp b/tests/FlickerTests/AppLaunch/Android.bp index 72a90650927f..b61739f100ab 100644 --- a/tests/FlickerTests/AppLaunch/Android.bp +++ b/tests/FlickerTests/AppLaunch/Android.bp @@ -15,6 +15,7 @@ // package { + default_team: "trendy_team_windowing_animations_transitions", // See: http://go/android-license-faq // A large-scale-change added 'default_applicable_licenses' to import // all of the 'license_kinds' from "frameworks_base_license" @@ -23,6 +24,9 @@ package { default_applicable_licenses: ["frameworks_base_license"], } +//////////////////////////////////////////////////////////////////////////////// +// Begin to cleanup after CL merges + filegroup { name: "FlickerTestsAppLaunchCommon-src", srcs: ["src/**/common/*"], @@ -69,3 +73,122 @@ android_test { ], data: ["trace_config/*"], } + +// End to cleanup after CL merges +//////////////////////////////////////////////////////////////////////////////// + +android_test { + name: "FlickerTestsAppLaunch", + defaults: ["FlickerTestsDefault"], + manifest: "AndroidManifest.xml", + test_config_template: "AndroidTestTemplate.xml", + srcs: ["src/**/*"], + static_libs: [ + "FlickerTestsBase", + "FlickerTestsAppLaunchCommon", + ], + data: ["trace_config/*"], +} + +//////////////////////////////////////////////////////////////////////////////// +// Begin breakdowns for FlickerTestsAppLaunch module + +test_module_config { + name: "FlickerTestsAppLaunch-CatchAll", + base: "FlickerTestsAppLaunch", + exclude_filters: [ + "com.android.server.wm.flicker.launch.TaskTransitionTest", + "com.android.server.wm.flicker.launch.ActivityTransitionTest", + "com.android.server.wm.flicker.launch.OpenAppFromIconColdTest", + "com.android.server.wm.flicker.launch.OpenAppFromIntentColdAfterCameraTest", + "com.android.server.wm.flicker.launch.OpenAppFromIntentColdTest", + "com.android.server.wm.flicker.launch.OpenAppFromIntentWarmTest", + "com.android.server.wm.flicker.launch.OpenAppFromLockscreenViaIntentTest", + "com.android.server.wm.flicker.launch.OpenAppFromOverviewTest", + "com.android.server.wm.flicker.launch.OpenCameraFromHomeOnDoubleClickPowerButtonTest", + "com.android.server.wm.flicker.launch.OpenTransferSplashscreenAppFromLauncherTransition", + "com.android.server.wm.flicker.launch.OverrideTaskTransitionTest", + "com.android.server.wm.flicker.launch.TaskTransitionTest", + ], + test_suites: ["device-tests"], +} + +test_module_config { + name: "FlickerTestsAppLaunch-ActivityTransitionTest", + base: "FlickerTestsAppLaunch", + include_filters: ["com.android.server.wm.flicker.launch.ActivityTransitionTest"], + test_suites: ["device-tests"], +} + +test_module_config { + name: "FlickerTestsAppLaunch-OpenAppFromIconColdTest", + base: "FlickerTestsAppLaunch", + include_filters: ["com.android.server.wm.flicker.launch.OpenAppFromIconColdTest"], + test_suites: ["device-tests"], +} + +test_module_config { + name: "FlickerTestsAppLaunch-OpenAppFromIntentColdAfterCameraTest", + base: "FlickerTestsAppLaunch", + include_filters: ["com.android.server.wm.flicker.launch.OpenAppFromIntentColdAfterCameraTest"], + test_suites: ["device-tests"], +} + +test_module_config { + name: "FlickerTestsAppLaunch-OpenAppFromIntentColdTest", + base: "FlickerTestsAppLaunch", + include_filters: ["com.android.server.wm.flicker.launch.OpenAppFromIntentColdTest"], + test_suites: ["device-tests"], +} + +test_module_config { + name: "FlickerTestsAppLaunch-OpenAppFromIntentWarmTest", + base: "FlickerTestsAppLaunch", + include_filters: ["com.android.server.wm.flicker.launch.OpenAppFromIntentWarmTest"], + test_suites: ["device-tests"], +} + +test_module_config { + name: "FlickerTestsAppLaunch-OpenAppFromLockscreenViaIntentTest", + base: "FlickerTestsAppLaunch", + include_filters: ["com.android.server.wm.flicker.launch.OpenAppFromLockscreenViaIntentTest"], + test_suites: ["device-tests"], +} + +test_module_config { + name: "FlickerTestsAppLaunch-OpenAppFromOverviewTest", + base: "FlickerTestsAppLaunch", + include_filters: ["com.android.server.wm.flicker.launch.OpenAppFromOverviewTest"], + test_suites: ["device-tests"], +} + +test_module_config { + name: "FlickerTestsAppLaunch-OpenCameraFromHomeOnDoubleClickPowerButtonTest", + base: "FlickerTestsAppLaunch", + include_filters: ["com.android.server.wm.flicker.launch.OpenCameraFromHomeOnDoubleClickPowerButtonTest"], + test_suites: ["device-tests"], +} + +test_module_config { + name: "FlickerTestsAppLaunch-OpenTransferSplashscreenAppFromLauncherTransition", + base: "FlickerTestsAppLaunch", + include_filters: ["com.android.server.wm.flicker.launch.OpenTransferSplashscreenAppFromLauncherTransition"], + test_suites: ["device-tests"], +} + +test_module_config { + name: "FlickerTestsAppLaunch-OverrideTaskTransitionTest", + base: "FlickerTestsAppLaunch", + include_filters: ["com.android.server.wm.flicker.launch.OverrideTaskTransitionTest"], + test_suites: ["device-tests"], +} + +test_module_config { + name: "FlickerTestsAppLaunch-TaskTransitionTest", + base: "FlickerTestsAppLaunch", + include_filters: ["com.android.server.wm.flicker.launch.TaskTransitionTest"], + test_suites: ["device-tests"], +} + +// End breakdowns for FlickerTestsAppLaunch module +//////////////////////////////////////////////////////////////////////////////// diff --git a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromLockscreenViaIntentTest.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromLockscreenViaIntentTest.kt index 44ae27c2ee4b..adeba72c9c96 100644 --- a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromLockscreenViaIntentTest.kt +++ b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromLockscreenViaIntentTest.kt @@ -75,7 +75,7 @@ open class OpenAppFromLockscreenViaIntentTest(flicker: LegacyFlickerTest) : @FlakyTest(bugId = 288341660) @Test fun navBarLayerVisibilityChanges() { - Assume.assumeFalse(flicker.scenario.isTablet) + Assume.assumeFalse(usesTaskbar) flicker.assertLayers { this.isInvisible(ComponentNameMatcher.NAV_BAR) .then() @@ -97,7 +97,7 @@ open class OpenAppFromLockscreenViaIntentTest(flicker: LegacyFlickerTest) : @FlakyTest(bugId = 293581770) @Test fun navBarWindowsVisibilityChanges() { - Assume.assumeFalse(flicker.scenario.isTablet) + Assume.assumeFalse(usesTaskbar) flicker.assertWm { this.isNonAppWindowInvisible(ComponentNameMatcher.NAV_BAR) .then() @@ -112,7 +112,7 @@ open class OpenAppFromLockscreenViaIntentTest(flicker: LegacyFlickerTest) : @Presubmit @Test fun taskBarLayerIsVisibleAtEnd() { - Assume.assumeTrue(flicker.scenario.isTablet) + Assume.assumeTrue(usesTaskbar) flicker.assertLayersEnd { this.isVisible(ComponentNameMatcher.TASK_BAR) } } @@ -170,7 +170,7 @@ open class OpenAppFromLockscreenViaIntentTest(flicker: LegacyFlickerTest) : @Presubmit @Test fun navBarLayerIsVisibleAtEnd() { - Assume.assumeFalse(flicker.scenario.isTablet) + Assume.assumeFalse(usesTaskbar) flicker.assertLayersEnd { this.isVisible(ComponentNameMatcher.NAV_BAR) } } @@ -184,7 +184,7 @@ open class OpenAppFromLockscreenViaIntentTest(flicker: LegacyFlickerTest) : @Presubmit @Test override fun appLayerBecomesVisible() { - Assume.assumeFalse(flicker.scenario.isTablet) + Assume.assumeFalse(usesTaskbar) super.appLayerBecomesVisible() } @@ -192,7 +192,7 @@ open class OpenAppFromLockscreenViaIntentTest(flicker: LegacyFlickerTest) : @FlakyTest(bugId = 227143265) @Test fun appLayerBecomesVisibleTablet() { - Assume.assumeTrue(flicker.scenario.isTablet) + Assume.assumeTrue(usesTaskbar) super.appLayerBecomesVisible() } diff --git a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/common/OpenAppFromIconTransition.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/common/OpenAppFromIconTransition.kt index 8a3304b0343d..b497e3048759 100644 --- a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/common/OpenAppFromIconTransition.kt +++ b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/common/OpenAppFromIconTransition.kt @@ -28,6 +28,7 @@ abstract class OpenAppFromIconTransition(flicker: LegacyFlickerTest) : get() = { super.transition(this) setup { + // By default, launcher doesn't rotate on phones, but rotates on tablets if (flicker.scenario.isTablet) { tapl.setExpectedRotation(flicker.scenario.startRotation.value) } else { diff --git a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/common/OpenAppFromLockscreenTransition.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/common/OpenAppFromLockscreenTransition.kt index f8fd35860f6f..a6e31d49a0e8 100644 --- a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/common/OpenAppFromLockscreenTransition.kt +++ b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/common/OpenAppFromLockscreenTransition.kt @@ -103,7 +103,7 @@ abstract class OpenAppFromLockscreenTransition(flicker: LegacyFlickerTest) : @Presubmit @Test open fun navBarLayerPositionAtEnd() { - Assume.assumeFalse(flicker.scenario.isTablet) + Assume.assumeFalse(usesTaskbar) flicker.navBarLayerPositionAtEnd() } diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeToAppOnPressBackTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeToAppOnPressBackTest.kt index dc2bd1bc9996..522c68bba0d1 100644 --- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeToAppOnPressBackTest.kt +++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeToAppOnPressBackTest.kt @@ -72,7 +72,7 @@ class CloseImeToAppOnPressBackTest(flicker: LegacyFlickerTest) : BaseTest(flicke @Presubmit @Test override fun navBarLayerPositionAtStartAndEnd() { - Assume.assumeFalse(flicker.scenario.isTablet) + Assume.assumeFalse(usesTaskbar) Assume.assumeFalse(flicker.scenario.isLandscapeOrSeascapeAtStart) flicker.navBarLayerPositionAtStartAndEnd() } @@ -80,7 +80,7 @@ class CloseImeToAppOnPressBackTest(flicker: LegacyFlickerTest) : BaseTest(flicke @Presubmit @Test fun navBarLayerPositionAtStartAndEndLandscapeOrSeascapeAtStart() { - Assume.assumeFalse(flicker.scenario.isTablet) + Assume.assumeFalse(usesTaskbar) Assume.assumeTrue(flicker.scenario.isLandscapeOrSeascapeAtStart) flicker.navBarLayerPositionAtStartAndEnd() } diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhileEnteringOverviewTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhileEnteringOverviewTest.kt index c96c760e2d7b..638d594b0a48 100644 --- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhileEnteringOverviewTest.kt +++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhileEnteringOverviewTest.kt @@ -93,7 +93,7 @@ class ShowImeWhileEnteringOverviewTest(flicker: LegacyFlickerTest) : BaseTest(fl @Presubmit @Test fun navBarLayerIsVisibleAtStartAndEnd3Button() { - Assume.assumeFalse(flicker.scenario.isTablet) + Assume.assumeFalse(usesTaskbar) Assume.assumeFalse(flicker.scenario.isGesturalNavigation) flicker.navBarLayerIsVisibleAtStartAndEnd() } @@ -105,7 +105,7 @@ class ShowImeWhileEnteringOverviewTest(flicker: LegacyFlickerTest) : BaseTest(fl @Presubmit @Test fun navBarLayerIsInvisibleInLandscapeGestural() { - Assume.assumeFalse(flicker.scenario.isTablet) + Assume.assumeFalse(usesTaskbar) Assume.assumeTrue(flicker.scenario.isLandscapeOrSeascapeAtStart) Assume.assumeTrue(flicker.scenario.isGesturalNavigation) flicker.assertLayersStart { this.isVisible(ComponentNameMatcher.NAV_BAR) } @@ -121,7 +121,7 @@ class ShowImeWhileEnteringOverviewTest(flicker: LegacyFlickerTest) : BaseTest(fl fun statusBarLayerIsInvisibleInLandscapePhone() { Assume.assumeTrue(flicker.scenario.isLandscapeOrSeascapeAtStart) Assume.assumeTrue(flicker.scenario.isGesturalNavigation) - Assume.assumeFalse(flicker.scenario.isTablet) + Assume.assumeFalse(usesTaskbar) flicker.assertLayersStart { this.isVisible(ComponentNameMatcher.STATUS_BAR) } flicker.assertLayersEnd { this.isInvisible(ComponentNameMatcher.STATUS_BAR) } } @@ -135,7 +135,7 @@ class ShowImeWhileEnteringOverviewTest(flicker: LegacyFlickerTest) : BaseTest(fl fun statusBarLayerIsInvisibleInLandscapeTablet() { Assume.assumeTrue(flicker.scenario.isLandscapeOrSeascapeAtStart) Assume.assumeTrue(flicker.scenario.isGesturalNavigation) - Assume.assumeTrue(flicker.scenario.isTablet) + Assume.assumeTrue(usesTaskbar) flicker.statusBarLayerIsVisibleAtStartAndEnd() } @@ -174,7 +174,7 @@ class ShowImeWhileEnteringOverviewTest(flicker: LegacyFlickerTest) : BaseTest(fl @Test fun statusBarLayerIsInvisibleInLandscape() { Assume.assumeTrue(flicker.scenario.isLandscapeOrSeascapeAtStart) - Assume.assumeFalse(flicker.scenario.isTablet) + Assume.assumeFalse(usesTaskbar) flicker.assertLayersStart { this.isVisible(ComponentNameMatcher.STATUS_BAR) } flicker.assertLayersEnd { this.isInvisible(ComponentNameMatcher.STATUS_BAR) } } diff --git a/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromNotificationWarmTest.kt b/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromNotificationWarmTest.kt index 07fc2300286a..ad70757a9a4d 100644 --- a/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromNotificationWarmTest.kt +++ b/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromNotificationWarmTest.kt @@ -151,7 +151,7 @@ open class OpenAppFromNotificationWarmTest(flicker: LegacyFlickerTest) : @Presubmit @Test open fun taskBarWindowIsVisibleAtEnd() { - Assume.assumeTrue(flicker.scenario.isTablet) + Assume.assumeTrue(usesTaskbar) flicker.taskBarWindowIsVisibleAtEnd() } @@ -163,7 +163,7 @@ open class OpenAppFromNotificationWarmTest(flicker: LegacyFlickerTest) : @Presubmit @Test open fun taskBarLayerIsVisibleAtEnd() { - Assume.assumeTrue(flicker.scenario.isTablet) + Assume.assumeTrue(usesTaskbar) flicker.taskBarLayerIsVisibleAtEnd() } @@ -171,7 +171,7 @@ open class OpenAppFromNotificationWarmTest(flicker: LegacyFlickerTest) : @Presubmit @Test open fun navBarLayerPositionAtEnd() { - Assume.assumeFalse(flicker.scenario.isTablet) + Assume.assumeFalse(usesTaskbar) flicker.navBarLayerPositionAtEnd() } @@ -179,14 +179,14 @@ open class OpenAppFromNotificationWarmTest(flicker: LegacyFlickerTest) : @Presubmit @Test open fun navBarLayerIsVisibleAtEnd() { - Assume.assumeFalse(flicker.scenario.isTablet) + Assume.assumeFalse(usesTaskbar) flicker.navBarLayerIsVisibleAtEnd() } @Presubmit @Test open fun navBarWindowIsVisibleAtEnd() { - Assume.assumeFalse(flicker.scenario.isTablet) + Assume.assumeFalse(usesTaskbar) flicker.navBarWindowIsVisibleAtEnd() } diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/BaseTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/BaseTest.kt index 060015bcc4b2..70d762e02af5 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/BaseTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/BaseTest.kt @@ -26,6 +26,7 @@ import android.tools.traces.component.ComponentNameMatcher import android.util.Log import androidx.test.platform.app.InstrumentationRegistry import com.android.launcher3.tapl.LauncherInstrumentation +import com.android.wm.shell.Flags import org.junit.Assume import org.junit.AssumptionViolatedException import org.junit.Test @@ -48,6 +49,9 @@ constructor( private val logTag = this::class.java.simpleName + protected val usesTaskbar: Boolean + get() = flicker.scenario.isTablet || Flags.enableTaskbarOnPhones() + /** Specification of the test transition to execute */ abstract val transition: FlickerBuilder.() -> Unit @@ -87,7 +91,7 @@ constructor( @Presubmit @Test open fun navBarLayerIsVisibleAtStartAndEnd() { - Assume.assumeFalse(flicker.scenario.isTablet) + Assume.assumeFalse(usesTaskbar) flicker.navBarLayerIsVisibleAtStartAndEnd() } @@ -100,7 +104,7 @@ constructor( @Presubmit @Test open fun navBarLayerPositionAtStartAndEnd() { - Assume.assumeFalse(flicker.scenario.isTablet) + Assume.assumeFalse(usesTaskbar) flicker.navBarLayerPositionAtStartAndEnd() } @@ -112,7 +116,7 @@ constructor( @Presubmit @Test open fun navBarWindowIsAlwaysVisible() { - Assume.assumeFalse(flicker.scenario.isTablet) + Assume.assumeFalse(usesTaskbar) Assume.assumeFalse(flicker.scenario.isLandscapeOrSeascapeAtStart) flicker.navBarWindowIsAlwaysVisible() } @@ -126,7 +130,7 @@ constructor( @Presubmit @Test open fun navBarWindowIsVisibleAtStartAndEnd() { - Assume.assumeFalse(flicker.scenario.isTablet) + Assume.assumeFalse(usesTaskbar) flicker.navBarWindowIsVisibleAtStartAndEnd() } @@ -139,7 +143,7 @@ constructor( @Presubmit @Test open fun taskBarLayerIsVisibleAtStartAndEnd() { - Assume.assumeTrue(flicker.scenario.isTablet) + Assume.assumeTrue(usesTaskbar) flicker.taskBarLayerIsVisibleAtStartAndEnd() } @@ -151,7 +155,7 @@ constructor( @Presubmit @Test open fun taskBarWindowIsAlwaysVisible() { - Assume.assumeTrue(flicker.scenario.isTablet) + Assume.assumeTrue(usesTaskbar) flicker.taskBarWindowIsAlwaysVisible() } diff --git a/tests/Input/src/android/hardware/input/KeyboardSystemShortcutListenerTest.kt b/tests/Input/src/android/hardware/input/KeyboardSystemShortcutListenerTest.kt new file mode 100644 index 000000000000..24d7291bec87 --- /dev/null +++ b/tests/Input/src/android/hardware/input/KeyboardSystemShortcutListenerTest.kt @@ -0,0 +1,202 @@ +/* + * Copyright 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.hardware.input + +import android.content.Context +import android.content.ContextWrapper +import android.os.Handler +import android.os.HandlerExecutor +import android.os.test.TestLooper +import android.platform.test.annotations.Presubmit +import android.platform.test.flag.junit.SetFlagsRule +import android.view.KeyEvent +import androidx.test.core.app.ApplicationProvider +import com.android.server.testutils.any +import org.junit.After +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.Mockito +import org.mockito.Mockito.doAnswer +import org.mockito.Mockito.`when` +import org.mockito.junit.MockitoJUnitRunner +import kotlin.test.assertEquals +import kotlin.test.assertNotNull +import kotlin.test.assertNull +import kotlin.test.fail + +/** + * Tests for [InputManager.KeyboardSystemShortcutListener]. + * + * Build/Install/Run: + * atest InputTests:KeyboardSystemShortcutListenerTest + */ +@Presubmit +@RunWith(MockitoJUnitRunner::class) +class KeyboardSystemShortcutListenerTest { + + companion object { + const val DEVICE_ID = 1 + val HOME_SHORTCUT = KeyboardSystemShortcut( + intArrayOf(KeyEvent.KEYCODE_H), + KeyEvent.META_META_ON or KeyEvent.META_META_LEFT_ON, + KeyboardSystemShortcut.SYSTEM_SHORTCUT_HOME + ) + } + + @get:Rule + val rule = SetFlagsRule() + + private val testLooper = TestLooper() + private val executor = HandlerExecutor(Handler(testLooper.looper)) + private var registeredListener: IKeyboardSystemShortcutListener? = null + private lateinit var context: Context + private lateinit var inputManager: InputManager + private lateinit var inputManagerGlobalSession: InputManagerGlobal.TestSession + + @Mock + private lateinit var iInputManagerMock: IInputManager + + @Before + fun setUp() { + context = Mockito.spy(ContextWrapper(ApplicationProvider.getApplicationContext())) + inputManagerGlobalSession = InputManagerGlobal.createTestSession(iInputManagerMock) + inputManager = InputManager(context) + `when`(context.getSystemService(Mockito.eq(Context.INPUT_SERVICE))) + .thenReturn(inputManager) + + // Handle keyboard system shortcut listener registration. + doAnswer { + val listener = it.getArgument(0) as IKeyboardSystemShortcutListener + if (registeredListener != null && + registeredListener!!.asBinder() != listener.asBinder()) { + // There can only be one registered keyboard system shortcut listener per process. + fail("Trying to register a new listener when one already exists") + } + registeredListener = listener + null + }.`when`(iInputManagerMock).registerKeyboardSystemShortcutListener(any()) + + // Handle keyboard system shortcut listener being unregistered. + doAnswer { + val listener = it.getArgument(0) as IKeyboardSystemShortcutListener + if (registeredListener == null || + registeredListener!!.asBinder() != listener.asBinder()) { + fail("Trying to unregister a listener that is not registered") + } + registeredListener = null + null + }.`when`(iInputManagerMock).unregisterKeyboardSystemShortcutListener(any()) + } + + @After + fun tearDown() { + if (this::inputManagerGlobalSession.isInitialized) { + inputManagerGlobalSession.close() + } + } + + private fun notifyKeyboardSystemShortcutTriggered(id: Int, shortcut: KeyboardSystemShortcut) { + registeredListener!!.onKeyboardSystemShortcutTriggered( + id, + shortcut.keycodes, + shortcut.modifierState, + shortcut.systemShortcut + ) + } + + @Test + fun testListenerHasCorrectSystemShortcutNotified() { + var callbackCount = 0 + + // Add a keyboard system shortcut listener + inputManager.registerKeyboardSystemShortcutListener(executor) { + deviceId: Int, systemShortcut: KeyboardSystemShortcut -> + assertEquals(DEVICE_ID, deviceId) + assertEquals(HOME_SHORTCUT, systemShortcut) + callbackCount++ + } + + // Notifying keyboard system shortcut triggered will notify the listener. + notifyKeyboardSystemShortcutTriggered(DEVICE_ID, HOME_SHORTCUT) + testLooper.dispatchNext() + assertEquals(1, callbackCount) + } + + @Test + fun testAddingListenersRegistersInternalCallbackListener() { + // Set up two callbacks. + val callback1 = InputManager.KeyboardSystemShortcutListener {_, _ -> } + val callback2 = InputManager.KeyboardSystemShortcutListener {_, _ -> } + + assertNull(registeredListener) + + // Adding the listener should register the callback with InputManagerService. + inputManager.registerKeyboardSystemShortcutListener(executor, callback1) + assertNotNull(registeredListener) + + // Adding another listener should not register new internal listener. + val currListener = registeredListener + inputManager.registerKeyboardSystemShortcutListener(executor, callback2) + assertEquals(currListener, registeredListener) + } + + @Test + fun testRemovingListenersUnregistersInternalCallbackListener() { + // Set up two callbacks. + val callback1 = InputManager.KeyboardSystemShortcutListener {_, _ -> } + val callback2 = InputManager.KeyboardSystemShortcutListener {_, _ -> } + + inputManager.registerKeyboardSystemShortcutListener(executor, callback1) + inputManager.registerKeyboardSystemShortcutListener(executor, callback2) + + // Only removing all listeners should remove the internal callback + inputManager.unregisterKeyboardSystemShortcutListener(callback1) + assertNotNull(registeredListener) + inputManager.unregisterKeyboardSystemShortcutListener(callback2) + assertNull(registeredListener) + } + + @Test + fun testMultipleListeners() { + // Set up two callbacks. + var callbackCount1 = 0 + var callbackCount2 = 0 + val callback1 = InputManager.KeyboardSystemShortcutListener { _, _ -> callbackCount1++ } + val callback2 = InputManager.KeyboardSystemShortcutListener { _, _ -> callbackCount2++ } + + // Add both keyboard system shortcut listeners + inputManager.registerKeyboardSystemShortcutListener(executor, callback1) + inputManager.registerKeyboardSystemShortcutListener(executor, callback2) + + // Notifying keyboard system shortcut triggered, should notify both the callbacks. + notifyKeyboardSystemShortcutTriggered(DEVICE_ID, HOME_SHORTCUT) + testLooper.dispatchAll() + assertEquals(1, callbackCount1) + assertEquals(1, callbackCount2) + + inputManager.unregisterKeyboardSystemShortcutListener(callback2) + // Notifying keyboard system shortcut triggered, should still trigger callback1 but not + // callback2. + notifyKeyboardSystemShortcutTriggered(DEVICE_ID, HOME_SHORTCUT) + testLooper.dispatchAll() + assertEquals(2, callbackCount1) + assertEquals(1, callbackCount2) + } +} diff --git a/tests/Input/src/com/android/server/input/KeyboardShortcutCallbackHandlerTests.kt b/tests/Input/src/com/android/server/input/KeyboardShortcutCallbackHandlerTests.kt new file mode 100644 index 000000000000..5a40a1c8201e --- /dev/null +++ b/tests/Input/src/com/android/server/input/KeyboardShortcutCallbackHandlerTests.kt @@ -0,0 +1,96 @@ +/* + * Copyright 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 com.android.server.input + +import android.content.Context +import android.content.ContextWrapper +import android.hardware.input.IKeyboardSystemShortcutListener +import android.hardware.input.KeyboardSystemShortcut +import android.platform.test.annotations.Presubmit +import android.view.KeyEvent +import androidx.test.core.app.ApplicationProvider +import org.junit.Assert.assertEquals +import org.junit.Assert.assertNull +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.mockito.Mockito +import org.mockito.junit.MockitoJUnit + +/** + * Tests for {@link KeyboardShortcutCallbackHandler}. + * + * Build/Install/Run: + * atest InputTests:KeyboardShortcutCallbackHandlerTests + */ +@Presubmit +class KeyboardShortcutCallbackHandlerTests { + + companion object { + val DEVICE_ID = 1 + val HOME_SHORTCUT = KeyboardSystemShortcut( + intArrayOf(KeyEvent.KEYCODE_H), + KeyEvent.META_META_ON or KeyEvent.META_META_LEFT_ON, + KeyboardSystemShortcut.SYSTEM_SHORTCUT_HOME + ) + } + + @get:Rule + val rule = MockitoJUnit.rule()!! + + private lateinit var keyboardShortcutCallbackHandler: KeyboardShortcutCallbackHandler + private lateinit var context: Context + private var lastShortcut: KeyboardSystemShortcut? = null + + @Before + fun setup() { + context = Mockito.spy(ContextWrapper(ApplicationProvider.getApplicationContext())) + keyboardShortcutCallbackHandler = KeyboardShortcutCallbackHandler() + } + + @Test + fun testKeyboardSystemShortcutTriggered_registerUnregisterListener() { + val listener = KeyboardSystemShortcutListener() + + // Register keyboard system shortcut listener + keyboardShortcutCallbackHandler.registerKeyboardSystemShortcutListener(listener, 0) + keyboardShortcutCallbackHandler.onKeyboardSystemShortcutTriggered(DEVICE_ID, HOME_SHORTCUT) + assertEquals( + "Listener should get callback on keyboard system shortcut triggered", + HOME_SHORTCUT, + lastShortcut!! + ) + + // Unregister listener + lastShortcut = null + keyboardShortcutCallbackHandler.unregisterKeyboardSystemShortcutListener(listener, 0) + keyboardShortcutCallbackHandler.onKeyboardSystemShortcutTriggered(DEVICE_ID, HOME_SHORTCUT) + assertNull("Listener should not get callback after being unregistered", lastShortcut) + } + + inner class KeyboardSystemShortcutListener : IKeyboardSystemShortcutListener.Stub() { + override fun onKeyboardSystemShortcutTriggered( + deviceId: Int, + keycodes: IntArray, + modifierState: Int, + shortcut: Int + ) { + assertEquals(DEVICE_ID, deviceId) + lastShortcut = KeyboardSystemShortcut(keycodes, modifierState, shortcut) + } + } +}
\ No newline at end of file diff --git a/tests/Internal/Android.bp b/tests/Internal/Android.bp index 827ff4fbd989..ad98e47fa8f0 100644 --- a/tests/Internal/Android.bp +++ b/tests/Internal/Android.bp @@ -24,6 +24,7 @@ android_test { "flickerlib-parsers", "perfetto_trace_java_protos", "flickerlib-trace_processor_shell", + "ravenwood-junit", ], java_resource_dirs: ["res"], certificate: "platform", @@ -39,6 +40,7 @@ android_ravenwood_test { "platform-test-annotations", ], srcs: [ + "src/com/android/internal/graphics/ColorUtilsTest.java", "src/com/android/internal/util/ParcellingTests.java", ], auto_gen_config: true, diff --git a/tests/Internal/src/com/android/internal/graphics/ColorUtilsTest.java b/tests/Internal/src/com/android/internal/graphics/ColorUtilsTest.java index d0bb8e3745bc..38a22f2fc2f3 100644 --- a/tests/Internal/src/com/android/internal/graphics/ColorUtilsTest.java +++ b/tests/Internal/src/com/android/internal/graphics/ColorUtilsTest.java @@ -19,14 +19,19 @@ package com.android.internal.graphics; import static org.junit.Assert.assertTrue; import android.graphics.Color; +import android.platform.test.ravenwood.RavenwoodRule; import androidx.test.filters.SmallTest; +import org.junit.Rule; import org.junit.Test; @SmallTest public class ColorUtilsTest { + @Rule + public final RavenwoodRule mRavenwood = new RavenwoodRule(); + @Test public void calculateMinimumBackgroundAlpha_satisfiestContrast() { diff --git a/tests/Internal/src/com/android/internal/protolog/PerfettoProtoLogImplTest.java b/tests/Internal/src/com/android/internal/protolog/PerfettoProtoLogImplTest.java index fad94d45c85d..7d0c5966b5dc 100644 --- a/tests/Internal/src/com/android/internal/protolog/PerfettoProtoLogImplTest.java +++ b/tests/Internal/src/com/android/internal/protolog/PerfettoProtoLogImplTest.java @@ -126,30 +126,35 @@ public class PerfettoProtoLogImplTest { .setMessage("My Test Debug Log Message %b") .setLevel(ProtologCommon.ProtoLogLevel.PROTOLOG_LEVEL_DEBUG) .setGroupId(1) + .setLocation("com/test/MyTestClass.java:123") ).addMessages( Protolog.ProtoLogViewerConfig.MessageData.newBuilder() .setMessageId(2) .setMessage("My Test Verbose Log Message %b") .setLevel(ProtologCommon.ProtoLogLevel.PROTOLOG_LEVEL_VERBOSE) .setGroupId(1) + .setLocation("com/test/MyTestClass.java:342") ).addMessages( Protolog.ProtoLogViewerConfig.MessageData.newBuilder() .setMessageId(3) .setMessage("My Test Warn Log Message %b") .setLevel(ProtologCommon.ProtoLogLevel.PROTOLOG_LEVEL_WARN) .setGroupId(1) + .setLocation("com/test/MyTestClass.java:563") ).addMessages( Protolog.ProtoLogViewerConfig.MessageData.newBuilder() .setMessageId(4) .setMessage("My Test Error Log Message %b") .setLevel(ProtologCommon.ProtoLogLevel.PROTOLOG_LEVEL_ERROR) .setGroupId(1) + .setLocation("com/test/MyTestClass.java:156") ).addMessages( Protolog.ProtoLogViewerConfig.MessageData.newBuilder() .setMessageId(5) .setMessage("My Test WTF Log Message %b") .setLevel(ProtologCommon.ProtoLogLevel.PROTOLOG_LEVEL_WTF) .setGroupId(1) + .setLocation("com/test/MyTestClass.java:192") ); ViewerConfigInputStreamProvider viewerConfigInputStreamProvider = Mockito.mock( @@ -465,6 +470,26 @@ public class PerfettoProtoLogImplTest { .isEqualTo("My test message :: test, 2, 4, 6, 0.400000, true"); } + @Test + public void supportsLocationInformation() throws IOException { + PerfettoTraceMonitor traceMonitor = + PerfettoTraceMonitor.newBuilder().enableProtoLog(true).build(); + try { + traceMonitor.start(); + mProtoLog.log(LogLevel.DEBUG, TestProtoLogGroup.TEST_GROUP, 1, + LogDataType.BOOLEAN, new Object[]{true}); + } finally { + traceMonitor.stop(mWriter); + } + + final ResultReader reader = new ResultReader(mWriter.write(), mTraceConfig); + final ProtoLogTrace protolog = reader.readProtoLogTrace(); + + Truth.assertThat(protolog.messages).hasSize(1); + Truth.assertThat(protolog.messages.get(0).getLocation()) + .isEqualTo("com/test/MyTestClass.java:123"); + } + private long addMessageToConfig(ProtologCommon.ProtoLogLevel logLevel, String message) { final long messageId = new Random().nextLong(); mViewerConfigBuilder.addMessages(Protolog.ProtoLogViewerConfig.MessageData.newBuilder() diff --git a/tests/Internal/src/com/android/internal/protolog/ProtoLogCommandHandlerTest.java b/tests/Internal/src/com/android/internal/protolog/ProtoLogCommandHandlerTest.java new file mode 100644 index 000000000000..e3ec62d5b5a6 --- /dev/null +++ b/tests/Internal/src/com/android/internal/protolog/ProtoLogCommandHandlerTest.java @@ -0,0 +1,207 @@ +/* + * 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 com.android.internal.protolog; + +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.contains; +import static org.mockito.ArgumentMatchers.endsWith; +import static org.mockito.Mockito.atLeast; +import static org.mockito.Mockito.times; + +import android.platform.test.annotations.Presubmit; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnitRunner; + +import java.io.FileDescriptor; +import java.io.PrintWriter; + +/** + * Test class for {@link ProtoLogImpl}. + */ +@Presubmit +@RunWith(MockitoJUnitRunner.class) +public class ProtoLogCommandHandlerTest { + + @Mock + ProtoLogService mProtoLogService; + @Mock + PrintWriter mPrintWriter; + + @Test + public void printsHelpForAllAvailableCommands() { + final ProtoLogCommandHandler cmdHandler = + new ProtoLogCommandHandler(mProtoLogService, mPrintWriter); + + cmdHandler.onHelp(); + validateOnHelpPrinted(); + } + + @Test + public void printsHelpIfCommandIsNull() { + final ProtoLogCommandHandler cmdHandler = + new ProtoLogCommandHandler(mProtoLogService, mPrintWriter); + + cmdHandler.onCommand(null); + validateOnHelpPrinted(); + } + + @Test + public void handlesGroupListCommand() { + Mockito.when(mProtoLogService.getGroups()) + .thenReturn(new String[] {"MY_TEST_GROUP", "MY_OTHER_GROUP"}); + final ProtoLogCommandHandler cmdHandler = + new ProtoLogCommandHandler(mProtoLogService, mPrintWriter); + + cmdHandler.exec(mProtoLogService, FileDescriptor.in, FileDescriptor.out, FileDescriptor.err, + new String[] { "groups", "list" }); + + Mockito.verify(mPrintWriter, times(1)) + .println(contains("MY_TEST_GROUP")); + Mockito.verify(mPrintWriter, times(1)) + .println(contains("MY_OTHER_GROUP")); + } + + @Test + public void handlesIncompleteGroupsCommand() { + final ProtoLogCommandHandler cmdHandler = + new ProtoLogCommandHandler(mProtoLogService, mPrintWriter); + + cmdHandler.exec(mProtoLogService, FileDescriptor.in, FileDescriptor.out, FileDescriptor.err, + new String[] { "groups" }); + + Mockito.verify(mPrintWriter, times(1)) + .println(contains("Incomplete command")); + } + + @Test + public void handlesGroupStatusCommand() { + Mockito.when(mProtoLogService.getGroups()).thenReturn(new String[] {"MY_GROUP"}); + Mockito.when(mProtoLogService.isLoggingToLogcat("MY_GROUP")).thenReturn(true); + final ProtoLogCommandHandler cmdHandler = + new ProtoLogCommandHandler(mProtoLogService, mPrintWriter); + + cmdHandler.exec(mProtoLogService, FileDescriptor.in, FileDescriptor.out, FileDescriptor.err, + new String[] { "groups", "status", "MY_GROUP" }); + + Mockito.verify(mPrintWriter, times(1)) + .println(contains("MY_GROUP")); + Mockito.verify(mPrintWriter, times(1)) + .println(contains("LOG_TO_LOGCAT = true")); + } + + @Test + public void handlesGroupStatusCommandOfUnregisteredGroups() { + Mockito.when(mProtoLogService.getGroups()).thenReturn(new String[] {}); + final ProtoLogCommandHandler cmdHandler = + new ProtoLogCommandHandler(mProtoLogService, mPrintWriter); + + cmdHandler.exec(mProtoLogService, FileDescriptor.in, FileDescriptor.out, FileDescriptor.err, + new String[] { "groups", "status", "MY_GROUP" }); + + Mockito.verify(mPrintWriter, times(1)) + .println(contains("MY_GROUP")); + Mockito.verify(mPrintWriter, times(1)) + .println(contains("UNREGISTERED")); + } + + @Test + public void handlesGroupStatusCommandWithNoGroups() { + final ProtoLogCommandHandler cmdHandler = + new ProtoLogCommandHandler(mProtoLogService, mPrintWriter); + + cmdHandler.exec(mProtoLogService, FileDescriptor.in, FileDescriptor.out, FileDescriptor.err, + new String[] { "groups", "status" }); + + Mockito.verify(mPrintWriter, times(1)) + .println(contains("Incomplete command")); + } + + @Test + public void handlesIncompleteLogcatCommand() { + final ProtoLogCommandHandler cmdHandler = + new ProtoLogCommandHandler(mProtoLogService, mPrintWriter); + + cmdHandler.exec(mProtoLogService, FileDescriptor.in, FileDescriptor.out, FileDescriptor.err, + new String[] { "logcat" }); + + Mockito.verify(mPrintWriter, times(1)) + .println(contains("Incomplete command")); + } + + @Test + public void handlesLogcatEnableCommand() { + final ProtoLogCommandHandler cmdHandler = + new ProtoLogCommandHandler(mProtoLogService, mPrintWriter); + + cmdHandler.exec(mProtoLogService, FileDescriptor.in, FileDescriptor.out, FileDescriptor.err, + new String[] { "logcat", "enable", "MY_GROUP" }); + Mockito.verify(mProtoLogService).enableProtoLogToLogcat("MY_GROUP"); + + cmdHandler.exec(mProtoLogService, FileDescriptor.in, FileDescriptor.out, FileDescriptor.err, + new String[] { "logcat", "enable", "MY_GROUP", "MY_OTHER_GROUP" }); + Mockito.verify(mProtoLogService) + .enableProtoLogToLogcat("MY_GROUP", "MY_OTHER_GROUP"); + } + + @Test + public void handlesLogcatDisableCommand() { + final ProtoLogCommandHandler cmdHandler = + new ProtoLogCommandHandler(mProtoLogService, mPrintWriter); + + cmdHandler.exec(mProtoLogService, FileDescriptor.in, FileDescriptor.out, FileDescriptor.err, + new String[] { "logcat", "disable", "MY_GROUP" }); + Mockito.verify(mProtoLogService).disableProtoLogToLogcat("MY_GROUP"); + + cmdHandler.exec(mProtoLogService, FileDescriptor.in, FileDescriptor.out, FileDescriptor.err, + new String[] { "logcat", "disable", "MY_GROUP", "MY_OTHER_GROUP" }); + Mockito.verify(mProtoLogService) + .disableProtoLogToLogcat("MY_GROUP", "MY_OTHER_GROUP"); + } + + @Test + public void handlesLogcatEnableCommandWithNoGroups() { + final ProtoLogCommandHandler cmdHandler = + new ProtoLogCommandHandler(mProtoLogService, mPrintWriter); + + cmdHandler.exec(mProtoLogService, FileDescriptor.in, FileDescriptor.out, FileDescriptor.err, + new String[] { "logcat", "enable" }); + Mockito.verify(mPrintWriter).println(contains("Incomplete command")); + } + + @Test + public void handlesLogcatDisableCommandWithNoGroups() { + final ProtoLogCommandHandler cmdHandler = + new ProtoLogCommandHandler(mProtoLogService, mPrintWriter); + + cmdHandler.exec(mProtoLogService, FileDescriptor.in, FileDescriptor.out, FileDescriptor.err, + new String[] { "logcat", "disable" }); + Mockito.verify(mPrintWriter).println(contains("Incomplete command")); + } + + private void validateOnHelpPrinted() { + Mockito.verify(mPrintWriter, times(1)).println(endsWith("help")); + Mockito.verify(mPrintWriter, times(1)) + .println(endsWith("groups (list | status)")); + Mockito.verify(mPrintWriter, times(1)) + .println(endsWith("logcat (enable | disable) <group>")); + Mockito.verify(mPrintWriter, atLeast(0)).println(anyString()); + } +} diff --git a/tests/Internal/src/com/android/internal/protolog/ProtoLogServiceTest.java b/tests/Internal/src/com/android/internal/protolog/ProtoLogServiceTest.java new file mode 100644 index 000000000000..feac59c702ea --- /dev/null +++ b/tests/Internal/src/com/android/internal/protolog/ProtoLogServiceTest.java @@ -0,0 +1,283 @@ +/* + * 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 com.android.internal.protolog; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.never; + +import static java.io.File.createTempFile; +import static java.nio.file.Files.createTempDirectory; + +import android.os.IBinder; +import android.os.RemoteException; +import android.platform.test.annotations.Presubmit; +import android.tools.ScenarioBuilder; +import android.tools.Tag; +import android.tools.io.ResultArtifactDescriptor; +import android.tools.io.TraceType; +import android.tools.traces.TraceConfig; +import android.tools.traces.TraceConfigs; +import android.tools.traces.io.ResultReader; +import android.tools.traces.io.ResultWriter; +import android.tools.traces.monitors.PerfettoTraceMonitor; + +import com.google.common.truth.Truth; +import com.google.protobuf.InvalidProtocolBufferException; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnitRunner; + +import perfetto.protos.Protolog.ProtoLogViewerConfig; +import perfetto.protos.ProtologCommon; +import perfetto.protos.TraceOuterClass.Trace; +import perfetto.protos.TracePacketOuterClass.TracePacket; + +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.List; + +/** + * Test class for {@link ProtoLogImpl}. + */ +@Presubmit +@RunWith(MockitoJUnitRunner.class) +public class ProtoLogServiceTest { + + private static final String TEST_GROUP = "MY_TEST_GROUP"; + private static final String OTHER_TEST_GROUP = "MY_OTHER_TEST_GROUP"; + + private static final ProtoLogViewerConfig VIEWER_CONFIG = + ProtoLogViewerConfig.newBuilder() + .addGroups( + ProtoLogViewerConfig.Group.newBuilder() + .setId(1) + .setName(TEST_GROUP) + .setTag(TEST_GROUP) + ).addMessages( + ProtoLogViewerConfig.MessageData.newBuilder() + .setMessageId(1) + .setMessage("My Test Debug Log Message %b") + .setLevel(ProtologCommon.ProtoLogLevel.PROTOLOG_LEVEL_DEBUG) + .setGroupId(1) + ).addMessages( + ProtoLogViewerConfig.MessageData.newBuilder() + .setMessageId(2) + .setMessage("My Test Verbose Log Message %b") + .setLevel(ProtologCommon.ProtoLogLevel.PROTOLOG_LEVEL_VERBOSE) + .setGroupId(1) + ).build(); + + @Mock + IProtoLogClient mMockClient; + + @Mock + IProtoLogClient mSecondMockClient; + + @Mock + IBinder mMockClientBinder; + + @Mock + IBinder mSecondMockClientBinder; + + private final File mTracingDirectory = createTempDirectory("temp").toFile(); + + private final ResultWriter mWriter = new ResultWriter() + .forScenario(new ScenarioBuilder() + .forClass(createTempFile("temp", "").getName()).build()) + .withOutputDir(mTracingDirectory) + .setRunComplete(); + + private final TraceConfigs mTraceConfig = new TraceConfigs( + new TraceConfig(false, true, false), + new TraceConfig(false, true, false), + new TraceConfig(false, true, false), + new TraceConfig(false, true, false) + ); + + @Captor + ArgumentCaptor<IBinder.DeathRecipient> mDeathRecipientArgumentCaptor; + + @Captor + ArgumentCaptor<IBinder.DeathRecipient> mSecondDeathRecipientArgumentCaptor; + + private File mViewerConfigFile; + + public ProtoLogServiceTest() throws IOException { + } + + @Before + public void setUp() { + Mockito.when(mMockClient.asBinder()).thenReturn(mMockClientBinder); + Mockito.when(mSecondMockClient.asBinder()).thenReturn(mSecondMockClientBinder); + + try { + mViewerConfigFile = File.createTempFile("viewer-config", ".pb"); + try (var fos = new FileOutputStream(mViewerConfigFile); + BufferedOutputStream bos = new BufferedOutputStream(fos)) { + + bos.write(VIEWER_CONFIG.toByteArray()); + } + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + @Test + public void canRegisterClientWithGroupsOnly() throws RemoteException { + final ProtoLogService service = new ProtoLogService(); + + final ProtoLogService.RegisterClientArgs args = new ProtoLogService.RegisterClientArgs() + .setGroups(new ProtoLogService.RegisterClientArgs.GroupConfig(TEST_GROUP, true)); + service.registerClient(mMockClient, args); + + Truth.assertThat(service.isLoggingToLogcat(TEST_GROUP)).isTrue(); + Truth.assertThat(service.getGroups()).asList().containsExactly(TEST_GROUP); + } + + @Test + public void willDumpViewerConfigOnlyOnceOnTraceStop() + throws RemoteException, InvalidProtocolBufferException { + final ProtoLogService service = new ProtoLogService(); + + final ProtoLogService.RegisterClientArgs args = new ProtoLogService.RegisterClientArgs() + .setGroups(new ProtoLogService.RegisterClientArgs.GroupConfig(TEST_GROUP, true)) + .setViewerConfigFile(mViewerConfigFile.getAbsolutePath()); + service.registerClient(mMockClient, args); + service.registerClient(mSecondMockClient, args); + + PerfettoTraceMonitor traceMonitor = + PerfettoTraceMonitor.newBuilder().enableProtoLog().build(); + + traceMonitor.start(); + traceMonitor.stop(mWriter); + final ResultReader reader = new ResultReader(mWriter.write(), mTraceConfig); + final byte[] traceData = reader.getArtifact() + .readBytes(new ResultArtifactDescriptor(TraceType.PERFETTO, Tag.ALL)); + + final Trace trace = Trace.parseFrom(traceData); + + final List<TracePacket> configPackets = trace.getPacketList().stream() + .filter(it -> it.hasProtologViewerConfig()) + // Exclude viewer configs from regular system tracing + .filter(it -> + it.getProtologViewerConfig().getGroups(0).getName().equals(TEST_GROUP)) + .toList(); + Truth.assertThat(configPackets).hasSize(1); + Truth.assertThat(configPackets.get(0).getProtologViewerConfig().toString()) + .isEqualTo(VIEWER_CONFIG.toString()); + } + + @Test + public void willDumpViewerConfigOnLastClientDisconnected() + throws RemoteException, FileNotFoundException { + final ProtoLogService.ViewerConfigFileTracer tracer = + Mockito.mock(ProtoLogService.ViewerConfigFileTracer.class); + final ProtoLogService service = new ProtoLogService(tracer); + + final ProtoLogService.RegisterClientArgs args = new ProtoLogService.RegisterClientArgs() + .setGroups(new ProtoLogService.RegisterClientArgs.GroupConfig( + TEST_GROUP, true)) + .setViewerConfigFile(mViewerConfigFile.getAbsolutePath()); + service.registerClient(mMockClient, args); + service.registerClient(mSecondMockClient, args); + + Mockito.verify(mMockClientBinder) + .linkToDeath(mDeathRecipientArgumentCaptor.capture(), anyInt()); + Mockito.verify(mSecondMockClientBinder) + .linkToDeath(mSecondDeathRecipientArgumentCaptor.capture(), anyInt()); + + mDeathRecipientArgumentCaptor.getValue().binderDied(); + Mockito.verify(tracer, never()).trace(any(), any()); + mSecondDeathRecipientArgumentCaptor.getValue().binderDied(); + Mockito.verify(tracer).trace(any(), eq(mViewerConfigFile.getAbsolutePath())); + } + + @Test + public void sendEnableLoggingToLogcatToClient() throws RemoteException { + final var service = new ProtoLogService(); + + final var args = new ProtoLogService.RegisterClientArgs() + .setGroups(new ProtoLogService.RegisterClientArgs.GroupConfig(TEST_GROUP, false)); + service.registerClient(mMockClient, args); + + Truth.assertThat(service.isLoggingToLogcat(TEST_GROUP)).isFalse(); + service.enableProtoLogToLogcat(TEST_GROUP); + Truth.assertThat(service.isLoggingToLogcat(TEST_GROUP)).isTrue(); + + Mockito.verify(mMockClient).toggleLogcat(eq(true), + Mockito.argThat(it -> it.length == 1 && it[0].equals(TEST_GROUP))); + } + + @Test + public void sendDisableLoggingToLogcatToClient() throws RemoteException { + final ProtoLogService service = new ProtoLogService(); + + final ProtoLogService.RegisterClientArgs args = new ProtoLogService.RegisterClientArgs() + .setGroups(new ProtoLogService.RegisterClientArgs.GroupConfig(TEST_GROUP, true)); + service.registerClient(mMockClient, args); + + Truth.assertThat(service.isLoggingToLogcat(TEST_GROUP)).isTrue(); + service.disableProtoLogToLogcat(TEST_GROUP); + Truth.assertThat(service.isLoggingToLogcat(TEST_GROUP)).isFalse(); + + Mockito.verify(mMockClient).toggleLogcat(eq(false), + Mockito.argThat(it -> it.length == 1 && it[0].equals(TEST_GROUP))); + } + + @Test + public void doNotSendLoggingToLogcatToClientWithoutRegisteredGroup() throws RemoteException { + final ProtoLogService service = new ProtoLogService(); + + final ProtoLogService.RegisterClientArgs args = new ProtoLogService.RegisterClientArgs() + .setGroups(new ProtoLogService.RegisterClientArgs.GroupConfig(TEST_GROUP, false)); + service.registerClient(mMockClient, args); + + Truth.assertThat(service.isLoggingToLogcat(TEST_GROUP)).isFalse(); + service.enableProtoLogToLogcat(OTHER_TEST_GROUP); + Truth.assertThat(service.isLoggingToLogcat(TEST_GROUP)).isFalse(); + + Mockito.verify(mMockClient, never()).toggleLogcat(anyBoolean(), any()); + } + + @Test + public void handlesToggleToLogcatBeforeClientIsRegistered() throws RemoteException { + final ProtoLogService service = new ProtoLogService(); + + Truth.assertThat(service.getGroups()).asList().doesNotContain(TEST_GROUP); + service.enableProtoLogToLogcat(TEST_GROUP); + Truth.assertThat(service.isLoggingToLogcat(TEST_GROUP)).isTrue(); + + final ProtoLogService.RegisterClientArgs args = new ProtoLogService.RegisterClientArgs() + .setGroups(new ProtoLogService.RegisterClientArgs.GroupConfig(TEST_GROUP, false)); + service.registerClient(mMockClient, args); + + Mockito.verify(mMockClient).toggleLogcat(eq(true), + Mockito.argThat(it -> it.length == 1 && it[0].equals(TEST_GROUP))); + } +} diff --git a/tests/Internal/src/com/android/internal/util/ParcellingTests.java b/tests/Internal/src/com/android/internal/util/ParcellingTests.java index 65a3436a4c5e..fb63422cdf9f 100644 --- a/tests/Internal/src/com/android/internal/util/ParcellingTests.java +++ b/tests/Internal/src/com/android/internal/util/ParcellingTests.java @@ -18,6 +18,7 @@ package com.android.internal.util; import android.os.Parcel; import android.platform.test.annotations.Presubmit; +import android.platform.test.ravenwood.RavenwoodRule; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; @@ -26,6 +27,7 @@ import androidx.test.filters.SmallTest; import com.android.internal.util.Parcelling.BuiltIn.ForInstant; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -38,6 +40,9 @@ import java.time.Instant; @RunWith(JUnit4.class) public class ParcellingTests { + @Rule + public final RavenwoodRule mRavenwood = new RavenwoodRule(); + private Parcel mParcel = Parcel.obtain(); @Test |