summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/AccessibilityEventsLogger/AndroidManifest.xml41
-rw-r--r--tests/AccessoryDisplay/sink/AndroidManifest.xml21
-rw-r--r--tests/AccessoryDisplay/sink/src/com/android/accessorydisplay/sink/SinkActivity.java2
-rw-r--r--tests/AccessoryDisplay/source/AndroidManifest.xml21
-rw-r--r--tests/ActivityManagerPerfTests/stub-app/AndroidManifest.xml45
-rw-r--r--tests/ActivityManagerPerfTests/tests/Android.bp1
-rw-r--r--tests/ActivityManagerPerfTests/tests/AndroidTest.xml17
-rw-r--r--tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/OomAdjPerfTest.java10
-rw-r--r--tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/ServiceStartPerfTest.java16
-rw-r--r--tests/ActivityTests/AndroidManifest.xml107
-rw-r--r--tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java6
-rw-r--r--tests/ActivityViewTest/AndroidManifest.xml66
-rw-r--r--tests/ActivityViewTest/res/layout/activity_view_activity.xml47
-rw-r--r--tests/ActivityViewTest/res/layout/activity_view_resize_activity.xml51
-rw-r--r--tests/ActivityViewTest/res/layout/activity_view_scroll_activity.xml57
-rw-r--r--tests/ActivityViewTest/res/layout/activity_view_test_activity.xml70
-rw-r--r--tests/ActivityViewTest/res/layout/activity_view_visibility_activity.xml46
-rw-r--r--tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewActivity.java56
-rw-r--r--tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewMainActivity.java42
-rw-r--r--tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewResizeActivity.java79
-rw-r--r--tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewScrollActivity.java44
-rw-r--r--tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewTestActivity.java116
-rw-r--r--tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewVisibilityActivity.java75
-rw-r--r--tests/AmSlam/AndroidManifest.xml425
-rw-r--r--tests/ApkVerityTest/Android.bp4
-rw-r--r--tests/ApkVerityTest/block_device_writer/Android.bp6
-rw-r--r--tests/ApkVerityTest/block_device_writer/src/com/android/blockdevicewriter/BlockDeviceWriter.java100
-rw-r--r--tests/ApkVerityTest/src/com/android/apkverity/ApkVerityTest.java210
-rw-r--r--tests/AppResourcesLoaders/AndroidManifest.xml13
-rw-r--r--tests/Assist/AndroidManifest.xml38
-rw-r--r--tests/AutoVerify/app1/Android.bp20
-rw-r--r--tests/AutoVerify/app1/AndroidManifest.xml43
-rw-r--r--tests/AutoVerify/app1/res/values/strings.xml21
-rw-r--r--tests/AutoVerify/app2/Android.bp20
-rw-r--r--tests/AutoVerify/app2/AndroidManifest.xml44
-rw-r--r--tests/AutoVerify/app2/res/values/strings.xml21
-rw-r--r--tests/AutoVerify/app3/Android.bp20
-rw-r--r--tests/AutoVerify/app3/AndroidManifest.xml44
-rw-r--r--tests/AutoVerify/app3/res/values/strings.xml21
-rw-r--r--tests/AutoVerify/app4/Android.bp20
-rw-r--r--tests/AutoVerify/app4/res/values/strings.xml21
-rw-r--r--tests/BandwidthTests/AndroidManifest.xml19
-rw-r--r--tests/BatteryStatsPerfTest/Android.bp34
-rw-r--r--tests/BatteryStatsPerfTest/AndroidManifest.xml27
-rw-r--r--tests/BatteryStatsPerfTest/AndroidTest.xml28
-rw-r--r--tests/BatteryStatsPerfTest/src/com/android/internal/os/BatteryStatsHelperPerfTest.java135
-rw-r--r--tests/BatteryStatsPerfTest/src/com/android/internal/os/BatteryUsageStatsPerfTest.java74
-rw-r--r--tests/BatteryWaster/AndroidManifest.xml18
-rw-r--r--tests/BiDiTests/AndroidManifest.xml19
-rw-r--r--tests/BlobStoreTestUtils/src/com/android/utils/blob/Utils.java11
-rw-r--r--tests/BrowserPowerTest/AndroidManifest.xml37
-rw-r--r--tests/Camera2Tests/CameraToo/AndroidManifest.xml17
-rw-r--r--tests/Camera2Tests/SmartCamera/SimpleCamera/AndroidManifest.xml25
-rw-r--r--tests/CameraPrewarmTest/AndroidManifest.xml28
-rw-r--r--tests/CanvasCompare/AndroidManifest.xml40
-rw-r--r--tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassBase.java8
-rw-r--r--tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassChild.java8
-rw-r--r--tests/Codegen/src/com/android/codegentest/ParcelAllTheThingsDataClass.java8
-rw-r--r--tests/Codegen/src/com/android/codegentest/SampleDataClass.java208
-rw-r--r--tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java8
-rw-r--r--tests/Codegen/src/com/android/codegentest/SampleWithNestedDataClasses.java18
-rw-r--r--tests/Codegen/src/com/android/codegentest/StaleDataclassDetectorFalsePositivesTest.java32
-rw-r--r--tests/DozeTest/src/com/android/dreams/dozetest/DozeTestDream.java2
-rw-r--r--tests/DpiTest/AndroidManifest.xml34
-rw-r--r--tests/DpiTest/src/com/google/android/test/dpi/DpiTestActivity.java24
-rw-r--r--tests/FeatureSplit/base/AndroidManifest.xml12
-rw-r--r--tests/FeatureSplit/feature1/AndroidManifest.xml16
-rw-r--r--tests/FixVibrateSetting/AndroidManifest.xml16
-rw-r--r--tests/FlickerTests/Android.bp40
-rw-r--r--tests/FlickerTests/AndroidManifest.xml16
-rw-r--r--tests/FlickerTests/AndroidTest.xml13
-rw-r--r--tests/FlickerTests/README.md190
-rw-r--r--tests/FlickerTests/TEST_MAPPING13
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ChangeAppRotationTest.java175
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/CloseImeAutoOpenWindowToAppTest.java77
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/CloseImeAutoOpenWindowToHomeTest.java69
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/CloseImeWindowToAppTest.java78
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/CloseImeWindowToHomeTest.java94
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt223
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/CommonTransitions.java339
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/DebugTest.java190
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/FlickerTestBase.java142
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/NonRotationTestBase.java80
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/OpenAppColdTest.java97
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/OpenAppToSplitScreenTest.java83
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/OpenAppWarmTest.java97
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/OpenImeWindowTest.java73
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/PipToAppTest.java89
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/PipToHomeTest.java93
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ResizeSplitScreenTest.java186
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/SeamlessAppRotationTest.java177
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/SplitScreenToLauncherTest.java100
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt57
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt57
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt142
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FlickerAppHelper.java31
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FlickerExtensions.kt (renamed from tests/AutoVerify/app4/src/com/android/test/autoverify/MainActivity.java)13
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppAutoFocusHelper.java31
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppAutoFocusHelper.kt48
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppHelper.java41
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppHelper.kt84
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/helpers/PipAppHelper.java47
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/helpers/SeamlessRotationAppHelper.kt32
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/helpers/SimpleAppHelper.kt32
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt153
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt162
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt159
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt167
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/CommonAssertions.kt141
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt165
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt178
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/SwitchImeWindowsFromGestureNavTest.kt143
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/launch/CommonAssertions.kt29
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt109
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt104
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt154
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt88
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt104
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/rotation/RotationTransition.kt159
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt133
-rw-r--r--tests/FlickerTests/test-apps/flickerapp/Android.bp2
-rw-r--r--tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml52
-rw-r--r--tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java22
-rw-r--r--tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/PipActivity.java45
-rw-r--r--tests/FrameworkPerf/AndroidManifest.xml33
-rw-r--r--tests/FrameworkPerf/src/com/android/frameworkperf/SchedulerService.java2
-rw-r--r--tests/GamePerformance/Android.bp2
-rw-r--r--tests/GamePerformance/AndroidManifest.xml26
-rw-r--r--tests/GridLayoutTest/AndroidManifest.xml42
-rw-r--r--tests/HierarchyViewerTest/AndroidManifest.xml20
-rw-r--r--tests/HugeBackup/AndroidManifest.xml22
-rw-r--r--tests/HwAccelerationTest/AndroidManifest.xml1288
-rw-r--r--tests/HwAccelerationTest/res/layout/image_filter_activity.xml28
-rw-r--r--tests/HwAccelerationTest/res/layout/scrolling_stretch_surfaceview.xml76
-rw-r--r--tests/HwAccelerationTest/res/layout/stretch_layout.xml86
-rw-r--r--tests/HwAccelerationTest/src/com/android/test/hwui/BlurActivity.java162
-rw-r--r--tests/HwAccelerationTest/src/com/android/test/hwui/ColorFiltersMutateActivity.java35
-rw-r--r--tests/HwAccelerationTest/src/com/android/test/hwui/EdgeEffectStretchActivity.java (renamed from tests/AutoVerify/app1/src/com/android/test/autoverify/MainActivity.java)16
-rw-r--r--tests/HwAccelerationTest/src/com/android/test/hwui/PictureCaptureDemo.java62
-rw-r--r--tests/HwAccelerationTest/src/com/android/test/hwui/PositionListenerActivity.java87
-rw-r--r--tests/HwAccelerationTest/src/com/android/test/hwui/RenderEffectShaderActivity.java107
-rw-r--r--tests/HwAccelerationTest/src/com/android/test/hwui/RippleActivity.java186
-rw-r--r--tests/HwAccelerationTest/src/com/android/test/hwui/ScrollingStretchSurfaceViewActivity.java113
-rw-r--r--tests/HwAccelerationTest/src/com/android/test/hwui/StretchShaderActivity.java537
-rw-r--r--tests/HwAccelerationTest/src/com/android/test/hwui/StretchySurfaceViewActivity.java158
-rw-r--r--tests/Input/Android.bp (renamed from tests/ActivityViewTest/Android.bp)14
-rw-r--r--tests/Input/AndroidManifest.xml34
-rw-r--r--tests/Input/AndroidTest.xml25
-rw-r--r--tests/Input/TEST_MAPPING7
-rw-r--r--tests/Input/src/com/android/test/input/AnrTest.kt115
-rw-r--r--tests/Input/src/com/android/test/input/InputDeviceTest.java98
-rw-r--r--tests/Input/src/com/android/test/input/InputEventAssignerTest.kt130
-rw-r--r--tests/Input/src/com/android/test/input/InputEventSenderAndReceiverTest.kt165
-rw-r--r--tests/Input/src/com/android/test/input/UnresponsiveGestureMonitorActivity.kt52
-rw-r--r--tests/Input/src/com/android/test/input/ViewFrameInfoTest.kt72
-rw-r--r--tests/Internal/Android.bp1
-rw-r--r--tests/Internal/AndroidManifest.xml25
-rw-r--r--tests/Internal/src/android/app/WallpaperColorsTest.java25
-rw-r--r--tests/Internal/src/com/android/internal/protolog/ProtoLogImplTest.java462
-rw-r--r--tests/Internal/src/com/android/internal/protolog/ProtoLogViewerConfigReaderTest.java114
-rw-r--r--tests/Internal/src/com/android/internal/protolog/common/LogDataTypeTest.java85
-rw-r--r--tests/JankBench/app/src/main/AndroidManifest.xml67
-rw-r--r--tests/JobSchedulerTestApp/AndroidManifest.xml38
-rw-r--r--tests/LargeAssetTest/AndroidManifest.xml14
-rw-r--r--tests/LegacyAssistant/AndroidManifest.xml11
-rw-r--r--tests/LocationTracker/AndroidManifest.xml29
-rw-r--r--tests/LockTaskTests/AndroidManifest.xml79
-rw-r--r--tests/LotsOfApps/AndroidManifest.xml1014
-rw-r--r--tests/LowStorageTest/AndroidManifest.xml12
-rw-r--r--tests/ManagedProfileLifecycleStressTest/app/DummyDPC/AndroidManifest.xml15
-rw-r--r--tests/ManagedProfileLifecycleStressTest/src/com/android/test/stress/ManagedProfileLifecycleStressTest.java52
-rw-r--r--tests/MirrorSurfaceTest/AndroidManifest.xml9
-rw-r--r--tests/NullHomeTest/Android.bp2
-rw-r--r--tests/NullHomeTest/AndroidManifest.xml2
-rw-r--r--tests/NullHomeTest/src/com/android/test/nullhome/NullHomeTest.java3
-rw-r--r--tests/OneMedia/AndroidManifest.xml40
-rw-r--r--tests/OneMedia/src/com/android/onemedia/NotificationHelper.java12
-rw-r--r--tests/PackageWatchdog/TEST_MAPPING7
-rw-r--r--tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java280
-rw-r--r--tests/PlatformCompatGating/src/com/android/tests/gating/PlatformCompatPermissionsTest.java13
-rw-r--r--tests/PlatformCompatGating/test-rules/src/android/compat/testing/PlatformCompatChangeRule.java15
-rw-r--r--tests/RenderThreadTest/AndroidManifest.xml28
-rw-r--r--tests/RollbackTest/Android.bp1
-rw-r--r--tests/RollbackTest/MultiUserRollbackTest.xml2
-rw-r--r--tests/RollbackTest/MultiUserRollbackTest/src/com/android/tests/rollback/host/MultiUserRollbackTest.java11
-rw-r--r--tests/RollbackTest/NetworkStagedRollbackTest.xml2
-rw-r--r--tests/RollbackTest/NetworkStagedRollbackTest/src/com/android/tests/rollback/host/NetworkStagedRollbackTest.java15
-rw-r--r--tests/RollbackTest/RollbackTest.xml2
-rw-r--r--tests/RollbackTest/RollbackTest/AndroidManifest.xml2
-rw-r--r--tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/MultiUserRollbackTest.java5
-rw-r--r--tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java54
-rw-r--r--tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java155
-rw-r--r--tests/RollbackTest/StagedRollbackTest.xml2
-rw-r--r--tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java421
-rw-r--r--tests/RollbackTest/lib/src/com/android/tests/rollback/host/WatchdogEventLogger.java120
-rw-r--r--tests/SerialChat/AndroidManifest.xml12
-rw-r--r--tests/ServiceCrashTest/AndroidManifest.xml15
-rw-r--r--tests/SharedLibrary/client/AndroidManifest.xml23
-rw-r--r--tests/SharedLibrary/lib/AndroidManifest.xml13
-rw-r--r--tests/ShowWhenLockedApp/AndroidManifest.xml9
-rw-r--r--tests/SilkFX/Android.bp37
-rw-r--r--tests/SilkFX/AndroidManifest.xml (renamed from tests/AutoVerify/app4/AndroidManifest.xml)46
-rw-r--r--tests/SilkFX/res/drawable-hdpi/background1.jpegbin0 -> 200459 bytes
-rw-r--r--tests/SilkFX/res/drawable-hdpi/background2.jpegbin0 -> 110703 bytes
-rw-r--r--tests/SilkFX/res/drawable-hdpi/background3.jpegbin0 -> 318853 bytes
-rw-r--r--tests/SilkFX/res/drawable-hdpi/noise.pngbin0 -> 494875 bytes
-rw-r--r--tests/SilkFX/res/drawable-nodpi/dark_notification.pngbin0 -> 42263 bytes
-rw-r--r--tests/SilkFX/res/drawable-nodpi/light_notification.pngbin0 -> 37096 bytes
-rw-r--r--tests/SilkFX/res/layout-television/activity_glass.xml302
-rw-r--r--tests/SilkFX/res/layout/activity_glass.xml303
-rw-r--r--tests/SilkFX/res/layout/bling_notifications.xml35
-rw-r--r--tests/SilkFX/res/layout/color_mode_controls.xml64
-rw-r--r--tests/SilkFX/res/layout/common_base.xml39
-rw-r--r--tests/SilkFX/res/layout/hdr_glows.xml51
-rw-r--r--tests/SilkFX/src/com/android/test/silkfx/Main.kt129
-rw-r--r--tests/SilkFX/src/com/android/test/silkfx/app/BaseDemoActivity.kt77
-rw-r--r--tests/SilkFX/src/com/android/test/silkfx/app/CommonDemoActivity.kt45
-rw-r--r--tests/SilkFX/src/com/android/test/silkfx/app/WindowObserver.kt (renamed from tests/AutoVerify/app3/src/com/android/test/autoverify/MainActivity.java)8
-rw-r--r--tests/SilkFX/src/com/android/test/silkfx/common/BaseDrawingView.kt43
-rw-r--r--tests/SilkFX/src/com/android/test/silkfx/common/ColorModeControls.kt150
-rw-r--r--tests/SilkFX/src/com/android/test/silkfx/common/HDRIndicator.kt50
-rw-r--r--tests/SilkFX/src/com/android/test/silkfx/hdr/BlingyNotification.kt99
-rw-r--r--tests/SilkFX/src/com/android/test/silkfx/hdr/GlowActivity.kt (renamed from tests/AutoVerify/app2/src/com/android/test/autoverify/MainActivity.java)14
-rw-r--r--tests/SilkFX/src/com/android/test/silkfx/hdr/GlowingCard.kt85
-rw-r--r--tests/SilkFX/src/com/android/test/silkfx/hdr/RadialGlow.kt91
-rw-r--r--tests/SilkFX/src/com/android/test/silkfx/materials/GlassActivity.kt162
-rw-r--r--tests/SilkFX/src/com/android/test/silkfx/materials/GlassView.kt230
-rw-r--r--tests/SmokeTest/AndroidManifest.xml15
-rw-r--r--tests/SmokeTestApps/AndroidManifest.xml23
-rw-r--r--tests/SoundTriggerTestApp/AndroidManifest.xml37
-rw-r--r--tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerTestService.java22
-rw-r--r--tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerUtil.java35
-rw-r--r--tests/Split/AndroidManifest.xml11
-rw-r--r--tests/StagedInstallTest/Android.bp7
-rw-r--r--tests/StagedInstallTest/TEST_MAPPING2
-rw-r--r--tests/StagedInstallTest/app/AndroidManifest.xml2
-rw-r--r--tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java313
-rw-r--r--tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java287
-rw-r--r--tests/StatusBar/AndroidManifest.xml78
-rw-r--r--tests/StatusBar/src/com/android/statusbartest/NotificationBuilderTest.java4
-rw-r--r--tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java20
-rw-r--r--tests/StatusBar/src/com/android/statusbartest/StatusBarTest.java2
-rw-r--r--tests/SurfaceComposition/AndroidManifest.xml17
-rw-r--r--tests/SurfaceControlViewHostTest/AndroidManifest.xml6
-rw-r--r--tests/SurfaceControlViewHostTest/src/com/android/test/viewembed/SurfaceControlViewHostTest.java8
-rw-r--r--tests/SurfaceViewBufferTests/Android.bp70
-rw-r--r--tests/SurfaceViewBufferTests/AndroidManifest.xml57
-rw-r--r--tests/SurfaceViewBufferTests/AndroidTest.xml35
-rw-r--r--tests/SurfaceViewBufferTests/OWNERS1
-rw-r--r--tests/SurfaceViewBufferTests/cpp/SurfaceProxy.cpp248
-rw-r--r--tests/SurfaceViewBufferTests/res/values/styles.xml (renamed from tests/FlickerTests/test-apps/flickerapp/res/layout/activity_pip.xml)21
-rw-r--r--tests/SurfaceViewBufferTests/src/com/android/test/BufferPresentationTests.kt173
-rw-r--r--tests/SurfaceViewBufferTests/src/com/android/test/BufferRejectionTests.kt152
-rw-r--r--tests/SurfaceViewBufferTests/src/com/android/test/GeometryTests.kt224
-rw-r--r--tests/SurfaceViewBufferTests/src/com/android/test/InverseDisplayTransformTests.kt76
-rw-r--r--tests/SurfaceViewBufferTests/src/com/android/test/MainActivity.kt141
-rw-r--r--tests/SurfaceViewBufferTests/src/com/android/test/ScreenRecordTestBase.kt83
-rw-r--r--tests/SurfaceViewBufferTests/src/com/android/test/SharedBufferModeScreenRecordTests.kt67
-rw-r--r--tests/SurfaceViewBufferTests/src/com/android/test/SharedBufferModeTests.kt90
-rw-r--r--tests/SurfaceViewBufferTests/src/com/android/test/SurfaceProxy.kt67
-rw-r--r--tests/SurfaceViewBufferTests/src/com/android/test/SurfaceTracingTestBase.kt120
-rw-r--r--tests/SurfaceViewBufferTests/src/com/android/test/SurfaceViewBufferTestBase.kt97
-rw-r--r--tests/SystemUIDemoModeController/AndroidManifest.xml26
-rw-r--r--tests/TaskOrganizerTest/Android.bp17
-rw-r--r--tests/TaskOrganizerTest/AndroidManifest.xml43
-rw-r--r--tests/TaskOrganizerTest/AndroidTest.xml35
-rw-r--r--tests/TaskOrganizerTest/src/com/android/test/taskembed/ResizeTasksSyncTest.kt111
-rw-r--r--tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerMultiWindowTest.java255
-rw-r--r--tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerPipTest.java82
-rw-r--r--tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskView.java106
-rw-r--r--tests/TelephonyCommonTests/src/com/android/internal/telephony/tests/SmsApplicationTest.java7
-rw-r--r--tests/TouchLatency/app/src/main/AndroidManifest.xml21
-rw-r--r--tests/TouchLatency/gradle/wrapper/gradle-wrapper.jarbin49896 -> 54417 bytes
-rw-r--r--tests/TouchLatency/gradle/wrapper/gradle-wrapper.properties3
-rwxr-xr-xtests/TouchLatency/gradlew78
-rw-r--r--tests/TouchLatency/gradlew.bat14
-rw-r--r--tests/TransformTest/AndroidManifest.xml12
-rw-r--r--tests/TransitionTests/AndroidManifest.xml256
-rw-r--r--tests/TtsTests/AndroidManifest.xml23
-rw-r--r--tests/UiBench/AndroidManifest.xml352
-rw-r--r--tests/UiBench/res/layout/recycler_view.xml1
-rw-r--r--tests/UpdatableSystemFontTest/Android.bp51
-rw-r--r--tests/UpdatableSystemFontTest/AndroidManifest.xml30
-rw-r--r--tests/UpdatableSystemFontTest/AndroidTest.xml44
-rw-r--r--tests/UpdatableSystemFontTest/EmojiRenderingTestApp/Android.bp32
-rw-r--r--tests/UpdatableSystemFontTest/EmojiRenderingTestApp/AndroidManifest.xml24
-rw-r--r--tests/UpdatableSystemFontTest/EmojiRenderingTestApp/src/com/android/emojirenderingtestapp/EmojiRenderingTestActivity.java40
-rw-r--r--tests/UpdatableSystemFontTest/EmojiRenderingTestApp/src/com/android/emojirenderingtestapp/GetAvailableFontsTestActivity.java53
-rw-r--r--tests/UpdatableSystemFontTest/TEST_MAPPING7
-rw-r--r--tests/UpdatableSystemFontTest/src/com/android/updatablesystemfont/UpdatableSystemFontTest.java451
-rw-r--r--tests/UpdatableSystemFontTest/testdata/Android.bp122
-rw-r--r--tests/UpdatableSystemFontTest/testdata/NotoColorEmoji.ttfbin0 -> 1820 bytes
-rw-r--r--tests/UpdatableSystemFontTest/testdata/NotoColorEmoji.ttx208
-rw-r--r--tests/UpdatableSystemFontTest/testdata/UpdatableSystemFontTestCert.derbin0 -> 1341 bytes
-rw-r--r--tests/UpdatableSystemFontTest/testdata/UpdatableSystemFontTestCert.pem30
-rw-r--r--tests/UpdatableSystemFontTest/testdata/UpdatableSystemFontTestKey.pem52
-rw-r--r--tests/UsageReportingTest/AndroidManifest.xml11
-rw-r--r--tests/UsageStatsTest/AndroidManifest.xml19
-rw-r--r--tests/UsageStatsTest/src/com/android/tests/usagestats/UsageStatsActivity.java4
-rw-r--r--tests/UsbHostExternalManagmentTest/AoapTestDevice/AndroidManifest.xml17
-rw-r--r--tests/UsbHostExternalManagmentTest/AoapTestDevice/src/com/android/hardware/usb/aoapdevicetest/UsbAoapDeviceTestActivity.java2
-rw-r--r--tests/UsbHostExternalManagmentTest/AoapTestHost/AndroidManifest.xml17
-rw-r--r--tests/UsbHostExternalManagmentTest/UsbHostExternalManagmentTestApp/AndroidManifest.xml16
-rw-r--r--tests/UsesFeature2Test/AndroidManifest.xml4
-rw-r--r--tests/VectorDrawableTest/AndroidManifest.xml163
-rw-r--r--tests/VoiceEnrollment/AndroidManifest.xml26
-rw-r--r--tests/VoiceInteraction/AndroidManifest.xml94
-rw-r--r--tests/WallpaperTest/AndroidManifest.xml34
-rw-r--r--tests/WindowAnimationJank/AndroidManifest.xml17
-rw-r--r--tests/WindowInsetsTests/AndroidManifest.xml17
-rw-r--r--tests/WindowInsetsTests/res/layout/chat_activity.xml (renamed from tests/WindowInsetsTests/res/layout/window_inset_activity.xml)0
-rw-r--r--tests/WindowInsetsTests/res/layout/controller_activity.xml106
-rw-r--r--tests/WindowInsetsTests/res/layout/main_activity.xml (renamed from tests/ActivityViewTest/res/layout/activity_view_main_activity.xml)23
-rw-r--r--tests/WindowInsetsTests/res/values/strings.xml11
-rw-r--r--tests/WindowInsetsTests/res/values/styles.xml8
-rw-r--r--tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/ChatActivity.java (renamed from tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/WindowInsetsActivity.java)9
-rw-r--r--tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/ControllerActivity.java204
-rw-r--r--tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/WindowInsetsTestsMainActivity.java36
-rw-r--r--tests/appwidgets/AppWidgetHostTest/AndroidManifest.xml39
-rw-r--r--tests/appwidgets/AppWidgetProviderTest/AndroidManifest.xml14
-rw-r--r--tests/backup/AndroidManifest.xml14
-rw-r--r--tests/benchmarks/internal/Android.bp34
-rw-r--r--tests/benchmarks/internal/AndroidManifest.xml28
-rw-r--r--tests/benchmarks/internal/AndroidTest.xml28
-rw-r--r--tests/benchmarks/internal/src/com/android/internal/LambdaPerfTest.java454
-rw-r--r--tests/net/integration/src/com/android/server/net/integrationtests/TestNetworkStackService.kt96
-rw-r--r--tests/permission/Android.bp9
-rw-r--r--tests/permission/AndroidManifest.xml5
-rw-r--r--tests/permission/src/com/android/framework/permission/tests/VibratorManagerServicePermissionTest.java150
-rw-r--r--tests/permission/src/com/android/framework/permission/tests/VibratorServicePermissionTest.java80
-rw-r--r--tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java49
-rw-r--r--tests/utils/StubIME/AndroidManifest.xml19
-rw-r--r--tests/utils/hostutils/src/com/android/fsverity/AddFsVerityCertRule.java77
-rw-r--r--tests/utils/hostutils/src/com/android/internal/util/test/SystemPreparer.java53
-rw-r--r--tests/utils/testutils/java/android/view/test/InsetsModeSession.java37
-rw-r--r--tests/utils/testutils/java/com/android/internal/util/test/BroadcastInterceptingContext.java6
-rw-r--r--tests/utils/testutils/java/com/android/server/wm/test/filters/FrameworksTestsFilter.java17
-rw-r--r--tests/vcn/java/android/net/vcn/VcnTransportInfoTest.java47
338 files changed, 17882 insertions, 7238 deletions
diff --git a/tests/AccessibilityEventsLogger/AndroidManifest.xml b/tests/AccessibilityEventsLogger/AndroidManifest.xml
index d86769f570c5..a5713679786f 100644
--- a/tests/AccessibilityEventsLogger/AndroidManifest.xml
+++ b/tests/AccessibilityEventsLogger/AndroidManifest.xml
@@ -16,25 +16,23 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- package="com.android.tests.accessibilityeventlogger"
- android:versionCode="1"
- android:versionName="0.0" >
-
- <uses-sdk
- android:minSdkVersion="18"
- android:targetSdkVersion="18" />
-
- <application
- android:allowBackup="true"
- android:enabled="true"
- android:label="@string/app_name" >
-
- <service
- android:name=".AELogger"
- android:enabled="true"
- android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"
- android:configChanges="locale" >
+ xmlns:tools="http://schemas.android.com/tools"
+ package="com.android.tests.accessibilityeventlogger"
+ android:versionCode="1"
+ android:versionName="0.0">
+
+ <uses-sdk android:minSdkVersion="18"
+ android:targetSdkVersion="18"/>
+
+ <application android:allowBackup="true"
+ android:enabled="true"
+ android:label="@string/app_name">
+
+ <service android:name=".AELogger"
+ android:enabled="true"
+ android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"
+ android:configChanges="locale"
+ android:exported="true">
<intent-filter>
<action android:name="android.accessibilityservice.AccessibilityService"/>
@@ -43,9 +41,8 @@
<category android:name="android.accessibilityservice.category.FEEDBACK_AUDIBLE"/>
</intent-filter>
- <meta-data
- android:name="android.accessibilityservice"
- android:resource="@xml/accessibilityservice" />
+ <meta-data android:name="android.accessibilityservice"
+ android:resource="@xml/accessibilityservice"/>
</service>
</application>
</manifest>
diff --git a/tests/AccessoryDisplay/sink/AndroidManifest.xml b/tests/AccessoryDisplay/sink/AndroidManifest.xml
index 72d498f2d855..2aee9693ff17 100644
--- a/tests/AccessoryDisplay/sink/AndroidManifest.xml
+++ b/tests/AccessoryDisplay/sink/AndroidManifest.xml
@@ -15,26 +15,27 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.accessorydisplay.sink" >
+ package="com.android.accessorydisplay.sink">
<uses-feature android:name="android.hardware.usb.host"/>
- <uses-sdk android:minSdkVersion="18" />
+ <uses-sdk android:minSdkVersion="18"/>
<application android:label="@string/app_name"
- android:icon="@drawable/ic_app"
- android:hardwareAccelerated="true">
+ android:icon="@drawable/ic_app"
+ android:hardwareAccelerated="true">
<activity android:name=".SinkActivity"
- android:label="@string/app_name"
- android:theme="@android:style/Theme.Holo">
+ android:label="@string/app_name"
+ android:theme="@android:style/Theme.Holo"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
+ <action android:name="android.intent.action.MAIN"/>
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"/>
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<meta-data android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
- android:resource="@xml/usb_device_filter"/>
+ android:resource="@xml/usb_device_filter"/>
</activity>
</application>
diff --git a/tests/AccessoryDisplay/sink/src/com/android/accessorydisplay/sink/SinkActivity.java b/tests/AccessoryDisplay/sink/src/com/android/accessorydisplay/sink/SinkActivity.java
index fc1d47bcd20f..65b4bd090c82 100644
--- a/tests/AccessoryDisplay/sink/src/com/android/accessorydisplay/sink/SinkActivity.java
+++ b/tests/AccessoryDisplay/sink/src/com/android/accessorydisplay/sink/SinkActivity.java
@@ -167,7 +167,7 @@ public class SinkActivity extends Activity {
Intent intent = new Intent(ACTION_USB_DEVICE_PERMISSION);
intent.setPackage(getPackageName());
PendingIntent pendingIntent = PendingIntent.getBroadcast(
- this, 0, intent, PendingIntent.FLAG_ONE_SHOT);
+ this, 0, intent, PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_MUTABLE);
mUsbManager.requestPermission(device, pendingIntent);
return;
}
diff --git a/tests/AccessoryDisplay/source/AndroidManifest.xml b/tests/AccessoryDisplay/source/AndroidManifest.xml
index d3edcb838877..4611e1de466c 100644
--- a/tests/AccessoryDisplay/source/AndroidManifest.xml
+++ b/tests/AccessoryDisplay/source/AndroidManifest.xml
@@ -15,26 +15,27 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.accessorydisplay.source" >
+ package="com.android.accessorydisplay.source">
<uses-feature android:name="android.hardware.usb.accessory"/>
- <uses-sdk android:minSdkVersion="18" />
+ <uses-sdk android:minSdkVersion="18"/>
<application android:label="@string/app_name"
- android:icon="@drawable/ic_app"
- android:hardwareAccelerated="true">
+ android:icon="@drawable/ic_app"
+ android:hardwareAccelerated="true">
<activity android:name=".SourceActivity"
- android:label="@string/app_name"
- android:theme="@android:style/Theme.Holo">
+ android:label="@string/app_name"
+ android:theme="@android:style/Theme.Holo"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
+ <action android:name="android.intent.action.MAIN"/>
<action android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED"/>
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<meta-data android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED"
- android:resource="@xml/usb_accessory_filter"/>
+ android:resource="@xml/usb_accessory_filter"/>
</activity>
</application>
diff --git a/tests/ActivityManagerPerfTests/stub-app/AndroidManifest.xml b/tests/ActivityManagerPerfTests/stub-app/AndroidManifest.xml
index a57f64c320c8..6bdeea06053f 100644
--- a/tests/ActivityManagerPerfTests/stub-app/AndroidManifest.xml
+++ b/tests/ActivityManagerPerfTests/stub-app/AndroidManifest.xml
@@ -16,39 +16,34 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.stubs.am">
+ package="com.android.stubs.am">
<uses-permission android:name="android.permission.START_ACTIVITIES_FROM_BACKGROUND"/>
- <application android:label="Android TestCase" >
- <provider
- android:authorities="@string/authority"
- android:name=".TestContentProvider"
- android:exported="true" />
- <receiver
- android:name=".TestBroadcastReceiver"
- android:exported="true">
+ <application android:label="Android TestCase">
+ <provider android:authorities="@string/authority"
+ android:name=".TestContentProvider"
+ android:exported="true"/>
+ <receiver android:name=".TestBroadcastReceiver"
+ android:exported="true">
<intent-filter>
- <action android:name="com.android.stubs.am.ACTION_BROADCAST_TEST" />
- <category android:name="android.intent.category.DEFAULT" />
+ <action android:name="com.android.stubs.am.ACTION_BROADCAST_TEST"/>
+ <category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</receiver>
- <service
- android:name=".InitService"
- android:exported="true" />
- <service
- android:name=".TestService"
- android:exported="true" />
- <activity
- android:name=".TestActivity"
- android:excludeFromRecents="true"
- android:turnScreenOn="true"
- android:launchMode="singleTask">
+ <service android:name=".InitService"
+ android:exported="true"/>
+ <service android:name=".TestService"
+ android:exported="true"/>
+ <activity android:name=".TestActivity"
+ android:excludeFromRecents="true"
+ android:turnScreenOn="true"
+ android:launchMode="singleTask"
+ android:exported="true">
<intent-filter>
- <action android:name="com.android.stubs.am.ACTION_START_TEST_ACTIVITY" />
- <category android:name="android.intent.category.DEFAULT" />
+ <action android:name="com.android.stubs.am.ACTION_START_TEST_ACTIVITY"/>
+ <category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
</application>
</manifest>
-
diff --git a/tests/ActivityManagerPerfTests/tests/Android.bp b/tests/ActivityManagerPerfTests/tests/Android.bp
index c8dbf811c69b..e5813aec9f43 100644
--- a/tests/ActivityManagerPerfTests/tests/Android.bp
+++ b/tests/ActivityManagerPerfTests/tests/Android.bp
@@ -28,6 +28,7 @@ android_test {
"androidx.test.rules",
"apct-perftests-utils",
"ActivityManagerPerfTestsUtils",
+ "collector-device-lib-platform",
],
platform_apis: true,
min_sdk_version: "25",
diff --git a/tests/ActivityManagerPerfTests/tests/AndroidTest.xml b/tests/ActivityManagerPerfTests/tests/AndroidTest.xml
index 475bb82a9856..e753b704a3ae 100644
--- a/tests/ActivityManagerPerfTests/tests/AndroidTest.xml
+++ b/tests/ActivityManagerPerfTests/tests/AndroidTest.xml
@@ -28,5 +28,22 @@
<test class="com.android.tradefed.testtype.AndroidJUnitTest">
<option name="package" value="com.android.frameworks.perftests.amtests"/>
<option name="runner" value="androidx.test.runner.AndroidJUnitRunner"/>
+
+ <!-- TODO: Add PerfettoListener to automatically capture perfetto traces for each test-->
+ <!-- Listener related args for collecting the traces and waiting for the device
+ to stabilize. -->
+ <option name="device-listeners"
+ value="android.device.collectors.ProcLoadListener" />
+ <!-- Guarantee that user defined RunListeners will be running before any of the default
+ listeners defined in this runner. -->
+ <option name="instrumentation-arg" key="newRunListenerMode" value="true" />
+
+ <!-- ProcLoadListener related arguments -->
+ <!-- Wait for device last minute threshold to reach 3 with 2 minute timeout before
+ starting the test run -->
+ <option name="instrumentation-arg" key="procload-collector:per_run" value="true" />
+ <option name="instrumentation-arg" key="proc-loadavg-threshold" value="3" />
+ <option name="instrumentation-arg" key="proc-loadavg-timeout" value="120000" />
+ <option name="instrumentation-arg" key="proc-loadavg-interval" value="10000" />
</test>
</configuration>
diff --git a/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/OomAdjPerfTest.java b/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/OomAdjPerfTest.java
index 1d3ff06e6bf1..5d6a4a3541c1 100644
--- a/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/OomAdjPerfTest.java
+++ b/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/OomAdjPerfTest.java
@@ -22,13 +22,13 @@ import android.content.Context;
import android.net.Uri;
import android.os.HandlerThread;
import android.perftests.utils.ManualBenchmarkState;
-import android.perftests.utils.PerfManualStatusReporter;
import android.perftests.utils.TraceMarkParser;
import android.perftests.utils.TraceMarkParser.TraceMarkLine;
import android.perftests.utils.TraceMarkParser.TraceMarkSlice;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
import com.android.frameworks.perftests.am.util.AtraceUtils;
import com.android.frameworks.perftests.am.util.TargetPackageUtils;
@@ -36,10 +36,8 @@ import com.android.frameworks.perftests.am.util.Utils;
import org.junit.After;
import org.junit.Before;
-import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
import java.util.ArrayList;
import java.util.List;
@@ -53,9 +51,9 @@ import java.util.List;
* into the stats; when there are enough samples in the stats, the test will
* stop and output the mean/stddev time spent on the updateOomAdjLocked.
*/
-@RunWith(JUnit4.class)
+@RunWith(AndroidJUnit4.class)
@LargeTest
-public final class OomAdjPerfTest {
+public final class OomAdjPerfTest extends BasePerfTest {
private static final String TAG = "OomAdjPerfTest";
private static final boolean VERBOSE = true;
@@ -74,8 +72,6 @@ public final class OomAdjPerfTest {
private static final String ATRACE_CATEGORY = "am";
private static final String ATRACE_OOMADJ_PREFIX = "updateOomAdj_";
- @Rule
- public PerfManualStatusReporter mPerfManualStatusReporter = new PerfManualStatusReporter();
private TraceMarkParser mTraceMarkParser = new TraceMarkParser(this::shouldFilterTraceLine);
private final ArrayList<Long> mDurations = new ArrayList<Long>();
private Context mContext;
diff --git a/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/ServiceStartPerfTest.java b/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/ServiceStartPerfTest.java
index ba2064005937..e1b508b424f5 100644
--- a/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/ServiceStartPerfTest.java
+++ b/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/ServiceStartPerfTest.java
@@ -25,14 +25,30 @@ import androidx.test.runner.AndroidJUnit4;
import com.android.frameworks.perftests.am.util.Constants;
import com.android.frameworks.perftests.am.util.TargetPackageUtils;
+import com.android.frameworks.perftests.am.util.Utils;
+import org.junit.After;
import org.junit.Assert;
+import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
@LargeTest
public class ServiceStartPerfTest extends BasePerfTest {
+ private static final String STUB_PACKAGE_NAME =
+ "com.android.frameworks.perftests.amteststestapp";
+
+ @Before
+ public void setUp() {
+ super.setUp();
+ Utils.runShellCommand("cmd deviceidle whitelist +" + STUB_PACKAGE_NAME);
+ }
+
+ @After
+ public void tearDown() {
+ Utils.runShellCommand("cmd deviceidle whitelist -" + STUB_PACKAGE_NAME);
+ }
/**
* Tries to start the service with the given intent, throwing a RuntimeException with the
diff --git a/tests/ActivityTests/AndroidManifest.xml b/tests/ActivityTests/AndroidManifest.xml
index 0b3bd70ba5c9..88a5e64a92bd 100644
--- a/tests/ActivityTests/AndroidManifest.xml
+++ b/tests/ActivityTests/AndroidManifest.xml
@@ -15,85 +15,98 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.google.android.test.activity">
- <uses-permission android:name="android.permission.REAL_GET_TASKS" />
- <uses-permission android:name="android.permission.REORDER_TASKS" />
- <uses-permission android:name="android.permission.REMOVE_TASKS" />
- <uses-permission android:name="android.permission.READ_FRAME_BUFFER" />
- <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
- <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
- <uses-permission android:name="android.permission.MANAGE_USERS" />
- <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
- <uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
- <uses-sdk android:targetSdkVersion="22" />
+ package="com.google.android.test.activity">
+ <uses-permission android:name="android.permission.REAL_GET_TASKS"/>
+ <uses-permission android:name="android.permission.REORDER_TASKS"/>
+ <uses-permission android:name="android.permission.REMOVE_TASKS"/>
+ <uses-permission android:name="android.permission.READ_FRAME_BUFFER"/>
+ <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS"/>
+ <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL"/>
+ <uses-permission android:name="android.permission.MANAGE_USERS"/>
+ <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
+ <uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"/>
+ <uses-sdk android:targetSdkVersion="22"/>
<application android:label="ActivityTest">
- <activity android:name="ActivityTestMain">
+ <activity android:name="ActivityTestMain"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<intent-filter>
- <action android:name="android.intent.action.VIEW" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.BROWSABLE" />
- <data android:scheme="http" android:host="www.angryredplanet.com"
- android:pathPrefix="" />
+ <action android:name="android.intent.action.VIEW"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.BROWSABLE"/>
+ <data android:scheme="http"
+ android:host="www.angryredplanet.com"
+ android:pathPrefix=""/>
</intent-filter>
<preferred>
- <action android:name="android.intent.action.VIEW" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.BROWSABLE" />
- <data android:scheme="http" android:host="www.angryredplanet.com"
- android:pathPrefix="" />
+ <action android:name="android.intent.action.VIEW"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.BROWSABLE"/>
+ <data android:scheme="http"
+ android:host="www.angryredplanet.com"
+ android:pathPrefix=""/>
</preferred>
</activity>
- <activity android:name="SpamActivity" android:label="Spam!"
- android:documentLaunchMode="always">
+ <activity android:name="SpamActivity"
+ android:label="Spam!"
+ android:documentLaunchMode="always">
</activity>
- <activity android:name="DocActivity" android:label="Some doc">
+ <activity android:name="DocActivity"
+ android:label="Some doc">
</activity>
<service android:name="SingleUserService"
- android:singleUser="true" android:exported="true">
+ android:singleUser="true"
+ android:exported="true">
</service>
<service android:name="ServiceUserTarget">
</service>
<receiver android:name="UserTarget">
</receiver>
- <service android:name="IsolatedService" android:isolatedProcess="true">
+ <service android:name="IsolatedService"
+ android:isolatedProcess="true">
</service>
- <receiver android:name="StartEmpty" android:exported="true">
+ <receiver android:name="StartEmpty"
+ android:exported="true">
<intent-filter>
- <action android:name="com.example.START_EMPTY" />
+ <action android:name="com.example.START_EMPTY"/>
</intent-filter>
</receiver>
- <service android:name="EmptyService" android:exported="true">
+ <service android:name="EmptyService"
+ android:exported="true">
<intent-filter>
- <action android:name="com.example.START_EMPTY" />
+ <action android:name="com.example.START_EMPTY"/>
</intent-filter>
</service>
<receiver android:name="SingleUserReceiver"
- android:singleUser="true" android:exported="true" >
+ android:singleUser="true"
+ android:exported="true">
</receiver>
<provider android:name="SingleUserProvider"
- android:authorities="com.google.android.test.activity.single_user"
- android:singleUser="true" android:exported="true" />
- <receiver android:name="TrackTimeReceiver" />
- <receiver android:name="AlarmSpamReceiver" />
- <receiver android:name="SlowReceiver" />
+ android:authorities="com.google.android.test.activity.single_user"
+ android:singleUser="true"
+ android:exported="true"/>
+ <receiver android:name="TrackTimeReceiver"/>
+ <receiver android:name="AlarmSpamReceiver"/>
+ <receiver android:name="SlowReceiver"/>
<activity android:name="DisableScreenshotsActivity"
- android:label="DisableScreenshots"
- android:theme="@style/DisableScreenshots">
+ android:label="DisableScreenshots"
+ android:theme="@style/DisableScreenshots"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:name="CustomSplashscreenActivity"
- android:label="CustomSplashscreen"
- android:theme="@style/CustomSplashscreen">
+ android:label="CustomSplashscreen"
+ android:theme="@style/CustomSplashscreen"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
diff --git a/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java b/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java
index 768cfaea4898..a8e47b5e6def 100644
--- a/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java
+++ b/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java
@@ -100,7 +100,7 @@ public class ActivityTestMain extends Activity {
Intent intent = new Intent(ActivityTestMain.this, AlarmSpamReceiver.class);
intent.setAction("com.example.SPAM_ALARM=" + when);
PendingIntent pi = PendingIntent.getBroadcast(ActivityTestMain.this,
- 0, intent, 0);
+ 0, intent, PendingIntent.FLAG_MUTABLE_UNAUDITED);
mAlarm.setAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME, when+(30*1000), pi);
scheduleSpamAlarm(30*1000);
} break;
@@ -134,7 +134,7 @@ public class ActivityTestMain extends Activity {
// Also send a broadcast alarm to evaluate the alarm fast-forward policy
intent.putExtra(SLOW_RECEIVER_EXTRA, 4);
- PendingIntent pi = PendingIntent.getBroadcast(ActivityTestMain.this, 1, intent, 0);
+ PendingIntent pi = PendingIntent.getBroadcast(ActivityTestMain.this, 1, intent, PendingIntent.FLAG_MUTABLE_UNAUDITED);
AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
long now = SystemClock.elapsedRealtime();
Log.i(TAG, "Setting alarm for now + 5 seconds");
@@ -493,7 +493,7 @@ public class ActivityTestMain extends Activity {
Intent receiveIntent = new Intent(ActivityTestMain.this, TrackTimeReceiver.class);
receiveIntent.putExtra("something", "yeah, this is us!");
options.requestUsageTimeReport(PendingIntent.getBroadcast(ActivityTestMain.this,
- 0, receiveIntent, PendingIntent.FLAG_CANCEL_CURRENT));
+ 0, receiveIntent, PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_MUTABLE_UNAUDITED));
startActivity(Intent.createChooser(intent, "Who do you love?"), options.toBundle());
return true;
}
diff --git a/tests/ActivityViewTest/AndroidManifest.xml b/tests/ActivityViewTest/AndroidManifest.xml
deleted file mode 100644
index 17eb029166f0..000000000000
--- a/tests/ActivityViewTest/AndroidManifest.xml
+++ /dev/null
@@ -1,66 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2018 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.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.google.android.test.activityview">
- <uses-permission android:name="android.permission.INJECT_EVENTS"/>
- <uses-permission android:name="android.permission.MANAGE_ACTIVITY_STACKS"/>
- <uses-permission android:name="android.permission.ACTIVITY_EMBEDDING"/>
- <uses-permission android:name="android.permission.INTERNAL_SYSTEM_WINDOW"/>
-
- <uses-sdk android:targetSdkVersion="27"/>
- <application android:label="ActivityViewTest">
- <activity android:name=".ActivityViewMainActivity"
- android:label="AV Main"
- android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|colorMode|density">
- <intent-filter>
- <action android:name="android.intent.action.MAIN"/>
- <category android:name="android.intent.category.LAUNCHER"/>
- <category android:name="android.intent.category.DEFAULT"/>
- </intent-filter>
- </activity>
-
- <activity android:name=".ActivityViewActivity"
- android:label="AV"
- android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|colorMode|density"
- android:windowSoftInputMode="stateHidden|adjustResize">
- </activity>
-
- <activity android:name=".ActivityViewResizeActivity"
- android:label="AV Resize"
- android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|colorMode|density"
- android:windowSoftInputMode="stateHidden|adjustResize">
- </activity>
-
- <activity android:name=".ActivityViewScrollActivity"
- android:label="AV Scroll"
- android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|colorMode|density"
- android:windowSoftInputMode="stateHidden">
- </activity>
-
- <activity android:name=".ActivityViewTestActivity"
- android:resizeableActivity="true"
- android:theme="@*android:style/Theme.NoTitleBar"
- android:exported="true"
- android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|colorMode|density">
- </activity>
-
- <activity android:name=".ActivityViewVisibilityActivity"
- android:label="AV Visibility"
- android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|colorMode|density">
- </activity>
- </application>
-</manifest>
diff --git a/tests/ActivityViewTest/res/layout/activity_view_activity.xml b/tests/ActivityViewTest/res/layout/activity_view_activity.xml
deleted file mode 100644
index 67c01f8c78fe..000000000000
--- a/tests/ActivityViewTest/res/layout/activity_view_activity.xml
+++ /dev/null
@@ -1,47 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2018 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.
--->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="#cfd8dc">
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal">
-
- <Button
- android:id="@+id/activity_launch_button"
- android:layout_width="200dp"
- android:layout_height="wrap_content"
- android:text="Launch test activity" />
-
- <Button
- android:id="@+id/activity_pick_launch_button"
- android:layout_width="200dp"
- android:layout_height="wrap_content"
- android:text="Launch from picker" />
-
- </LinearLayout>
-
- <ActivityView
- android:id="@+id/activity_view"
- android:layout_width="match_parent"
- android:layout_height="match_parent" />
-
-</LinearLayout> \ No newline at end of file
diff --git a/tests/ActivityViewTest/res/layout/activity_view_resize_activity.xml b/tests/ActivityViewTest/res/layout/activity_view_resize_activity.xml
deleted file mode 100644
index 18d86e3d5a6f..000000000000
--- a/tests/ActivityViewTest/res/layout/activity_view_resize_activity.xml
+++ /dev/null
@@ -1,51 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2018 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.
--->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="#cfd8dc">
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal">
-
- <Button
- android:id="@+id/activity_launch_button"
- android:layout_width="100dp"
- android:layout_height="wrap_content"
- android:text="Launch" />
-
- <Button
- android:id="@+id/activity_resize_button"
- android:layout_width="100dp"
- android:layout_height="wrap_content"
- android:text="Resize" />
- </LinearLayout>
-
- <SeekBar
- android:id="@+id/activity_view_seek_bar"
- android:layout_width="match_parent"
- android:layout_height="wrap_content" />
-
- <ActivityView
- android:id="@+id/activity_view"
- android:layout_width="match_parent"
- android:layout_height="600dp" />
-
-</LinearLayout> \ No newline at end of file
diff --git a/tests/ActivityViewTest/res/layout/activity_view_scroll_activity.xml b/tests/ActivityViewTest/res/layout/activity_view_scroll_activity.xml
deleted file mode 100644
index 879c2c20a082..000000000000
--- a/tests/ActivityViewTest/res/layout/activity_view_scroll_activity.xml
+++ /dev/null
@@ -1,57 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2018 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.
--->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical" android:layout_width="match_parent"
- android:layout_height="match_parent">
-
- <Button
- android:id="@+id/activity_launch_button"
- android:layout_width="100dp"
- android:layout_height="wrap_content"
- android:text="Launch" />
-
- <ScrollView
- android:id="@+id/activity_view_host_scroll_view"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:color="#cfd8dc">
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical" >
-
- <View
- android:layout_width="match_parent"
- android:layout_height="300dp"
- android:layout_gravity="center_horizontal"
- android:background="#eeeeee" />
-
- <ActivityView
- android:id="@+id/activity_view"
- android:layout_width="match_parent"
- android:layout_height="300dp"
- android:background="#fce4ec" />
-
- <View
- android:layout_width="match_parent"
- android:layout_height="300dp"
- android:layout_gravity="center_horizontal"
- android:background="#eeeeee" />
- </LinearLayout>
- </ScrollView>
-</LinearLayout> \ No newline at end of file
diff --git a/tests/ActivityViewTest/res/layout/activity_view_test_activity.xml b/tests/ActivityViewTest/res/layout/activity_view_test_activity.xml
deleted file mode 100644
index 338d68adfafb..000000000000
--- a/tests/ActivityViewTest/res/layout/activity_view_test_activity.xml
+++ /dev/null
@@ -1,70 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2018 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.
--->
-
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/test_activity_root"
- android:orientation="vertical"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="#ffe0b2">
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_centerInParent="true"
- android:orientation="vertical"
- android:background="#00000000" >
- <TextView
- android:id="@+id/test_activity_title"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:textColor="@android:color/black"
- android:background="#00000000"
- android:gravity="center" />
- <TextView
- android:id="@+id/test_activity_touch_state"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:textColor="@android:color/black"
- android:background="#00000000"
- android:gravity="center" />
- </LinearLayout>
-
- <TextView
- android:id="@+id/test_activity_width_text"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:textColor="@android:color/black"
- android:background="#00000000"
- android:gravity="center" />
-
- <TextView
- android:id="@+id/test_activity_height_text"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:layout_alignParentRight="true"
- android:layout_alignParentEnd="true"
- android:textColor="@android:color/black"
- android:background="#00000000"
- android:gravity="center" />
-
- <EditText
- android:id="@+id/test_activity_edittext"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_alignParentBottom="true"
- android:layout_margin="16dp" />
-</RelativeLayout> \ No newline at end of file
diff --git a/tests/ActivityViewTest/res/layout/activity_view_visibility_activity.xml b/tests/ActivityViewTest/res/layout/activity_view_visibility_activity.xml
deleted file mode 100644
index d29d4dfc0428..000000000000
--- a/tests/ActivityViewTest/res/layout/activity_view_visibility_activity.xml
+++ /dev/null
@@ -1,46 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2019 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.
--->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="#cfd8dc">
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal">
-
- <Button
- android:id="@+id/activity_launch_button"
- android:layout_width="200dp"
- android:layout_height="wrap_content"
- android:text="Launch test activity" />
-
- <Spinner
- android:id="@+id/visibility_spinner"
- android:layout_width="200dp"
- android:layout_height="match_parent"/>
-
- </LinearLayout>
-
- <ActivityView
- android:id="@+id/activity_view"
- android:layout_width="match_parent"
- android:layout_height="match_parent" />
-
-</LinearLayout>
diff --git a/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewActivity.java b/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewActivity.java
deleted file mode 100644
index f7c60fc73cb3..000000000000
--- a/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewActivity.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/**
- * Copyright (c) 2018 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.google.android.test.activityview;
-
-import android.app.Activity;
-import android.app.ActivityView;
-import android.content.Intent;
-import android.os.Bundle;
-import android.os.Parcelable;
-import android.widget.Button;
-
-public class ActivityViewActivity extends Activity {
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_view_activity);
-
- final ActivityView activityView = findViewById(R.id.activity_view);
- final Button launchButton = findViewById(R.id.activity_launch_button);
- launchButton.setOnClickListener(v -> {
- final Intent intent = new Intent(this, ActivityViewTestActivity.class);
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
- activityView.startActivity(intent);
- });
- final Button pickActivityLaunchButton = findViewById(R.id.activity_pick_launch_button);
- pickActivityLaunchButton.setOnClickListener(v -> {
- final Intent intent = Intent.makeMainActivity(null);
- final Intent chooser = Intent.createChooser(intent,
- "Pick an app to launch in ActivityView");
- chooser.putExtra(Intent.EXTRA_INITIAL_INTENTS, new Parcelable[] {
- new Intent(Intent.ACTION_MAIN)
- .addCategory("com.android.internal.category.PLATLOGO")
- });
- if (intent.resolveActivity(getPackageManager()) != null) {
- chooser.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
- | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
- activityView.startActivity(chooser);
- }
- });
- }
-}
diff --git a/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewMainActivity.java b/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewMainActivity.java
deleted file mode 100644
index 4f09c28fe711..000000000000
--- a/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewMainActivity.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/**
- * Copyright (c) 2018 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.google.android.test.activityview;
-
-import android.app.Activity;
-import android.content.Intent;
-import android.os.Bundle;
-
-public class ActivityViewMainActivity extends Activity {
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_view_main_activity);
-
- findViewById(R.id.activity_view_button).setOnClickListener(
- v -> startActivity(new Intent(this, ActivityViewActivity.class)));
-
- findViewById(R.id.scroll_activity_view_button).setOnClickListener(
- v -> startActivity(new Intent(this, ActivityViewScrollActivity.class)));
-
- findViewById(R.id.resize_activity_view_button).setOnClickListener(
- v -> startActivity(new Intent(this, ActivityViewResizeActivity.class)));
-
- findViewById(R.id.visibility_activity_view_button).setOnClickListener(
- v -> startActivity(new Intent(this, ActivityViewVisibilityActivity.class)));
- }
-}
diff --git a/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewResizeActivity.java b/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewResizeActivity.java
deleted file mode 100644
index 8860a771fd5a..000000000000
--- a/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewResizeActivity.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/**
- * Copyright (c) 2018 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.google.android.test.activityview;
-
-import android.app.Activity;
-import android.app.ActivityView;
-import android.content.Intent;
-import android.os.Bundle;
-import android.widget.Button;
-import android.widget.LinearLayout;
-import android.widget.SeekBar;
-
-public class ActivityViewResizeActivity extends Activity {
- private static final int SMALL_SIZE = 600;
- private static final int LARGE_SIZE = 1200;
-
- private ActivityView mActivityView;
-
- private boolean mFlipSize;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_view_resize_activity);
-
- mActivityView = findViewById(R.id.activity_view);
-
- final Button launchButton = findViewById(R.id.activity_launch_button);
- launchButton.setOnClickListener(v -> {
- final Intent intent = new Intent(this, ActivityViewTestActivity.class);
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
- mActivityView.startActivity(intent);
- });
- final Button resizeButton = findViewById(R.id.activity_resize_button);
- if (resizeButton != null) {
- resizeButton.setOnClickListener(v -> {
- LinearLayout.LayoutParams params =
- (LinearLayout.LayoutParams) mActivityView.getLayoutParams();
- params.height = mFlipSize ? SMALL_SIZE : LARGE_SIZE;
- mFlipSize = !mFlipSize;
- mActivityView.setLayoutParams(params);
- });
- }
- final SeekBar seekBar = findViewById(R.id.activity_view_seek_bar);
- if (seekBar != null) {
- seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
- @Override
- public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
- final LinearLayout.LayoutParams params =
- (LinearLayout.LayoutParams) mActivityView.getLayoutParams();
- params.height = SMALL_SIZE + progress * 10;
- mActivityView.setLayoutParams(params);
- }
-
- @Override
- public void onStartTrackingTouch(SeekBar seekBar) {
- }
-
- @Override
- public void onStopTrackingTouch(SeekBar seekBar) {
- }
- });
- }
- }
-}
diff --git a/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewScrollActivity.java b/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewScrollActivity.java
deleted file mode 100644
index 56543662675c..000000000000
--- a/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewScrollActivity.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/**
- * Copyright (c) 2018 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.google.android.test.activityview;
-
-import android.app.Activity;
-import android.app.ActivityView;
-import android.content.Intent;
-import android.os.Bundle;
-import android.view.View;
-import android.widget.Button;
-
-public class ActivityViewScrollActivity extends Activity {
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_view_scroll_activity);
-
- final ActivityView activityView = findViewById(R.id.activity_view);
- final Button launchButton = findViewById(R.id.activity_launch_button);
- launchButton.setOnClickListener(v -> {
- final Intent intent = new Intent(this, ActivityViewTestActivity.class);
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
- activityView.startActivity(intent);
- });
- findViewById(R.id.activity_view_host_scroll_view).setOnScrollChangeListener(
- (View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY)
- -> activityView.onLocationChanged());
- }
-}
diff --git a/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewTestActivity.java b/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewTestActivity.java
deleted file mode 100644
index 52aba2b13c42..000000000000
--- a/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewTestActivity.java
+++ /dev/null
@@ -1,116 +0,0 @@
-/**
- * Copyright (c) 2018 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.google.android.test.activityview;
-
-import static android.view.MotionEvent.ACTION_CANCEL;
-import static android.view.MotionEvent.ACTION_DOWN;
-import static android.view.MotionEvent.ACTION_MOVE;
-import static android.view.MotionEvent.ACTION_UP;
-
-import android.app.Activity;
-import android.content.res.Configuration;
-import android.os.Bundle;
-import android.util.Log;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewTreeObserver;
-import android.widget.TextView;
-
-public class ActivityViewTestActivity extends Activity {
- private static final String TAG = "ActivityViewTestActivity";
-
- private View mRoot;
- private TextView mTextView;
- private TextView mWidthTextView;
- private TextView mHeightTextView;
- private TextView mTouchStateTextView;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_view_test_activity);
- mRoot = findViewById(R.id.test_activity_root);
- mTextView = findViewById(R.id.test_activity_title);
- mWidthTextView = findViewById(R.id.test_activity_width_text);
- mHeightTextView = findViewById(R.id.test_activity_height_text);
- mTouchStateTextView = findViewById(R.id.test_activity_touch_state);
- ViewTreeObserver viewTreeObserver = mRoot.getViewTreeObserver();
- if (viewTreeObserver.isAlive()) {
- viewTreeObserver.addOnGlobalLayoutListener(this::updateDimensionTexts);
- }
- updateStateText("CREATED");
- }
-
- @Override
- protected void onStart() {
- super.onStart();
- updateStateText("STARTED");
- }
-
- @Override
- protected void onResume() {
- super.onResume();
- updateStateText("RESUMED");
- }
-
- @Override
- protected void onPause() {
- super.onPause();
- updateStateText("PAUSED");
- }
-
- @Override
- protected void onStop() {
- super.onStop();
- updateStateText("STOPPED");
- }
-
- @Override
- public void onConfigurationChanged(Configuration newConfig) {
- super.onConfigurationChanged(newConfig);
- updateDimensionTexts();
- }
-
- private void updateStateText(String state) {
- Log.d(TAG, state);
- mTextView.setText(state);
- }
-
- private void updateDimensionTexts() {
- mWidthTextView.setText("" + mRoot.getWidth());
- mHeightTextView.setText("" + mRoot.getHeight());
- }
-
- private void updateTouchState(MotionEvent event) {
- switch (event.getAction()) {
- case ACTION_DOWN:
- case ACTION_MOVE:
- mTouchStateTextView.setText("[" + event.getX() + "," + event.getY() + "]");
- break;
- case ACTION_UP:
- case ACTION_CANCEL:
- mTouchStateTextView.setText("");
- break;
- }
- }
-
- @Override
- public boolean dispatchTouchEvent(MotionEvent event) {
- updateTouchState(event);
- return super.dispatchTouchEvent(event);
- }
-}
diff --git a/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewVisibilityActivity.java b/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewVisibilityActivity.java
deleted file mode 100644
index ecd2cf3c578e..000000000000
--- a/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewVisibilityActivity.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/**
- * Copyright (c) 2019 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.google.android.test.activityview;
-
-import static android.view.View.GONE;
-import static android.view.View.INVISIBLE;
-import static android.view.View.VISIBLE;
-
-import android.app.Activity;
-import android.app.ActivityView;
-import android.content.Intent;
-import android.os.Bundle;
-import android.view.View;
-import android.widget.AdapterView;
-import android.widget.ArrayAdapter;
-import android.widget.Button;
-import android.widget.Spinner;
-
-public class ActivityViewVisibilityActivity extends Activity {
- private static final String[] sVisibilityOptions = {"VISIBLE", "INVISIBLE", "GONE"};
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_view_visibility_activity);
-
- final ActivityView activityView = findViewById(R.id.activity_view);
- final Button launchButton = findViewById(R.id.activity_launch_button);
- launchButton.setOnClickListener(v -> {
- final Intent intent = new Intent(this, ActivityViewTestActivity.class);
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
- activityView.startActivity(intent);
- });
-
- final Spinner visibilitySpinner = findViewById(R.id.visibility_spinner);
- final ArrayAdapter<String> adapter = new ArrayAdapter<>(this,
- android.R.layout.simple_spinner_item, sVisibilityOptions);
- adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
- visibilitySpinner.setAdapter(adapter);
- visibilitySpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
- @Override
- public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
- switch (position) {
- case 0:
- activityView.setVisibility(VISIBLE);
- break;
- case 1:
- activityView.setVisibility(INVISIBLE);
- break;
- case 2:
- activityView.setVisibility(GONE);
- break;
- }
- }
-
- @Override
- public void onNothingSelected(AdapterView<?> parent) {
- }
- });
- }
-}
diff --git a/tests/AmSlam/AndroidManifest.xml b/tests/AmSlam/AndroidManifest.xml
index 3d39e850f024..37583a946d1e 100644
--- a/tests/AmSlam/AndroidManifest.xml
+++ b/tests/AmSlam/AndroidManifest.xml
@@ -15,125 +15,324 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="test.amslam">
+ package="test.amslam">
- <application
- android:allowBackup="false"
- android:icon="@mipmap/ic_launcher"
- android:label="@string/app_name"
- android:supportsRtl="true"
- android:theme="@style/AppTheme">
- <activity android:name=".MainActivity">
+ <application android:allowBackup="false"
+ android:icon="@mipmap/ic_launcher"
+ android:label="@string/app_name"
+ android:supportsRtl="true"
+ android:theme="@style/AppTheme">
+ <activity android:name=".MainActivity"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <receiver
- android:name=".PongReceiver"
- android:exported="false" />
+ <receiver android:name=".PongReceiver"
+ android:exported="false"/>
- <service android:name=".subreceivers.PingReceiver000" android:exported="false" android:process=":ping000" />
- <service android:name=".subreceivers.PingReceiver001" android:exported="false" android:process=":ping001" />
- <service android:name=".subreceivers.PingReceiver002" android:exported="false" android:process=":ping002" />
- <service android:name=".subreceivers.PingReceiver003" android:exported="false" android:process=":ping003" />
- <service android:name=".subreceivers.PingReceiver004" android:exported="false" android:process=":ping004" />
- <service android:name=".subreceivers.PingReceiver005" android:exported="false" android:process=":ping005" />
- <service android:name=".subreceivers.PingReceiver006" android:exported="false" android:process=":ping006" />
- <service android:name=".subreceivers.PingReceiver007" android:exported="false" android:process=":ping007" />
- <service android:name=".subreceivers.PingReceiver008" android:exported="false" android:process=":ping008" />
- <service android:name=".subreceivers.PingReceiver009" android:exported="false" android:process=":ping009" />
- <service android:name=".subreceivers.PingReceiver010" android:exported="false" android:process=":ping010" />
- <service android:name=".subreceivers.PingReceiver011" android:exported="false" android:process=":ping011" />
- <service android:name=".subreceivers.PingReceiver012" android:exported="false" android:process=":ping012" />
- <service android:name=".subreceivers.PingReceiver013" android:exported="false" android:process=":ping013" />
- <service android:name=".subreceivers.PingReceiver014" android:exported="false" android:process=":ping014" />
- <service android:name=".subreceivers.PingReceiver015" android:exported="false" android:process=":ping015" />
- <service android:name=".subreceivers.PingReceiver016" android:exported="false" android:process=":ping016" />
- <service android:name=".subreceivers.PingReceiver017" android:exported="false" android:process=":ping017" />
- <service android:name=".subreceivers.PingReceiver018" android:exported="false" android:process=":ping018" />
- <service android:name=".subreceivers.PingReceiver019" android:exported="false" android:process=":ping019" />
- <service android:name=".subreceivers.PingReceiver020" android:exported="false" android:process=":ping020" />
- <service android:name=".subreceivers.PingReceiver021" android:exported="false" android:process=":ping021" />
- <service android:name=".subreceivers.PingReceiver022" android:exported="false" android:process=":ping022" />
- <service android:name=".subreceivers.PingReceiver023" android:exported="false" android:process=":ping023" />
- <service android:name=".subreceivers.PingReceiver024" android:exported="false" android:process=":ping024" />
- <service android:name=".subreceivers.PingReceiver025" android:exported="false" android:process=":ping025" />
- <service android:name=".subreceivers.PingReceiver026" android:exported="false" android:process=":ping026" />
- <service android:name=".subreceivers.PingReceiver027" android:exported="false" android:process=":ping027" />
- <service android:name=".subreceivers.PingReceiver028" android:exported="false" android:process=":ping028" />
- <service android:name=".subreceivers.PingReceiver029" android:exported="false" android:process=":ping029" />
- <service android:name=".subreceivers.PingReceiver030" android:exported="false" android:process=":ping030" />
- <service android:name=".subreceivers.PingReceiver031" android:exported="false" android:process=":ping031" />
- <service android:name=".subreceivers.PingReceiver032" android:exported="false" android:process=":ping032" />
- <service android:name=".subreceivers.PingReceiver033" android:exported="false" android:process=":ping033" />
- <service android:name=".subreceivers.PingReceiver034" android:exported="false" android:process=":ping034" />
- <service android:name=".subreceivers.PingReceiver035" android:exported="false" android:process=":ping035" />
- <service android:name=".subreceivers.PingReceiver036" android:exported="false" android:process=":ping036" />
- <service android:name=".subreceivers.PingReceiver037" android:exported="false" android:process=":ping037" />
- <service android:name=".subreceivers.PingReceiver038" android:exported="false" android:process=":ping038" />
- <service android:name=".subreceivers.PingReceiver039" android:exported="false" android:process=":ping039" />
- <service android:name=".subreceivers.PingReceiver040" android:exported="false" android:process=":ping040" />
- <service android:name=".subreceivers.PingReceiver041" android:exported="false" android:process=":ping041" />
- <service android:name=".subreceivers.PingReceiver042" android:exported="false" android:process=":ping042" />
- <service android:name=".subreceivers.PingReceiver043" android:exported="false" android:process=":ping043" />
- <service android:name=".subreceivers.PingReceiver044" android:exported="false" android:process=":ping044" />
- <service android:name=".subreceivers.PingReceiver045" android:exported="false" android:process=":ping045" />
- <service android:name=".subreceivers.PingReceiver046" android:exported="false" android:process=":ping046" />
- <service android:name=".subreceivers.PingReceiver047" android:exported="false" android:process=":ping047" />
- <service android:name=".subreceivers.PingReceiver048" android:exported="false" android:process=":ping048" />
- <service android:name=".subreceivers.PingReceiver049" android:exported="false" android:process=":ping049" />
- <service android:name=".subreceivers.PingReceiver050" android:exported="false" android:process=":ping050" />
- <service android:name=".subreceivers.PingReceiver051" android:exported="false" android:process=":ping051" />
- <service android:name=".subreceivers.PingReceiver052" android:exported="false" android:process=":ping052" />
- <service android:name=".subreceivers.PingReceiver053" android:exported="false" android:process=":ping053" />
- <service android:name=".subreceivers.PingReceiver054" android:exported="false" android:process=":ping054" />
- <service android:name=".subreceivers.PingReceiver055" android:exported="false" android:process=":ping055" />
- <service android:name=".subreceivers.PingReceiver056" android:exported="false" android:process=":ping056" />
- <service android:name=".subreceivers.PingReceiver057" android:exported="false" android:process=":ping057" />
- <service android:name=".subreceivers.PingReceiver058" android:exported="false" android:process=":ping058" />
- <service android:name=".subreceivers.PingReceiver059" android:exported="false" android:process=":ping059" />
- <service android:name=".subreceivers.PingReceiver060" android:exported="false" android:process=":ping060" />
- <service android:name=".subreceivers.PingReceiver061" android:exported="false" android:process=":ping061" />
- <service android:name=".subreceivers.PingReceiver062" android:exported="false" android:process=":ping062" />
- <service android:name=".subreceivers.PingReceiver063" android:exported="false" android:process=":ping063" />
- <service android:name=".subreceivers.PingReceiver064" android:exported="false" android:process=":ping064" />
- <service android:name=".subreceivers.PingReceiver065" android:exported="false" android:process=":ping065" />
- <service android:name=".subreceivers.PingReceiver066" android:exported="false" android:process=":ping066" />
- <service android:name=".subreceivers.PingReceiver067" android:exported="false" android:process=":ping067" />
- <service android:name=".subreceivers.PingReceiver068" android:exported="false" android:process=":ping068" />
- <service android:name=".subreceivers.PingReceiver069" android:exported="false" android:process=":ping069" />
- <service android:name=".subreceivers.PingReceiver070" android:exported="false" android:process=":ping070" />
- <service android:name=".subreceivers.PingReceiver071" android:exported="false" android:process=":ping071" />
- <service android:name=".subreceivers.PingReceiver072" android:exported="false" android:process=":ping072" />
- <service android:name=".subreceivers.PingReceiver073" android:exported="false" android:process=":ping073" />
- <service android:name=".subreceivers.PingReceiver074" android:exported="false" android:process=":ping074" />
- <service android:name=".subreceivers.PingReceiver075" android:exported="false" android:process=":ping075" />
- <service android:name=".subreceivers.PingReceiver076" android:exported="false" android:process=":ping076" />
- <service android:name=".subreceivers.PingReceiver077" android:exported="false" android:process=":ping077" />
- <service android:name=".subreceivers.PingReceiver078" android:exported="false" android:process=":ping078" />
- <service android:name=".subreceivers.PingReceiver079" android:exported="false" android:process=":ping079" />
- <service android:name=".subreceivers.PingReceiver080" android:exported="false" android:process=":ping080" />
- <service android:name=".subreceivers.PingReceiver081" android:exported="false" android:process=":ping081" />
- <service android:name=".subreceivers.PingReceiver082" android:exported="false" android:process=":ping082" />
- <service android:name=".subreceivers.PingReceiver083" android:exported="false" android:process=":ping083" />
- <service android:name=".subreceivers.PingReceiver084" android:exported="false" android:process=":ping084" />
- <service android:name=".subreceivers.PingReceiver085" android:exported="false" android:process=":ping085" />
- <service android:name=".subreceivers.PingReceiver086" android:exported="false" android:process=":ping086" />
- <service android:name=".subreceivers.PingReceiver087" android:exported="false" android:process=":ping087" />
- <service android:name=".subreceivers.PingReceiver088" android:exported="false" android:process=":ping088" />
- <service android:name=".subreceivers.PingReceiver089" android:exported="false" android:process=":ping089" />
- <service android:name=".subreceivers.PingReceiver090" android:exported="false" android:process=":ping090" />
- <service android:name=".subreceivers.PingReceiver091" android:exported="false" android:process=":ping091" />
- <service android:name=".subreceivers.PingReceiver092" android:exported="false" android:process=":ping092" />
- <service android:name=".subreceivers.PingReceiver093" android:exported="false" android:process=":ping093" />
- <service android:name=".subreceivers.PingReceiver094" android:exported="false" android:process=":ping094" />
- <service android:name=".subreceivers.PingReceiver095" android:exported="false" android:process=":ping095" />
- <service android:name=".subreceivers.PingReceiver096" android:exported="false" android:process=":ping096" />
- <service android:name=".subreceivers.PingReceiver097" android:exported="false" android:process=":ping097" />
- <service android:name=".subreceivers.PingReceiver098" android:exported="false" android:process=":ping098" />
- <service android:name=".subreceivers.PingReceiver099" android:exported="false" android:process=":ping099" />
+ <service android:name=".subreceivers.PingReceiver000"
+ android:exported="false"
+ android:process=":ping000"/>
+ <service android:name=".subreceivers.PingReceiver001"
+ android:exported="false"
+ android:process=":ping001"/>
+ <service android:name=".subreceivers.PingReceiver002"
+ android:exported="false"
+ android:process=":ping002"/>
+ <service android:name=".subreceivers.PingReceiver003"
+ android:exported="false"
+ android:process=":ping003"/>
+ <service android:name=".subreceivers.PingReceiver004"
+ android:exported="false"
+ android:process=":ping004"/>
+ <service android:name=".subreceivers.PingReceiver005"
+ android:exported="false"
+ android:process=":ping005"/>
+ <service android:name=".subreceivers.PingReceiver006"
+ android:exported="false"
+ android:process=":ping006"/>
+ <service android:name=".subreceivers.PingReceiver007"
+ android:exported="false"
+ android:process=":ping007"/>
+ <service android:name=".subreceivers.PingReceiver008"
+ android:exported="false"
+ android:process=":ping008"/>
+ <service android:name=".subreceivers.PingReceiver009"
+ android:exported="false"
+ android:process=":ping009"/>
+ <service android:name=".subreceivers.PingReceiver010"
+ android:exported="false"
+ android:process=":ping010"/>
+ <service android:name=".subreceivers.PingReceiver011"
+ android:exported="false"
+ android:process=":ping011"/>
+ <service android:name=".subreceivers.PingReceiver012"
+ android:exported="false"
+ android:process=":ping012"/>
+ <service android:name=".subreceivers.PingReceiver013"
+ android:exported="false"
+ android:process=":ping013"/>
+ <service android:name=".subreceivers.PingReceiver014"
+ android:exported="false"
+ android:process=":ping014"/>
+ <service android:name=".subreceivers.PingReceiver015"
+ android:exported="false"
+ android:process=":ping015"/>
+ <service android:name=".subreceivers.PingReceiver016"
+ android:exported="false"
+ android:process=":ping016"/>
+ <service android:name=".subreceivers.PingReceiver017"
+ android:exported="false"
+ android:process=":ping017"/>
+ <service android:name=".subreceivers.PingReceiver018"
+ android:exported="false"
+ android:process=":ping018"/>
+ <service android:name=".subreceivers.PingReceiver019"
+ android:exported="false"
+ android:process=":ping019"/>
+ <service android:name=".subreceivers.PingReceiver020"
+ android:exported="false"
+ android:process=":ping020"/>
+ <service android:name=".subreceivers.PingReceiver021"
+ android:exported="false"
+ android:process=":ping021"/>
+ <service android:name=".subreceivers.PingReceiver022"
+ android:exported="false"
+ android:process=":ping022"/>
+ <service android:name=".subreceivers.PingReceiver023"
+ android:exported="false"
+ android:process=":ping023"/>
+ <service android:name=".subreceivers.PingReceiver024"
+ android:exported="false"
+ android:process=":ping024"/>
+ <service android:name=".subreceivers.PingReceiver025"
+ android:exported="false"
+ android:process=":ping025"/>
+ <service android:name=".subreceivers.PingReceiver026"
+ android:exported="false"
+ android:process=":ping026"/>
+ <service android:name=".subreceivers.PingReceiver027"
+ android:exported="false"
+ android:process=":ping027"/>
+ <service android:name=".subreceivers.PingReceiver028"
+ android:exported="false"
+ android:process=":ping028"/>
+ <service android:name=".subreceivers.PingReceiver029"
+ android:exported="false"
+ android:process=":ping029"/>
+ <service android:name=".subreceivers.PingReceiver030"
+ android:exported="false"
+ android:process=":ping030"/>
+ <service android:name=".subreceivers.PingReceiver031"
+ android:exported="false"
+ android:process=":ping031"/>
+ <service android:name=".subreceivers.PingReceiver032"
+ android:exported="false"
+ android:process=":ping032"/>
+ <service android:name=".subreceivers.PingReceiver033"
+ android:exported="false"
+ android:process=":ping033"/>
+ <service android:name=".subreceivers.PingReceiver034"
+ android:exported="false"
+ android:process=":ping034"/>
+ <service android:name=".subreceivers.PingReceiver035"
+ android:exported="false"
+ android:process=":ping035"/>
+ <service android:name=".subreceivers.PingReceiver036"
+ android:exported="false"
+ android:process=":ping036"/>
+ <service android:name=".subreceivers.PingReceiver037"
+ android:exported="false"
+ android:process=":ping037"/>
+ <service android:name=".subreceivers.PingReceiver038"
+ android:exported="false"
+ android:process=":ping038"/>
+ <service android:name=".subreceivers.PingReceiver039"
+ android:exported="false"
+ android:process=":ping039"/>
+ <service android:name=".subreceivers.PingReceiver040"
+ android:exported="false"
+ android:process=":ping040"/>
+ <service android:name=".subreceivers.PingReceiver041"
+ android:exported="false"
+ android:process=":ping041"/>
+ <service android:name=".subreceivers.PingReceiver042"
+ android:exported="false"
+ android:process=":ping042"/>
+ <service android:name=".subreceivers.PingReceiver043"
+ android:exported="false"
+ android:process=":ping043"/>
+ <service android:name=".subreceivers.PingReceiver044"
+ android:exported="false"
+ android:process=":ping044"/>
+ <service android:name=".subreceivers.PingReceiver045"
+ android:exported="false"
+ android:process=":ping045"/>
+ <service android:name=".subreceivers.PingReceiver046"
+ android:exported="false"
+ android:process=":ping046"/>
+ <service android:name=".subreceivers.PingReceiver047"
+ android:exported="false"
+ android:process=":ping047"/>
+ <service android:name=".subreceivers.PingReceiver048"
+ android:exported="false"
+ android:process=":ping048"/>
+ <service android:name=".subreceivers.PingReceiver049"
+ android:exported="false"
+ android:process=":ping049"/>
+ <service android:name=".subreceivers.PingReceiver050"
+ android:exported="false"
+ android:process=":ping050"/>
+ <service android:name=".subreceivers.PingReceiver051"
+ android:exported="false"
+ android:process=":ping051"/>
+ <service android:name=".subreceivers.PingReceiver052"
+ android:exported="false"
+ android:process=":ping052"/>
+ <service android:name=".subreceivers.PingReceiver053"
+ android:exported="false"
+ android:process=":ping053"/>
+ <service android:name=".subreceivers.PingReceiver054"
+ android:exported="false"
+ android:process=":ping054"/>
+ <service android:name=".subreceivers.PingReceiver055"
+ android:exported="false"
+ android:process=":ping055"/>
+ <service android:name=".subreceivers.PingReceiver056"
+ android:exported="false"
+ android:process=":ping056"/>
+ <service android:name=".subreceivers.PingReceiver057"
+ android:exported="false"
+ android:process=":ping057"/>
+ <service android:name=".subreceivers.PingReceiver058"
+ android:exported="false"
+ android:process=":ping058"/>
+ <service android:name=".subreceivers.PingReceiver059"
+ android:exported="false"
+ android:process=":ping059"/>
+ <service android:name=".subreceivers.PingReceiver060"
+ android:exported="false"
+ android:process=":ping060"/>
+ <service android:name=".subreceivers.PingReceiver061"
+ android:exported="false"
+ android:process=":ping061"/>
+ <service android:name=".subreceivers.PingReceiver062"
+ android:exported="false"
+ android:process=":ping062"/>
+ <service android:name=".subreceivers.PingReceiver063"
+ android:exported="false"
+ android:process=":ping063"/>
+ <service android:name=".subreceivers.PingReceiver064"
+ android:exported="false"
+ android:process=":ping064"/>
+ <service android:name=".subreceivers.PingReceiver065"
+ android:exported="false"
+ android:process=":ping065"/>
+ <service android:name=".subreceivers.PingReceiver066"
+ android:exported="false"
+ android:process=":ping066"/>
+ <service android:name=".subreceivers.PingReceiver067"
+ android:exported="false"
+ android:process=":ping067"/>
+ <service android:name=".subreceivers.PingReceiver068"
+ android:exported="false"
+ android:process=":ping068"/>
+ <service android:name=".subreceivers.PingReceiver069"
+ android:exported="false"
+ android:process=":ping069"/>
+ <service android:name=".subreceivers.PingReceiver070"
+ android:exported="false"
+ android:process=":ping070"/>
+ <service android:name=".subreceivers.PingReceiver071"
+ android:exported="false"
+ android:process=":ping071"/>
+ <service android:name=".subreceivers.PingReceiver072"
+ android:exported="false"
+ android:process=":ping072"/>
+ <service android:name=".subreceivers.PingReceiver073"
+ android:exported="false"
+ android:process=":ping073"/>
+ <service android:name=".subreceivers.PingReceiver074"
+ android:exported="false"
+ android:process=":ping074"/>
+ <service android:name=".subreceivers.PingReceiver075"
+ android:exported="false"
+ android:process=":ping075"/>
+ <service android:name=".subreceivers.PingReceiver076"
+ android:exported="false"
+ android:process=":ping076"/>
+ <service android:name=".subreceivers.PingReceiver077"
+ android:exported="false"
+ android:process=":ping077"/>
+ <service android:name=".subreceivers.PingReceiver078"
+ android:exported="false"
+ android:process=":ping078"/>
+ <service android:name=".subreceivers.PingReceiver079"
+ android:exported="false"
+ android:process=":ping079"/>
+ <service android:name=".subreceivers.PingReceiver080"
+ android:exported="false"
+ android:process=":ping080"/>
+ <service android:name=".subreceivers.PingReceiver081"
+ android:exported="false"
+ android:process=":ping081"/>
+ <service android:name=".subreceivers.PingReceiver082"
+ android:exported="false"
+ android:process=":ping082"/>
+ <service android:name=".subreceivers.PingReceiver083"
+ android:exported="false"
+ android:process=":ping083"/>
+ <service android:name=".subreceivers.PingReceiver084"
+ android:exported="false"
+ android:process=":ping084"/>
+ <service android:name=".subreceivers.PingReceiver085"
+ android:exported="false"
+ android:process=":ping085"/>
+ <service android:name=".subreceivers.PingReceiver086"
+ android:exported="false"
+ android:process=":ping086"/>
+ <service android:name=".subreceivers.PingReceiver087"
+ android:exported="false"
+ android:process=":ping087"/>
+ <service android:name=".subreceivers.PingReceiver088"
+ android:exported="false"
+ android:process=":ping088"/>
+ <service android:name=".subreceivers.PingReceiver089"
+ android:exported="false"
+ android:process=":ping089"/>
+ <service android:name=".subreceivers.PingReceiver090"
+ android:exported="false"
+ android:process=":ping090"/>
+ <service android:name=".subreceivers.PingReceiver091"
+ android:exported="false"
+ android:process=":ping091"/>
+ <service android:name=".subreceivers.PingReceiver092"
+ android:exported="false"
+ android:process=":ping092"/>
+ <service android:name=".subreceivers.PingReceiver093"
+ android:exported="false"
+ android:process=":ping093"/>
+ <service android:name=".subreceivers.PingReceiver094"
+ android:exported="false"
+ android:process=":ping094"/>
+ <service android:name=".subreceivers.PingReceiver095"
+ android:exported="false"
+ android:process=":ping095"/>
+ <service android:name=".subreceivers.PingReceiver096"
+ android:exported="false"
+ android:process=":ping096"/>
+ <service android:name=".subreceivers.PingReceiver097"
+ android:exported="false"
+ android:process=":ping097"/>
+ <service android:name=".subreceivers.PingReceiver098"
+ android:exported="false"
+ android:process=":ping098"/>
+ <service android:name=".subreceivers.PingReceiver099"
+ android:exported="false"
+ android:process=":ping099"/>
</application>
</manifest>
diff --git a/tests/ApkVerityTest/Android.bp b/tests/ApkVerityTest/Android.bp
index 0cdb11fe7945..4e98f4264e11 100644
--- a/tests/ApkVerityTest/Android.bp
+++ b/tests/ApkVerityTest/Android.bp
@@ -25,6 +25,10 @@ java_test_host {
name: "ApkVerityTest",
srcs: ["src/**/*.java"],
libs: ["tradefed", "compatibility-tradefed", "compatibility-host-util"],
+ static_libs: [
+ "block_device_writer_jar",
+ "frameworks-base-hostutils",
+ ],
test_suites: ["general-tests", "vts"],
target_required: [
"block_device_writer_module",
diff --git a/tests/ApkVerityTest/block_device_writer/Android.bp b/tests/ApkVerityTest/block_device_writer/Android.bp
index b5a46da402eb..0b5f0f611916 100644
--- a/tests/ApkVerityTest/block_device_writer/Android.bp
+++ b/tests/ApkVerityTest/block_device_writer/Android.bp
@@ -60,3 +60,9 @@ cc_test {
test_suites: ["general-tests", "pts", "vts"],
gtest: false,
}
+
+java_library_host {
+ name: "block_device_writer_jar",
+ srcs: ["src/**/*.java"],
+ libs: ["tradefed", "junit"],
+}
diff --git a/tests/ApkVerityTest/block_device_writer/src/com/android/blockdevicewriter/BlockDeviceWriter.java b/tests/ApkVerityTest/block_device_writer/src/com/android/blockdevicewriter/BlockDeviceWriter.java
new file mode 100644
index 000000000000..5c2c15b22bb0
--- /dev/null
+++ b/tests/ApkVerityTest/block_device_writer/src/com/android/blockdevicewriter/BlockDeviceWriter.java
@@ -0,0 +1,100 @@
+/*
+ * 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.blockdevicewriter;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.util.CommandResult;
+import com.android.tradefed.util.CommandStatus;
+
+import java.util.ArrayList;
+
+/**
+ * Wrapper for block_device_writer command.
+ *
+ * <p>To use this class, please push block_device_writer binary to /data/local/tmp.
+ * 1. In Android.bp, add:
+ * <pre>
+ * target_required: ["block_device_writer_module"],
+ * </pre>
+ * 2. In AndroidText.xml, add:
+ * <pre>
+ * <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ * <option name="push" value="block_device_writer->/data/local/tmp/block_device_writer" />
+ * </target_preparer>
+ * </pre>
+ */
+public final class BlockDeviceWriter {
+ private static final String EXECUTABLE = "/data/local/tmp/block_device_writer";
+
+ /**
+ * Modifies a byte of the file directly against the backing block storage.
+ *
+ * The effect can only be observed when the page cache is read from disk again. See
+ * {@link #dropCaches} for details.
+ */
+ public static void damageFileAgainstBlockDevice(ITestDevice device, String path,
+ long offsetOfTargetingByte)
+ throws DeviceNotAvailableException {
+ assertThat(path).startsWith("/data/");
+ ITestDevice.MountPointInfo mountPoint = device.getMountPointInfo("/data");
+ ArrayList<String> args = new ArrayList<>();
+ args.add(EXECUTABLE);
+ if ("f2fs".equals(mountPoint.type)) {
+ args.add("--use-f2fs-pinning");
+ }
+ args.add(mountPoint.filesystem);
+ args.add(path);
+ args.add(Long.toString(offsetOfTargetingByte));
+ CommandResult result = device.executeShellV2Command(String.join(" ", args));
+ assertWithMessage(
+ String.format("stdout=%s\nstderr=%s", result.getStdout(), result.getStderr()))
+ .that(result.getStatus()).isEqualTo(CommandStatus.SUCCESS);
+ }
+
+ /**
+ * Drops file caches so that the result of {@link #damageFileAgainstBlockDevice} can be
+ * observed. If a process has an open FD or memory map of the damaged file, cache eviction won't
+ * happen and the damage cannot be observed.
+ */
+ public static void dropCaches(ITestDevice device) throws DeviceNotAvailableException {
+ CommandResult result = device.executeShellV2Command(
+ "sync && echo 1 > /proc/sys/vm/drop_caches");
+ assertThat(result.getStatus()).isEqualTo(CommandStatus.SUCCESS);
+ }
+
+ public static void assertFileNotOpen(ITestDevice device, String path)
+ throws DeviceNotAvailableException {
+ CommandResult result = device.executeShellV2Command("lsof " + path);
+ assertThat(result.getStatus()).isEqualTo(CommandStatus.SUCCESS);
+ assertThat(result.getStdout()).isEmpty();
+ }
+
+ /**
+ * Checks if the give offset of a file can be read.
+ * This method will return false if the file has fs-verity enabled and is damaged at the offset.
+ */
+ public static boolean canReadByte(ITestDevice device, String filePath, long offset)
+ throws DeviceNotAvailableException {
+ CommandResult result = device.executeShellV2Command(
+ "dd if=" + filePath + " bs=1 count=1 skip=" + Long.toString(offset));
+ return result.getStatus() == CommandStatus.SUCCESS;
+ }
+}
diff --git a/tests/ApkVerityTest/src/com/android/apkverity/ApkVerityTest.java b/tests/ApkVerityTest/src/com/android/apkverity/ApkVerityTest.java
index 629b6c714ae8..d96005b8a71a 100644
--- a/tests/ApkVerityTest/src/com/android/apkverity/ApkVerityTest.java
+++ b/tests/ApkVerityTest/src/com/android/apkverity/ApkVerityTest.java
@@ -21,10 +21,11 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
-import static org.junit.Assume.assumeTrue;
import android.platform.test.annotations.RootPermissionTest;
+import com.android.blockdevicewriter.BlockDeviceWriter;
+import com.android.fsverity.AddFsVerityCertRule;
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.log.LogUtil.CLog;
@@ -35,6 +36,7 @@ import com.android.tradefed.util.CommandStatus;
import org.junit.After;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -85,29 +87,21 @@ public class ApkVerityTest extends BaseHostJUnit4Test {
private static final String DAMAGING_EXECUTABLE = "/data/local/tmp/block_device_writer";
private static final String CERT_PATH = "/data/local/tmp/ApkVerityTestCert.der";
- private static final String APK_VERITY_STANDARD_MODE = "2";
-
/** Only 4K page is supported by fs-verity currently. */
private static final int FSVERITY_PAGE_SIZE = 4096;
+ @Rule
+ public final AddFsVerityCertRule mAddFsVerityCertRule =
+ new AddFsVerityCertRule(this, CERT_PATH);
+
private ITestDevice mDevice;
- private String mKeyId;
+ private boolean mDmRequireFsVerity;
@Before
public void setUp() throws DeviceNotAvailableException {
mDevice = getDevice();
-
- String apkVerityMode = mDevice.getProperty("ro.apk_verity.mode");
- assumeTrue(mDevice.getLaunchApiLevel() >= 30
- || APK_VERITY_STANDARD_MODE.equals(apkVerityMode));
-
- mKeyId = expectRemoteCommandToSucceed(
- "mini-keyctl padd asymmetric fsv_test .fs-verity < " + CERT_PATH).trim();
- if (!mKeyId.matches("^\\d+$")) {
- String keyId = mKeyId;
- mKeyId = null;
- fail("Key ID is not decimal: " + keyId);
- }
+ mDmRequireFsVerity = "true".equals(
+ mDevice.getProperty("pm.dexopt.dm.require_fsverity"));
uninstallPackage(TARGET_PACKAGE);
}
@@ -115,10 +109,6 @@ public class ApkVerityTest extends BaseHostJUnit4Test {
@After
public void tearDown() throws DeviceNotAvailableException {
uninstallPackage(TARGET_PACKAGE);
-
- if (mKeyId != null) {
- expectRemoteCommandToSucceed("mini-keyctl unlink " + mKeyId + " .fs-verity");
- }
}
@Test
@@ -137,7 +127,7 @@ public class ApkVerityTest extends BaseHostJUnit4Test {
verifyInstalledFiles(
INSTALLED_BASE_APK,
INSTALLED_BASE_APK_FSV_SIG);
- verifyInstalledFilesHaveFsverity();
+ verifyInstalledFilesHaveFsverity(INSTALLED_BASE_APK);
}
@Test
@@ -164,7 +154,9 @@ public class ApkVerityTest extends BaseHostJUnit4Test {
INSTALLED_BASE_APK_FSV_SIG,
INSTALLED_SPLIT_APK,
INSTALLED_SPLIT_APK_FSV_SIG);
- verifyInstalledFilesHaveFsverity();
+ verifyInstalledFilesHaveFsverity(
+ INSTALLED_BASE_APK,
+ INSTALLED_SPLIT_APK);
}
@Test
@@ -180,7 +172,9 @@ public class ApkVerityTest extends BaseHostJUnit4Test {
INSTALLED_BASE_APK_FSV_SIG,
INSTALLED_BASE_DM,
INSTALLED_BASE_DM_FSV_SIG);
- verifyInstalledFilesHaveFsverity();
+ verifyInstalledFilesHaveFsverity(
+ INSTALLED_BASE_APK,
+ INSTALLED_BASE_DM);
}
@Test
@@ -202,7 +196,11 @@ public class ApkVerityTest extends BaseHostJUnit4Test {
INSTALLED_SPLIT_APK_FSV_SIG,
INSTALLED_SPLIT_DM,
INSTALLED_SPLIT_DM_FSV_SIG);
- verifyInstalledFilesHaveFsverity();
+ verifyInstalledFilesHaveFsverity(
+ INSTALLED_BASE_APK,
+ INSTALLED_BASE_DM,
+ INSTALLED_SPLIT_APK,
+ INSTALLED_SPLIT_DM);
}
@Test
@@ -226,7 +224,9 @@ public class ApkVerityTest extends BaseHostJUnit4Test {
INSTALLED_BASE_APK_FSV_SIG,
INSTALLED_SPLIT_APK,
INSTALLED_SPLIT_APK_FSV_SIG);
- verifyInstalledFilesHaveFsverity();
+ verifyInstalledFilesHaveFsverity(
+ INSTALLED_BASE_APK,
+ INSTALLED_SPLIT_APK);
}
@Test
@@ -263,39 +263,92 @@ public class ApkVerityTest extends BaseHostJUnit4Test {
INSTALLED_BASE_APK,
INSTALLED_SPLIT_APK,
INSTALLED_SPLIT_APK_FSV_SIG);
-
}
@Test
- public void testInstallOnlyBaseHasFsvSig()
+ public void testInstallOnlyDmHasFsvSig()
throws DeviceNotAvailableException, FileNotFoundException {
new InstallMultiple()
- .addFileAndSignature(BASE_APK)
+ .addFile(BASE_APK)
+ .addFileAndSignature(BASE_APK_DM)
+ .addFile(SPLIT_APK)
+ .addFileAndSignature(SPLIT_APK_DM)
+ .run();
+ verifyInstalledFiles(
+ INSTALLED_BASE_APK,
+ INSTALLED_BASE_DM,
+ INSTALLED_BASE_DM_FSV_SIG,
+ INSTALLED_SPLIT_APK,
+ INSTALLED_SPLIT_DM,
+ INSTALLED_SPLIT_DM_FSV_SIG);
+ verifyInstalledFilesHaveFsverity(
+ INSTALLED_BASE_DM,
+ INSTALLED_SPLIT_DM);
+ }
+
+ @Test
+ public void testInstallDmWithoutFsvSig_Base()
+ throws DeviceNotAvailableException, FileNotFoundException {
+ InstallMultiple installer = new InstallMultiple()
+ .addFile(BASE_APK)
.addFile(BASE_APK_DM)
.addFile(SPLIT_APK)
- .addFile(SPLIT_APK_DM)
- .runExpectingFailure();
+ .addFileAndSignature(SPLIT_APK_DM);
+ if (mDmRequireFsVerity) {
+ installer.runExpectingFailure();
+ } else {
+ installer.run();
+ verifyInstalledFiles(
+ INSTALLED_BASE_APK,
+ INSTALLED_BASE_DM,
+ INSTALLED_SPLIT_APK,
+ INSTALLED_SPLIT_DM,
+ INSTALLED_SPLIT_DM_FSV_SIG);
+ verifyInstalledFilesHaveFsverity(INSTALLED_SPLIT_DM);
+ }
}
@Test
- public void testInstallOnlyDmHasFsvSig()
+ public void testInstallDmWithoutFsvSig_Split()
throws DeviceNotAvailableException, FileNotFoundException {
- new InstallMultiple()
+ InstallMultiple installer = new InstallMultiple()
.addFile(BASE_APK)
.addFileAndSignature(BASE_APK_DM)
.addFile(SPLIT_APK)
- .addFile(SPLIT_APK_DM)
+ .addFile(SPLIT_APK_DM);
+ if (mDmRequireFsVerity) {
+ installer.runExpectingFailure();
+ } else {
+ installer.run();
+ verifyInstalledFiles(
+ INSTALLED_BASE_APK,
+ INSTALLED_BASE_DM,
+ INSTALLED_BASE_DM_FSV_SIG,
+ INSTALLED_SPLIT_APK,
+ INSTALLED_SPLIT_DM);
+ verifyInstalledFilesHaveFsverity(INSTALLED_BASE_DM);
+ }
+ }
+
+ @Test
+ public void testInstallSomeApkIsMissingFsvSig_Base()
+ throws DeviceNotAvailableException, FileNotFoundException {
+ new InstallMultiple()
+ .addFileAndSignature(BASE_APK)
+ .addFileAndSignature(BASE_APK_DM)
+ .addFile(SPLIT_APK)
+ .addFileAndSignature(SPLIT_APK_DM)
.runExpectingFailure();
}
@Test
- public void testInstallOnlySplitHasFsvSig()
+ public void testInstallSomeApkIsMissingFsvSig_Split()
throws DeviceNotAvailableException, FileNotFoundException {
new InstallMultiple()
.addFile(BASE_APK)
- .addFile(BASE_APK_DM)
+ .addFileAndSignature(BASE_APK_DM)
.addFileAndSignature(SPLIT_APK)
- .addFile(SPLIT_APK_DM)
+ .addFileAndSignature(SPLIT_APK_DM)
.runExpectingFailure();
}
@@ -348,22 +401,23 @@ public class ApkVerityTest extends BaseHostJUnit4Test {
long offsetFirstByte = 0;
// The first two pages should be both readable at first.
- assertTrue(canReadByte(apkPath, offsetFirstByte));
+ assertTrue(BlockDeviceWriter.canReadByte(mDevice, apkPath, offsetFirstByte));
if (apkSize > offsetFirstByte + FSVERITY_PAGE_SIZE) {
- assertTrue(canReadByte(apkPath, offsetFirstByte + FSVERITY_PAGE_SIZE));
+ assertTrue(BlockDeviceWriter.canReadByte(mDevice, apkPath,
+ offsetFirstByte + FSVERITY_PAGE_SIZE));
}
// Damage the file directly against the block device.
damageFileAgainstBlockDevice(apkPath, offsetFirstByte);
// Expect actual read from disk to fail but only at damaged page.
- dropCaches();
- assertFalse(canReadByte(apkPath, offsetFirstByte));
+ BlockDeviceWriter.dropCaches(mDevice);
+ assertFalse(BlockDeviceWriter.canReadByte(mDevice, apkPath, offsetFirstByte));
if (apkSize > offsetFirstByte + FSVERITY_PAGE_SIZE) {
long lastByteOfTheSamePage =
offsetFirstByte % FSVERITY_PAGE_SIZE + FSVERITY_PAGE_SIZE - 1;
- assertFalse(canReadByte(apkPath, lastByteOfTheSamePage));
- assertTrue(canReadByte(apkPath, lastByteOfTheSamePage + 1));
+ assertFalse(BlockDeviceWriter.canReadByte(mDevice, apkPath, lastByteOfTheSamePage));
+ assertTrue(BlockDeviceWriter.canReadByte(mDevice, apkPath, lastByteOfTheSamePage + 1));
}
}
@@ -376,55 +430,55 @@ public class ApkVerityTest extends BaseHostJUnit4Test {
long offsetOfLastByte = apkSize - 1;
// The first two pages should be both readable at first.
- assertTrue(canReadByte(apkPath, offsetOfLastByte));
+ assertTrue(BlockDeviceWriter.canReadByte(mDevice, apkPath, offsetOfLastByte));
if (offsetOfLastByte - FSVERITY_PAGE_SIZE > 0) {
- assertTrue(canReadByte(apkPath, offsetOfLastByte - FSVERITY_PAGE_SIZE));
+ assertTrue(BlockDeviceWriter.canReadByte(mDevice, apkPath,
+ offsetOfLastByte - FSVERITY_PAGE_SIZE));
}
// Damage the file directly against the block device.
damageFileAgainstBlockDevice(apkPath, offsetOfLastByte);
// Expect actual read from disk to fail but only at damaged page.
- dropCaches();
- assertFalse(canReadByte(apkPath, offsetOfLastByte));
+ BlockDeviceWriter.dropCaches(mDevice);
+ assertFalse(BlockDeviceWriter.canReadByte(mDevice, apkPath, offsetOfLastByte));
if (offsetOfLastByte - FSVERITY_PAGE_SIZE > 0) {
long firstByteOfTheSamePage = offsetOfLastByte - offsetOfLastByte % FSVERITY_PAGE_SIZE;
- assertFalse(canReadByte(apkPath, firstByteOfTheSamePage));
- assertTrue(canReadByte(apkPath, firstByteOfTheSamePage - 1));
+ assertFalse(BlockDeviceWriter.canReadByte(mDevice, apkPath, firstByteOfTheSamePage));
+ assertTrue(BlockDeviceWriter.canReadByte(mDevice, apkPath, firstByteOfTheSamePage - 1));
}
}
- private void verifyInstalledFilesHaveFsverity() throws DeviceNotAvailableException {
+ private void verifyInstalledFilesHaveFsverity(String... filenames)
+ throws DeviceNotAvailableException {
// Verify that all files are protected by fs-verity
String apkPath = getApkPath(TARGET_PACKAGE);
String appDir = apkPath.substring(0, apkPath.lastIndexOf("/"));
long kTargetOffset = 0;
- for (String basename : expectRemoteCommandToSucceed("ls " + appDir).split("\n")) {
- if (basename.endsWith(".apk") || basename.endsWith(".dm")) {
- String path = appDir + "/" + basename;
- damageFileAgainstBlockDevice(path, kTargetOffset);
-
- // Retry is sometimes needed to pass the test. Package manager may have FD leaks
- // (see b/122744005 as example) that prevents the file in question to be evicted
- // from filesystem cache. Forcing GC workarounds the problem.
- int retry = 5;
- for (; retry > 0; retry--) {
- dropCaches();
- if (!canReadByte(path, kTargetOffset)) {
- break;
- }
- try {
- CLog.d("lsof: " + expectRemoteCommandToSucceed("lsof " + apkPath));
- Thread.sleep(1000);
- String pid = expectRemoteCommandToSucceed("pidof system_server");
- mDevice.executeShellV2Command("kill -10 " + pid); // force GC
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- return;
- }
+ for (String basename : filenames) {
+ String path = appDir + "/" + basename;
+ damageFileAgainstBlockDevice(path, kTargetOffset);
+
+ // Retry is sometimes needed to pass the test. Package manager may have FD leaks
+ // (see b/122744005 as example) that prevents the file in question to be evicted
+ // from filesystem cache. Forcing GC workarounds the problem.
+ int retry = 5;
+ for (; retry > 0; retry--) {
+ BlockDeviceWriter.dropCaches(mDevice);
+ if (!BlockDeviceWriter.canReadByte(mDevice, path, kTargetOffset)) {
+ break;
+ }
+ try {
+ CLog.d("lsof: " + expectRemoteCommandToSucceed("lsof " + apkPath));
+ Thread.sleep(1000);
+ String pid = expectRemoteCommandToSucceed("pidof system_server");
+ mDevice.executeShellV2Command("kill -10 " + pid); // force GC
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ return;
}
- assertTrue("Read from " + path + " should fail", retry > 0);
}
+ assertTrue("Read from " + path + " should fail", retry > 0);
}
}
@@ -465,16 +519,6 @@ public class ApkVerityTest extends BaseHostJUnit4Test {
return Long.parseLong(expectRemoteCommandToSucceed("stat -c '%s' " + packageName).trim());
}
- private void dropCaches() throws DeviceNotAvailableException {
- expectRemoteCommandToSucceed("sync && echo 1 > /proc/sys/vm/drop_caches");
- }
-
- private boolean canReadByte(String filePath, long offset) throws DeviceNotAvailableException {
- CommandResult result = mDevice.executeShellV2Command(
- "dd if=" + filePath + " bs=1 count=1 skip=" + Long.toString(offset));
- return result.getStatus() == CommandStatus.SUCCESS;
- }
-
private String expectRemoteCommandToSucceed(String cmd) throws DeviceNotAvailableException {
CommandResult result = mDevice.executeShellV2Command(cmd);
assertEquals("`" + cmd + "` failed: " + result.getStderr(), CommandStatus.SUCCESS,
diff --git a/tests/AppResourcesLoaders/AndroidManifest.xml b/tests/AppResourcesLoaders/AndroidManifest.xml
index cb403b968abf..61011008d949 100644
--- a/tests/AppResourcesLoaders/AndroidManifest.xml
+++ b/tests/AppResourcesLoaders/AndroidManifest.xml
@@ -16,16 +16,17 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.example.loaders">
+ package="com.android.example.loaders">
<application android:label="AppResourcesLoaders"
- android:name=".LoadersApplication">
- <activity android:name=".LoaderActivity">
+ android:name=".LoadersApplication">
+ <activity android:name=".LoaderActivity"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:name=".LoaderActivityIsolated"
- android:process="com.android.phone" />
+ android:process="com.android.phone"/>
</application>
</manifest>
diff --git a/tests/Assist/AndroidManifest.xml b/tests/Assist/AndroidManifest.xml
index 9d4c4ad17454..2f6f50bd4f48 100644
--- a/tests/Assist/AndroidManifest.xml
+++ b/tests/Assist/AndroidManifest.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2015 The Android Open Source Project
~
@@ -15,35 +16,34 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.test.assist">
+ package="com.android.test.assist">
<application>
<service android:name="AssistInteractionService"
- android:label="Test Assist Interaction Service"
- android:permission="android.permission.BIND_VOICE_INTERACTION"
- android:process=":interactor">
+ android:label="Test Assist Interaction Service"
+ android:permission="android.permission.BIND_VOICE_INTERACTION"
+ android:process=":interactor"
+ android:exported="true">
<meta-data android:name="android.voice_interaction"
- android:resource="@xml/interaction_service" />
+ android:resource="@xml/interaction_service"/>
<intent-filter>
- <action android:name="android.service.voice.VoiceInteractionService" />
+ <action android:name="android.service.voice.VoiceInteractionService"/>
</intent-filter>
- <meta-data
- android:name="com.android.systemui.action_assist_icon"
- android:resource="@drawable/assistant" />
- <meta-data
- android:name="com.android.keyguard.layout"
- android:resource="@layout/keyguard_preview" />
+ <meta-data android:name="com.android.systemui.action_assist_icon"
+ android:resource="@drawable/assistant"/>
+ <meta-data android:name="com.android.keyguard.layout"
+ android:resource="@layout/keyguard_preview"/>
</service>
<service android:name="AssistInteractionSessionService"
- android:permission="android.permission.BIND_VOICE_INTERACTION"
- android:process=":session">
+ android:permission="android.permission.BIND_VOICE_INTERACTION"
+ android:process=":session">
</service>
<activity android:name=".AboveKeyguardActivity"
- android:label="Test Above Keyguard Activity"
- android:theme="@android:style/Theme.NoTitleBar"
- android:excludeFromRecents="true"
- android:launchMode="singleTask"
- android:exported="false" >
+ android:label="Test Above Keyguard Activity"
+ android:theme="@android:style/Theme.NoTitleBar"
+ android:excludeFromRecents="true"
+ android:launchMode="singleTask"
+ android:exported="false">
</activity>
</application>
</manifest>
diff --git a/tests/AutoVerify/app1/Android.bp b/tests/AutoVerify/app1/Android.bp
deleted file mode 100644
index 0e26067d803e..000000000000
--- a/tests/AutoVerify/app1/Android.bp
+++ /dev/null
@@ -1,20 +0,0 @@
-package {
- // 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"
- // to get the below license kinds:
- // SPDX-license-identifier-Apache-2.0
- default_applicable_licenses: ["frameworks_base_license"],
-}
-
-android_app {
- name: "AutoVerifyTest",
- srcs: ["src/**/*.java"],
- resource_dirs: ["res"],
- platform_apis: true,
- min_sdk_version: "26",
- target_sdk_version: "26",
- optimize: {
- enabled: false,
- },
-}
diff --git a/tests/AutoVerify/app1/AndroidManifest.xml b/tests/AutoVerify/app1/AndroidManifest.xml
deleted file mode 100644
index d9caad490d82..000000000000
--- a/tests/AutoVerify/app1/AndroidManifest.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2020 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.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.test.autoverify" >
-
- <uses-sdk android:targetSdkVersion="26" />
-
- <application
- android:label="@string/app_name" >
- <activity
- android:name=".MainActivity"
- android:label="@string/app_name" >
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
-
- <intent-filter android:autoVerify="true">
- <action android:name="android.intent.action.VIEW" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.BROWSABLE" />
- <data android:scheme="http" />
- <data android:scheme="https" />
- <data android:host="explicit.example.com" />
- </intent-filter>
- </activity>
- </application>
-</manifest>
diff --git a/tests/AutoVerify/app1/res/values/strings.xml b/tests/AutoVerify/app1/res/values/strings.xml
deleted file mode 100644
index e234355041c6..000000000000
--- a/tests/AutoVerify/app1/res/values/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-Copyright 2020 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.
--->
-
-<resources>
- <!-- app icon label, do not translate -->
- <string name="app_name" translatable="false">AutoVerify Test</string>
-</resources>
diff --git a/tests/AutoVerify/app2/Android.bp b/tests/AutoVerify/app2/Android.bp
deleted file mode 100644
index 5fcff1a70783..000000000000
--- a/tests/AutoVerify/app2/Android.bp
+++ /dev/null
@@ -1,20 +0,0 @@
-package {
- // 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"
- // to get the below license kinds:
- // SPDX-license-identifier-Apache-2.0
- default_applicable_licenses: ["frameworks_base_license"],
-}
-
-android_app {
- name: "AutoVerifyTest2",
- srcs: ["src/**/*.java"],
- resource_dirs: ["res"],
- platform_apis: true,
- min_sdk_version: "26",
- target_sdk_version: "26",
- optimize: {
- enabled: false,
- },
-}
diff --git a/tests/AutoVerify/app2/AndroidManifest.xml b/tests/AutoVerify/app2/AndroidManifest.xml
deleted file mode 100644
index a00807883cfc..000000000000
--- a/tests/AutoVerify/app2/AndroidManifest.xml
+++ /dev/null
@@ -1,44 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2020 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.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.test.autoverify" >
-
- <uses-sdk android:targetSdkVersion="26" />
-
- <application
- android:label="@string/app_name" >
- <activity
- android:name=".MainActivity"
- android:label="@string/app_name" >
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
-
- <intent-filter android:autoVerify="true">
- <action android:name="android.intent.action.VIEW" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.BROWSABLE" />
- <data android:scheme="http" />
- <data android:scheme="https" />
- <data android:host="explicit.example.com" />
- <data android:host="*.wildcard.tld" />
- </intent-filter>
- </activity>
- </application>
-</manifest>
diff --git a/tests/AutoVerify/app2/res/values/strings.xml b/tests/AutoVerify/app2/res/values/strings.xml
deleted file mode 100644
index e234355041c6..000000000000
--- a/tests/AutoVerify/app2/res/values/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-Copyright 2020 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.
--->
-
-<resources>
- <!-- app icon label, do not translate -->
- <string name="app_name" translatable="false">AutoVerify Test</string>
-</resources>
diff --git a/tests/AutoVerify/app3/Android.bp b/tests/AutoVerify/app3/Android.bp
deleted file mode 100644
index 479f355bc75c..000000000000
--- a/tests/AutoVerify/app3/Android.bp
+++ /dev/null
@@ -1,20 +0,0 @@
-package {
- // 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"
- // to get the below license kinds:
- // SPDX-license-identifier-Apache-2.0
- default_applicable_licenses: ["frameworks_base_license"],
-}
-
-android_app {
- name: "AutoVerifyTest3",
- srcs: ["src/**/*.java"],
- resource_dirs: ["res"],
- platform_apis: true,
- min_sdk_version: "26",
- target_sdk_version: "26",
- optimize: {
- enabled: false,
- },
-}
diff --git a/tests/AutoVerify/app3/AndroidManifest.xml b/tests/AutoVerify/app3/AndroidManifest.xml
deleted file mode 100644
index efaabc9a38d3..000000000000
--- a/tests/AutoVerify/app3/AndroidManifest.xml
+++ /dev/null
@@ -1,44 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2020 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.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.test.autoverify" >
-
- <uses-sdk android:targetSdkVersion="26" />
-
- <application
- android:label="@string/app_name" >
- <activity
- android:name=".MainActivity"
- android:label="@string/app_name" >
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
-
- <!-- does not request autoVerify -->
- <intent-filter>
- <action android:name="android.intent.action.VIEW" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.BROWSABLE" />
- <data android:scheme="http" />
- <data android:scheme="https" />
- <data android:host="explicit.example.com" />
- </intent-filter>
- </activity>
- </application>
-</manifest>
diff --git a/tests/AutoVerify/app3/res/values/strings.xml b/tests/AutoVerify/app3/res/values/strings.xml
deleted file mode 100644
index e234355041c6..000000000000
--- a/tests/AutoVerify/app3/res/values/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-Copyright 2020 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.
--->
-
-<resources>
- <!-- app icon label, do not translate -->
- <string name="app_name" translatable="false">AutoVerify Test</string>
-</resources>
diff --git a/tests/AutoVerify/app4/Android.bp b/tests/AutoVerify/app4/Android.bp
deleted file mode 100644
index dcf8902ee03a..000000000000
--- a/tests/AutoVerify/app4/Android.bp
+++ /dev/null
@@ -1,20 +0,0 @@
-package {
- // 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"
- // to get the below license kinds:
- // SPDX-license-identifier-Apache-2.0
- default_applicable_licenses: ["frameworks_base_license"],
-}
-
-android_app {
- name: "AutoVerifyTest4",
- srcs: ["src/**/*.java"],
- resource_dirs: ["res"],
- platform_apis: true,
- min_sdk_version: "26",
- target_sdk_version: "26",
- optimize: {
- enabled: false,
- },
-}
diff --git a/tests/AutoVerify/app4/res/values/strings.xml b/tests/AutoVerify/app4/res/values/strings.xml
deleted file mode 100644
index e234355041c6..000000000000
--- a/tests/AutoVerify/app4/res/values/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-Copyright 2020 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.
--->
-
-<resources>
- <!-- app icon label, do not translate -->
- <string name="app_name" translatable="false">AutoVerify Test</string>
-</resources>
diff --git a/tests/BandwidthTests/AndroidManifest.xml b/tests/BandwidthTests/AndroidManifest.xml
index 19f38cabf23e..72bdd1430cb4 100644
--- a/tests/BandwidthTests/AndroidManifest.xml
+++ b/tests/BandwidthTests/AndroidManifest.xml
@@ -13,19 +13,22 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.tests.bandwidthenforcement">
- <uses-permission android:name="android.permission.INTERNET" />
- <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ package="com.android.tests.bandwidthenforcement">
+ <uses-permission android:name="android.permission.INTERNET"/>
+ <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<application>
- <activity android:name=".BandwidthEnforcementTestActivity">
+ <activity android:name=".BandwidthEnforcementTestActivity"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<!-- adb shell am startservice -n com.android.tests.bandwidthenforcement/.BandwidthEnforcementTestService -->
- <service android:name=".BandwidthEnforcementTestService" android:exported="true" />
+ <service android:name=".BandwidthEnforcementTestService"
+ android:exported="true"/>
</application>
</manifest>
diff --git a/tests/BatteryStatsPerfTest/Android.bp b/tests/BatteryStatsPerfTest/Android.bp
new file mode 100644
index 000000000000..5233a5b8654e
--- /dev/null
+++ b/tests/BatteryStatsPerfTest/Android.bp
@@ -0,0 +1,34 @@
+// Copyright (C) 2020 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 {
+ // 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"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+android_test {
+ name: "BatteryStatsPerfTests",
+ srcs: ["src/**/*.java"],
+ static_libs: [
+ "androidx.test.rules",
+ "apct-perftests-utils",
+ "truth-prebuilt",
+ ],
+ platform_apis: true,
+ certificate: "platform",
+}
diff --git a/tests/BatteryStatsPerfTest/AndroidManifest.xml b/tests/BatteryStatsPerfTest/AndroidManifest.xml
new file mode 100644
index 000000000000..7633d5283f5e
--- /dev/null
+++ b/tests/BatteryStatsPerfTest/AndroidManifest.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 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.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.frameworks.perftests.batterystats">
+ <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
+ <uses-permission android:name="android.permission.BATTERY_STATS"/>
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.frameworks.perftests.batterystats"/>
+</manifest>
diff --git a/tests/BatteryStatsPerfTest/AndroidTest.xml b/tests/BatteryStatsPerfTest/AndroidTest.xml
new file mode 100644
index 000000000000..2f9e114756d1
--- /dev/null
+++ b/tests/BatteryStatsPerfTest/AndroidTest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 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.
+-->
+<configuration description="Runs BatteryStats service Performance Tests">
+ <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
+ <option name="test-file-name" value="BatteryStatsPerfTests.apk"/>
+ <option name="cleanup-apks" value="true"/>
+ </target_preparer>
+
+ <option name="test-suite-tag" value="apct"/>
+ <option name="test-tag" value="BatteryStatsPerfTests"/>
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest">
+ <option name="package" value="com.android.frameworks.perftests.batterystats"/>
+ <option name="runner" value="androidx.test.runner.AndroidJUnitRunner"/>
+ </test>
+</configuration>
diff --git a/tests/BatteryStatsPerfTest/src/com/android/internal/os/BatteryStatsHelperPerfTest.java b/tests/BatteryStatsPerfTest/src/com/android/internal/os/BatteryStatsHelperPerfTest.java
new file mode 100644
index 000000000000..6266cda204b0
--- /dev/null
+++ b/tests/BatteryStatsPerfTest/src/com/android/internal/os/BatteryStatsHelperPerfTest.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2020 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.os;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+import android.os.BatteryStats;
+import android.os.Bundle;
+import android.os.UserHandle;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.List;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class BatteryStatsHelperPerfTest {
+
+ @Rule
+ public final PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ /**
+ * Measures the performance of {@link BatteryStatsHelper#getStats()}, which triggers
+ * a battery stats sync on every iteration.
+ */
+ @Test
+ public void testGetStats_forceUpdate() {
+ final Context context = InstrumentationRegistry.getContext();
+ final BatteryStatsHelper statsHelper = new BatteryStatsHelper(context,
+ true /* collectBatteryBroadcast */);
+ statsHelper.create((Bundle) null);
+ statsHelper.refreshStats(BatteryStats.STATS_SINCE_CHARGED, UserHandle.myUserId());
+
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ state.pauseTiming();
+ statsHelper.clearStats();
+ state.resumeTiming();
+
+ statsHelper.getStats();
+
+ assertThat(statsHelper.getUsageList()).isNotEmpty();
+ }
+ }
+
+ /**
+ * Measures performance of the {@link BatteryStatsHelper#getStats(boolean)}, which does
+ * not trigger a sync and just returns current values.
+ */
+ @Test
+ public void testGetStats_cached() {
+ final Context context = InstrumentationRegistry.getContext();
+ final BatteryStatsHelper statsHelper = new BatteryStatsHelper(context,
+ true /* collectBatteryBroadcast */);
+ statsHelper.create((Bundle) null);
+ statsHelper.refreshStats(BatteryStats.STATS_SINCE_CHARGED, UserHandle.myUserId());
+
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ state.pauseTiming();
+ statsHelper.clearStats();
+ state.resumeTiming();
+
+ statsHelper.getStats(false /* forceUpdate */);
+
+ assertThat(statsHelper.getUsageList()).isNotEmpty();
+ }
+ }
+
+ @Test
+ public void testPowerCalculation() {
+ final Context context = InstrumentationRegistry.getContext();
+ final BatteryStatsHelper statsHelper = new BatteryStatsHelper(context,
+ true /* collectBatteryBroadcast */);
+ statsHelper.create((Bundle) null);
+ statsHelper.getStats();
+
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ // This will use the cached BatteryStatsObject
+ statsHelper.refreshStats(BatteryStats.STATS_SINCE_CHARGED, UserHandle.myUserId());
+
+ assertThat(statsHelper.getUsageList()).isNotEmpty();
+ }
+ }
+
+ @Test
+ public void testEndToEnd() {
+ final Context context = InstrumentationRegistry.getContext();
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ final BatteryStatsHelper statsHelper = new BatteryStatsHelper(context,
+ true /* collectBatteryBroadcast */);
+ statsHelper.create((Bundle) null);
+ statsHelper.clearStats();
+ statsHelper.refreshStats(BatteryStats.STATS_SINCE_CHARGED, UserHandle.myUserId());
+
+ state.pauseTiming();
+
+ List<BatterySipper> usageList = statsHelper.getUsageList();
+ double power = 0;
+ for (int i = 0; i < usageList.size(); i++) {
+ BatterySipper sipper = usageList.get(i);
+ power += sipper.sumPower();
+ }
+
+ assertThat(power).isGreaterThan(0.0);
+
+ state.resumeTiming();
+ }
+ }
+}
diff --git a/tests/BatteryStatsPerfTest/src/com/android/internal/os/BatteryUsageStatsPerfTest.java b/tests/BatteryStatsPerfTest/src/com/android/internal/os/BatteryUsageStatsPerfTest.java
new file mode 100644
index 000000000000..54d70478f762
--- /dev/null
+++ b/tests/BatteryStatsPerfTest/src/com/android/internal/os/BatteryUsageStatsPerfTest.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2020 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.os;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+import android.os.BatteryStatsManager;
+import android.os.BatteryUsageStats;
+import android.os.UidBatteryConsumer;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.List;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class BatteryUsageStatsPerfTest {
+
+ @Rule
+ public final PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ /**
+ * Measures the performance of {@link BatteryStatsManager#getBatteryUsageStats()},
+ * which triggers a battery stats sync on every iteration.
+ */
+ @Test
+ public void testGetBatteryUsageStats() {
+ final Context context = InstrumentationRegistry.getContext();
+ final BatteryStatsManager batteryStatsManager =
+ context.getSystemService(BatteryStatsManager.class);
+
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ BatteryUsageStats batteryUsageStats = batteryStatsManager.getBatteryUsageStats();
+
+ state.pauseTiming();
+
+ List<UidBatteryConsumer> uidBatteryConsumers =
+ batteryUsageStats.getUidBatteryConsumers();
+ double power = 0;
+ for (int i = 0; i < uidBatteryConsumers.size(); i++) {
+ UidBatteryConsumer uidBatteryConsumer = uidBatteryConsumers.get(i);
+ power += uidBatteryConsumer.getConsumedPower();
+ }
+
+ assertThat(power).isGreaterThan(0.0);
+
+ state.resumeTiming();
+ }
+ }
+}
diff --git a/tests/BatteryWaster/AndroidManifest.xml b/tests/BatteryWaster/AndroidManifest.xml
index 0d7f007f15fc..5910c187c6eb 100644
--- a/tests/BatteryWaster/AndroidManifest.xml
+++ b/tests/BatteryWaster/AndroidManifest.xml
@@ -1,14 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.batterywaster">
- <uses-permission android:name="android.permission.DEVICE_POWER" />
- <uses-permission android:name="android.permission.WAKE_LOCK" />
+ package="com.android.batterywaster">
+ <uses-permission android:name="android.permission.DEVICE_POWER"/>
+ <uses-permission android:name="android.permission.WAKE_LOCK"/>
<application>
- <activity android:name="BatteryWaster" android:label="Battery Waster">
+ <activity android:name="BatteryWaster"
+ android:label="Battery Waster"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
diff --git a/tests/BiDiTests/AndroidManifest.xml b/tests/BiDiTests/AndroidManifest.xml
index 4aead814c8a0..cea5d683a2f9 100644
--- a/tests/BiDiTests/AndroidManifest.xml
+++ b/tests/BiDiTests/AndroidManifest.xml
@@ -15,23 +15,24 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.bidi"
- android:versionCode="1"
- android:versionName="1.0">
+ package="com.android.bidi"
+ android:versionCode="1"
+ android:versionName="1.0">
<application android:label="BiDiTests"
- android:hardwareAccelerated="true"
- android:supportsRtl="true" >
+ android:hardwareAccelerated="true"
+ android:supportsRtl="true">
<activity android:name=".BiDiTestActivity"
- android:windowSoftInputMode="stateAlwaysHidden">
+ android:windowSoftInputMode="stateAlwaysHidden"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
<uses-sdk android:minSdkVersion="10"
- android:targetSdkVersion="10"/>
+ android:targetSdkVersion="10"/>
</manifest>
diff --git a/tests/BlobStoreTestUtils/src/com/android/utils/blob/Utils.java b/tests/BlobStoreTestUtils/src/com/android/utils/blob/Utils.java
index ec859955694c..2d230a74a477 100644
--- a/tests/BlobStoreTestUtils/src/com/android/utils/blob/Utils.java
+++ b/tests/BlobStoreTestUtils/src/com/android/utils/blob/Utils.java
@@ -23,6 +23,7 @@ import android.app.blob.BlobStoreManager;
import android.app.blob.LeaseInfo;
import android.content.Context;
import android.content.res.Resources;
+import android.os.FileUtils;
import android.os.ParcelFileDescriptor;
import android.util.Log;
@@ -56,6 +57,16 @@ public class Utils {
}
}
+ public static void writeToSession(BlobStoreManager.Session session, ParcelFileDescriptor input)
+ throws IOException {
+ try (FileInputStream in = new ParcelFileDescriptor.AutoCloseInputStream(input)) {
+ try (FileOutputStream out = new ParcelFileDescriptor.AutoCloseOutputStream(
+ session.openWrite(0, -1))) {
+ FileUtils.copy(in, out);
+ }
+ }
+ }
+
public static void writeToSession(BlobStoreManager.Session session, ParcelFileDescriptor input,
long lengthBytes) throws IOException {
try (FileInputStream in = new ParcelFileDescriptor.AutoCloseInputStream(input)) {
diff --git a/tests/BrowserPowerTest/AndroidManifest.xml b/tests/BrowserPowerTest/AndroidManifest.xml
index 43eeaad23f8b..003e47ef5642 100644
--- a/tests/BrowserPowerTest/AndroidManifest.xml
+++ b/tests/BrowserPowerTest/AndroidManifest.xml
@@ -13,34 +13,35 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-
<!-- package name must be unique so suffix with "tests" so package loader doesn't ignore us -->
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.browserpowertest">
+ package="com.android.browserpowertest">
<!-- We add an application tag here just so that we can indicate that
- this package needs to link against the android.test library,
- which is needed when building test cases. -->
+ this package needs to link against the android.test library,
+ which is needed when building test cases. -->
<application>
- <uses-library android:name="android.test.runner" />
- <activity android:name="PowerTestActivity" android:label="Power">
+ <uses-library android:name="android.test.runner"/>
+ <activity android:name="PowerTestActivity"
+ android:label="Power"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.TEST"/>
</intent-filter>
</activity>
</application>
<!--
- This declares that this app uses the instrumentation test runner targeting
- the package of browserpowertest. To run the tests use the command:
- "adb shell am instrument -w com.android.browserpowertest/.PowerTestRunner"
- -->
+ This declares that this app uses the instrumentation test runner targeting
+ the package of browserpowertest. To run the tests use the command:
+ "adb shell am instrument -w com.android.browserpowertest/.PowerTestRunner"
+ -->
<instrumentation android:name=".PowerTestRunner"
- android:targetPackage="com.android.browserpowertest"
- android:label="Test runner for Browser Power Tests."
- />
+ android:targetPackage="com.android.browserpowertest"
+ android:label="Test runner for Browser Power Tests."/>
- <uses-permission android:name="android.permission.INTERNET" />
- <uses-permission android:name="android.permission.WRITE_SDCARD" />
- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.INTERNET"/>
+ <uses-permission android:name="android.permission.WRITE_SDCARD"/>
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
</manifest>
diff --git a/tests/Camera2Tests/CameraToo/AndroidManifest.xml b/tests/Camera2Tests/CameraToo/AndroidManifest.xml
index a92b5d81f660..2c1b4cbbc7d5 100644
--- a/tests/Camera2Tests/CameraToo/AndroidManifest.xml
+++ b/tests/Camera2Tests/CameraToo/AndroidManifest.xml
@@ -1,5 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
-
<!--
Copyright (C) 2014 The Android Open Source Project
@@ -17,16 +16,16 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.example.android.camera2.cameratoo">
- <uses-permission android:name="android.permission.CAMERA" />
- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ package="com.example.android.camera2.cameratoo">
+ <uses-permission android:name="android.permission.CAMERA"/>
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<application android:label="CameraToo">
- <activity
- android:name=".CameraTooActivity"
- android:screenOrientation="portrait">
+ <activity android:name=".CameraTooActivity"
+ android:screenOrientation="portrait"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
diff --git a/tests/Camera2Tests/SmartCamera/SimpleCamera/AndroidManifest.xml b/tests/Camera2Tests/SmartCamera/SimpleCamera/AndroidManifest.xml
index 06818682192f..35a86500b78a 100644
--- a/tests/Camera2Tests/SmartCamera/SimpleCamera/AndroidManifest.xml
+++ b/tests/Camera2Tests/SmartCamera/SimpleCamera/AndroidManifest.xml
@@ -13,24 +13,27 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- android:versionCode="1"
- android:versionName="1.0"
- package="androidx.media.filterfw.samples.simplecamera">
- <uses-sdk android:minSdkVersion="18" android:targetSdkVersion="19"/>
- <uses-permission android:name="android.permission.CAMERA" />
+ android:versionCode="1"
+ android:versionName="1.0"
+ package="androidx.media.filterfw.samples.simplecamera">
+ <uses-sdk android:minSdkVersion="18"
+ android:targetSdkVersion="19"/>
+ <uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<application android:label="Smart Camera"
- android:debuggable="true">
+ android:debuggable="true">
<uses-library android:name="com.google.android.media.effects"
- android:required="false" />
+ android:required="false"/>
<activity android:name=".SmartCamera"
- android:label="Smart Camera"
- android:screenOrientation="portrait">
+ android:label="Smart Camera"
+ android:screenOrientation="portrait"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
diff --git a/tests/CameraPrewarmTest/AndroidManifest.xml b/tests/CameraPrewarmTest/AndroidManifest.xml
index 11b2686d2932..7fafd33620b3 100644
--- a/tests/CameraPrewarmTest/AndroidManifest.xml
+++ b/tests/CameraPrewarmTest/AndroidManifest.xml
@@ -16,35 +16,35 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.google.android.test.cameraprewarm">
+ package="com.google.android.test.cameraprewarm">
<application android:label="@string/activity_title">
<activity android:name=".CameraActivity"
- android:theme="@android:style/Theme.NoTitleBar">
+ android:theme="@android:style/Theme.NoTitleBar"
+ android:exported="true">
<intent-filter>
- <action android:name="android.media.action.STILL_IMAGE_CAMERA" />
- <category android:name="android.intent.category.DEFAULT" />
+ <action android:name="android.media.action.STILL_IMAGE_CAMERA"/>
+ <category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
- <meta-data
- android:name="android.media.still_image_camera_preview_service"
- android:value="com.google.android.test.cameraprewarm.PrewarmService">
+ <meta-data android:name="android.media.still_image_camera_preview_service"
+ android:value="com.google.android.test.cameraprewarm.PrewarmService">
</meta-data>
</activity>
<activity android:name=".SecureCameraActivity"
- android:theme="@android:style/Theme.NoTitleBar">
+ android:theme="@android:style/Theme.NoTitleBar"
+ android:exported="true">
<intent-filter>
- <action android:name="android.media.action.STILL_IMAGE_CAMERA_SECURE" />
- <category android:name="android.intent.category.DEFAULT" />
+ <action android:name="android.media.action.STILL_IMAGE_CAMERA_SECURE"/>
+ <category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
- <meta-data
- android:name="android.media.still_image_camera_preview_service"
- android:value="com.google.android.test.cameraprewarm.PrewarmService">
+ <meta-data android:name="android.media.still_image_camera_preview_service"
+ android:value="com.google.android.test.cameraprewarm.PrewarmService">
</meta-data>
</activity>
<service android:name=".PrewarmService"
- android:exported="true">
+ android:exported="true">
</service>
</application>
diff --git a/tests/CanvasCompare/AndroidManifest.xml b/tests/CanvasCompare/AndroidManifest.xml
index b55e290a52dd..2734e7f07f27 100644
--- a/tests/CanvasCompare/AndroidManifest.xml
+++ b/tests/CanvasCompare/AndroidManifest.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2012 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
@@ -12,37 +13,36 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.test.hwuicompare" >
+ package="com.android.test.hwuicompare">
- <uses-permission android:name="android.permission.INTERNET" />
+ <uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
- <application
- android:label="@string/app_name"
- android:theme="@android:style/Theme.Holo.Light.NoActionBar">
- <activity
- android:name="AutomaticActivity"
- android:label="CanvasAutoCompare" >
+ <application android:label="@string/app_name"
+ android:theme="@android:style/Theme.Holo.Light.NoActionBar">
+ <activity android:name="AutomaticActivity"
+ android:label="CanvasAutoCompare"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity
- android:name="ManualActivity"
- android:label="CanvasManualCompare" >
+ <activity android:name="ManualActivity"
+ android:label="CanvasManualCompare"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <uses-library android:name="android.test.runner" />
+ <uses-library android:name="android.test.runner"/>
</application>
- <instrumentation
- android:name="android.test.InstrumentationTestRunner"
- android:targetPackage="com.android.test.hwuicompare"
- android:label="HW/SW Canvas comparison tool."/>
+ <instrumentation android:name="android.test.InstrumentationTestRunner"
+ android:targetPackage="com.android.test.hwuicompare"
+ android:label="HW/SW Canvas comparison tool."/>
</manifest>
diff --git a/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassBase.java b/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassBase.java
index 475305eb83a2..4259a8620727 100644
--- a/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassBase.java
+++ b/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassBase.java
@@ -32,7 +32,7 @@ public class HierrarchicalDataClassBase implements Parcelable {
- // Code below generated by codegen v1.0.15.
+ // Code below generated by codegen v1.0.23.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -51,7 +51,7 @@ public class HierrarchicalDataClassBase implements Parcelable {
}
@DataClass.Generated.Member
- public HierrarchicalDataClassBase setBaseData( int value) {
+ public @android.annotation.NonNull HierrarchicalDataClassBase setBaseData( int value) {
mBaseData = value;
return this;
}
@@ -98,8 +98,8 @@ public class HierrarchicalDataClassBase implements Parcelable {
};
@DataClass.Generated(
- time = 1582685650576L,
- codegenVersion = "1.0.15",
+ time = 1616541542813L,
+ codegenVersion = "1.0.23",
sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassBase.java",
inputSignatures = "private int mBaseData\nclass HierrarchicalDataClassBase extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genConstructor=false, genSetters=true)")
@Deprecated
diff --git a/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassChild.java b/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassChild.java
index 150b324d1a30..677094b14fd6 100644
--- a/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassChild.java
+++ b/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassChild.java
@@ -46,7 +46,7 @@ public class HierrarchicalDataClassChild extends HierrarchicalDataClassBase {
- // Code below generated by codegen v1.0.15.
+ // Code below generated by codegen v1.0.23.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -65,7 +65,7 @@ public class HierrarchicalDataClassChild extends HierrarchicalDataClassBase {
}
@DataClass.Generated.Member
- public HierrarchicalDataClassChild setChildData(@NonNull String value) {
+ public @NonNull HierrarchicalDataClassChild setChildData(@NonNull String value) {
mChildData = value;
com.android.internal.util.AnnotationValidations.validate(
NonNull.class, null, mChildData);
@@ -120,8 +120,8 @@ public class HierrarchicalDataClassChild extends HierrarchicalDataClassBase {
};
@DataClass.Generated(
- time = 1582685651560L,
- codegenVersion = "1.0.15",
+ time = 1616541543730L,
+ codegenVersion = "1.0.23",
sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassChild.java",
inputSignatures = "private @android.annotation.NonNull java.lang.String mChildData\nclass HierrarchicalDataClassChild extends com.android.codegentest.HierrarchicalDataClassBase implements []\n@com.android.internal.util.DataClass(genParcelable=true, genConstructor=false, genSetters=true)")
@Deprecated
diff --git a/tests/Codegen/src/com/android/codegentest/ParcelAllTheThingsDataClass.java b/tests/Codegen/src/com/android/codegentest/ParcelAllTheThingsDataClass.java
index 30871566c269..eb260ab6d35d 100644
--- a/tests/Codegen/src/com/android/codegentest/ParcelAllTheThingsDataClass.java
+++ b/tests/Codegen/src/com/android/codegentest/ParcelAllTheThingsDataClass.java
@@ -54,7 +54,7 @@ public class ParcelAllTheThingsDataClass implements Parcelable {
- // Code below generated by codegen v1.0.15.
+ // Code below generated by codegen v1.0.23.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -412,10 +412,10 @@ public class ParcelAllTheThingsDataClass implements Parcelable {
}
@DataClass.Generated(
- time = 1582685649678L,
- codegenVersion = "1.0.15",
+ time = 1616541541942L,
+ codegenVersion = "1.0.23",
sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/ParcelAllTheThingsDataClass.java",
- inputSignatures = " @android.annotation.NonNull java.lang.String[] mStringArray\n @android.annotation.NonNull int[] mIntArray\n @android.annotation.NonNull java.util.List<java.lang.String> mStringList\n @android.annotation.NonNull java.util.Map<java.lang.String,com.android.codegentest.SampleWithCustomBuilder> mMap\n @android.annotation.NonNull java.util.Map<java.lang.String,java.lang.String> mStringMap\n @android.annotation.NonNull android.util.SparseArray<com.android.codegentest.SampleWithCustomBuilder> mSparseArray\n @android.annotation.NonNull android.util.SparseIntArray mSparseIntArray\n @java.lang.SuppressWarnings({\"WeakerAccess\"}) @android.annotation.Nullable java.lang.Boolean mNullableBoolean\nclass ParcelAllTheThingsDataClass extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genBuilder=true, genAidl=false, genToString=true)")
+ inputSignatures = " @android.annotation.NonNull java.lang.String[] mStringArray\n @android.annotation.NonNull int[] mIntArray\n @android.annotation.NonNull java.util.List<java.lang.String> mStringList\n @android.annotation.NonNull java.util.Map<java.lang.String,com.android.codegentest.SampleWithCustomBuilder> mMap\n @android.annotation.NonNull java.util.Map<java.lang.String,java.lang.String> mStringMap\n @android.annotation.NonNull android.util.SparseArray<com.android.codegentest.SampleWithCustomBuilder> mSparseArray\n @android.annotation.NonNull android.util.SparseIntArray mSparseIntArray\n @java.lang.SuppressWarnings @android.annotation.Nullable java.lang.Boolean mNullableBoolean\nclass ParcelAllTheThingsDataClass extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genBuilder=true, genAidl=false, genToString=true)")
@Deprecated
private void __metadata() {}
diff --git a/tests/Codegen/src/com/android/codegentest/SampleDataClass.java b/tests/Codegen/src/com/android/codegentest/SampleDataClass.java
index 8d421bfa492a..158e0656b574 100644
--- a/tests/Codegen/src/com/android/codegentest/SampleDataClass.java
+++ b/tests/Codegen/src/com/android/codegentest/SampleDataClass.java
@@ -23,7 +23,11 @@ import android.annotation.Size;
import android.annotation.StringDef;
import android.annotation.StringRes;
import android.annotation.UserIdInt;
+import android.companion.ICompanionDeviceManager;
+import android.content.pm.PackageManager;
import android.net.LinkAddress;
+import android.os.Binder;
+import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
import android.view.accessibility.AccessibilityNodeInfo;
@@ -86,9 +90,10 @@ public final class SampleDataClass implements Parcelable {
* @see #toString()
* @see State
*/
- public static final int STATE_UNDEFINED = -1;
public static final int STATE_ON = 1;
public static final int STATE_OFF = 0;
+ public static final int STATE_UNDEFINED
+ = PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED;
/**
* {@link IntDef}s with values specified in hex("0x...") are considered to be
@@ -280,6 +285,16 @@ public final class SampleDataClass implements Parcelable {
/**
+ * Binder types are also supported
+ */
+ private @NonNull IBinder mToken = new Binder();
+ /**
+ * AIDL interface types are also supported
+ */
+ private @Nullable ICompanionDeviceManager mIPCInterface = null;
+
+
+ /**
* Manually declaring any method that would otherwise be generated suppresses its generation,
* allowing for fine-grained overrides of the generated behavior.
*/
@@ -342,7 +357,7 @@ public final class SampleDataClass implements Parcelable {
- // Code below generated by codegen v1.0.15.
+ // Code below generated by codegen v1.0.23.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -356,9 +371,9 @@ public final class SampleDataClass implements Parcelable {
@IntDef(prefix = "STATE_", value = {
- STATE_UNDEFINED,
STATE_ON,
- STATE_OFF
+ STATE_OFF,
+ STATE_UNDEFINED
})
@java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE)
@DataClass.Generated.Member
@@ -367,12 +382,12 @@ public final class SampleDataClass implements Parcelable {
@DataClass.Generated.Member
public static String stateToString(@State int value) {
switch (value) {
- case STATE_UNDEFINED:
- return "STATE_UNDEFINED";
case STATE_ON:
return "STATE_ON";
case STATE_OFF:
return "STATE_OFF";
+ case STATE_UNDEFINED:
+ return "STATE_UNDEFINED";
default: return Integer.toHexString(value);
}
}
@@ -490,6 +505,10 @@ public final class SampleDataClass implements Parcelable {
*
* Validation annotations following {@link Each} annotation, will be applied for each
* array/collection element instead.
+ * @param token
+ * Binder types are also supported
+ * @param iPCInterface
+ * AIDL interface types are also supported
*/
@DataClass.Generated.Member
public SampleDataClass(
@@ -512,7 +531,9 @@ public final class SampleDataClass implements Parcelable {
@Nullable LinkAddress[] linkAddresses5,
@StringRes int stringRes,
@android.annotation.IntRange(from = 0, to = 6) int dayOfWeek,
- @Size(2) @NonNull @FloatRange(from = 0f) float[] coords) {
+ @Size(2) @NonNull @FloatRange(from = 0f) float[] coords,
+ @NonNull IBinder token,
+ @Nullable ICompanionDeviceManager iPCInterface) {
this.mNum = num;
this.mNum2 = num2;
this.mNum4 = num4;
@@ -560,14 +581,14 @@ public final class SampleDataClass implements Parcelable {
| FLAG_AUGMENTED_REQUEST);
this.mState = state;
- if (!(mState == STATE_UNDEFINED)
- && !(mState == STATE_ON)
- && !(mState == STATE_OFF)) {
+ if (!(mState == STATE_ON)
+ && !(mState == STATE_OFF)
+ && !(mState == STATE_UNDEFINED)) {
throw new java.lang.IllegalArgumentException(
"state was " + mState + " but must be one of: "
- + "STATE_UNDEFINED(" + STATE_UNDEFINED + "), "
+ "STATE_ON(" + STATE_ON + "), "
- + "STATE_OFF(" + STATE_OFF + ")");
+ + "STATE_OFF(" + STATE_OFF + "), "
+ + "STATE_UNDEFINED(" + STATE_UNDEFINED + ")");
}
this.charSeq = charSeq;
@@ -595,6 +616,10 @@ public final class SampleDataClass implements Parcelable {
"from", 0f);
}
+ this.mToken = token;
+ AnnotationValidations.validate(
+ NonNull.class, null, mToken);
+ this.mIPCInterface = iPCInterface;
onConstructed();
}
@@ -795,6 +820,22 @@ public final class SampleDataClass implements Parcelable {
}
/**
+ * Binder types are also supported
+ */
+ @DataClass.Generated.Member
+ public @NonNull IBinder getToken() {
+ return mToken;
+ }
+
+ /**
+ * AIDL interface types are also supported
+ */
+ @DataClass.Generated.Member
+ public @Nullable ICompanionDeviceManager getIPCInterface() {
+ return mIPCInterface;
+ }
+
+ /**
* When using transient fields for caching it's often also a good idea to initialize them
* lazily.
*
@@ -820,7 +861,7 @@ public final class SampleDataClass implements Parcelable {
* pieces in multiple places for each field.
*/
@DataClass.Generated.Member
- public SampleDataClass setNum( int value) {
+ public @NonNull SampleDataClass setNum( int value) {
mNum = value;
return this;
}
@@ -832,7 +873,7 @@ public final class SampleDataClass implements Parcelable {
* @see #mNum2 ..and so should blocks at the bottom, e.g. {@code @see} blocks.
*/
@DataClass.Generated.Member
- public SampleDataClass setNum2( int value) {
+ public @NonNull SampleDataClass setNum2( int value) {
mNum2 = value;
return this;
}
@@ -846,7 +887,7 @@ public final class SampleDataClass implements Parcelable {
* @hide
*/
@DataClass.Generated.Member
- public SampleDataClass setNum4( int value) {
+ public @NonNull SampleDataClass setNum4( int value) {
mNum4 = value;
return this;
}
@@ -855,7 +896,7 @@ public final class SampleDataClass implements Parcelable {
* {@link Nullable} or {@link NonNull} annotation is required on all non-primitive fields.
*/
@DataClass.Generated.Member
- public SampleDataClass setName(@NonNull String value) {
+ public @NonNull SampleDataClass setName(@NonNull String value) {
mName = value;
return this;
}
@@ -868,7 +909,7 @@ public final class SampleDataClass implements Parcelable {
* while mandatory fields are passed via {@link Builder#Builder constructor}.
*/
@DataClass.Generated.Member
- public SampleDataClass setName2(@NonNull String value) {
+ public @NonNull SampleDataClass setName2(@NonNull String value) {
mName2 = value;
AnnotationValidations.validate(
NonNull.class, null, mName2);
@@ -880,7 +921,7 @@ public final class SampleDataClass implements Parcelable {
* {@link #defaultName4 defaultFieldName()} can be defined to compute the default value.
*/
@DataClass.Generated.Member
- public SampleDataClass setName4(@NonNull String value) {
+ public @NonNull SampleDataClass setName4(@NonNull String value) {
mName4 = value;
AnnotationValidations.validate(
NonNull.class, null, mName4);
@@ -892,7 +933,7 @@ public final class SampleDataClass implements Parcelable {
* E.g. {@link Parcelable} subclasses, {@link String}, {@link int}, {@link boolean}, etc.
*/
@DataClass.Generated.Member
- public SampleDataClass setOtherParcelable(@NonNull AccessibilityNodeInfo value) {
+ public @NonNull SampleDataClass setOtherParcelable(@NonNull AccessibilityNodeInfo value) {
mOtherParcelable = value;
return this;
}
@@ -904,7 +945,7 @@ public final class SampleDataClass implements Parcelable {
* @see MyDateParcelling an example {@link Parcelling} implementation
*/
@DataClass.Generated.Member
- public SampleDataClass setDate(@NonNull Date value) {
+ public @NonNull SampleDataClass setDate(@NonNull Date value) {
mDate = value;
AnnotationValidations.validate(
NonNull.class, null, mDate);
@@ -916,7 +957,7 @@ public final class SampleDataClass implements Parcelable {
* to encourage its reuse.
*/
@DataClass.Generated.Member
- public SampleDataClass setPattern(@NonNull Pattern value) {
+ public @NonNull SampleDataClass setPattern(@NonNull Pattern value) {
mPattern = value;
AnnotationValidations.validate(
NonNull.class, null, mPattern);
@@ -929,7 +970,7 @@ public final class SampleDataClass implements Parcelable {
* {@link Builder#addLinkAddresses2(LinkAddress) add} method is generated for convenience.
*/
@DataClass.Generated.Member
- public SampleDataClass setLinkAddresses2(@NonNull List<LinkAddress> value) {
+ public @NonNull SampleDataClass setLinkAddresses2(@NonNull List<LinkAddress> value) {
mLinkAddresses2 = value;
AnnotationValidations.validate(
NonNull.class, null, mLinkAddresses2);
@@ -943,7 +984,7 @@ public final class SampleDataClass implements Parcelable {
* @see Builder#addLinkAddress(LinkAddress)
*/
@DataClass.Generated.Member
- public SampleDataClass setLinkAddresses(@NonNull ArrayList<LinkAddress> value) {
+ public @NonNull SampleDataClass setLinkAddresses(@NonNull ArrayList<LinkAddress> value) {
mLinkAddresses = value;
AnnotationValidations.validate(
NonNull.class, null, mLinkAddresses);
@@ -957,7 +998,7 @@ public final class SampleDataClass implements Parcelable {
* @see Builder#setLinkAddresses4(LinkAddress...)
*/
@DataClass.Generated.Member
- public SampleDataClass setLinkAddresses4(@NonNull LinkAddress... value) {
+ public @NonNull SampleDataClass setLinkAddresses4(@NonNull LinkAddress... value) {
mLinkAddresses4 = value;
return this;
}
@@ -970,7 +1011,7 @@ public final class SampleDataClass implements Parcelable {
* @see Builder#setStateName
*/
@DataClass.Generated.Member
- public SampleDataClass setStateName(@StateName @NonNull String value) {
+ public @NonNull SampleDataClass setStateName(@StateName @NonNull String value) {
mStateName = value;
if (!(Objects.equals(mStateName, STATE_NAME_UNDEFINED))
@@ -992,7 +1033,7 @@ public final class SampleDataClass implements Parcelable {
* Fields annotated with {@link IntDef} annotations also get a proper {@link #toString()} value.
*/
@DataClass.Generated.Member
- public SampleDataClass setFlags(@RequestFlags int value) {
+ public @NonNull SampleDataClass setFlags(@RequestFlags int value) {
mFlags = value;
Preconditions.checkFlagsArgument(
@@ -1007,17 +1048,17 @@ public final class SampleDataClass implements Parcelable {
* Above is true for both {@link IntDef#flag flags} and enum-like {@link IntDef}s
*/
@DataClass.Generated.Member
- public SampleDataClass setState(@State int value) {
+ public @NonNull SampleDataClass setState(@State int value) {
mState = value;
- if (!(mState == STATE_UNDEFINED)
- && !(mState == STATE_ON)
- && !(mState == STATE_OFF)) {
+ if (!(mState == STATE_ON)
+ && !(mState == STATE_OFF)
+ && !(mState == STATE_UNDEFINED)) {
throw new java.lang.IllegalArgumentException(
"state was " + mState + " but must be one of: "
- + "STATE_UNDEFINED(" + STATE_UNDEFINED + "), "
+ "STATE_ON(" + STATE_ON + "), "
- + "STATE_OFF(" + STATE_OFF + ")");
+ + "STATE_OFF(" + STATE_OFF + "), "
+ + "STATE_UNDEFINED(" + STATE_UNDEFINED + ")");
}
return this;
@@ -1036,7 +1077,7 @@ public final class SampleDataClass implements Parcelable {
* @see #SampleDataClass
*/
@DataClass.Generated.Member
- public SampleDataClass setStringRes(@StringRes int value) {
+ public @NonNull SampleDataClass setStringRes(@StringRes int value) {
mStringRes = value;
AnnotationValidations.validate(
StringRes.class, null, mStringRes);
@@ -1051,7 +1092,7 @@ public final class SampleDataClass implements Parcelable {
* @see AnnotationValidations#validate(Class, Size, int, String, int, String, int)
*/
@DataClass.Generated.Member
- public SampleDataClass setDayOfWeek(@android.annotation.IntRange(from = 0, to = 6) int value) {
+ public @NonNull SampleDataClass setDayOfWeek(@android.annotation.IntRange(from = 0, to = 6) int value) {
mDayOfWeek = value;
AnnotationValidations.validate(
android.annotation.IntRange.class, null, mDayOfWeek,
@@ -1070,7 +1111,7 @@ public final class SampleDataClass implements Parcelable {
* @see AnnotationValidations#validate(Class, Size, int, String, int)
*/
@DataClass.Generated.Member
- public SampleDataClass setCoords(@Size(2) @NonNull @FloatRange(from = 0f) float... value) {
+ public @NonNull SampleDataClass setCoords(@Size(2) @NonNull @FloatRange(from = 0f) float... value) {
mCoords = value;
AnnotationValidations.validate(
Size.class, null, mCoords.length,
@@ -1087,6 +1128,26 @@ public final class SampleDataClass implements Parcelable {
return this;
}
+ /**
+ * Binder types are also supported
+ */
+ @DataClass.Generated.Member
+ public @NonNull SampleDataClass setToken(@NonNull IBinder value) {
+ mToken = value;
+ AnnotationValidations.validate(
+ NonNull.class, null, mToken);
+ return this;
+ }
+
+ /**
+ * AIDL interface types are also supported
+ */
+ @DataClass.Generated.Member
+ public @NonNull SampleDataClass setIPCInterface(@NonNull ICompanionDeviceManager value) {
+ mIPCInterface = value;
+ return this;
+ }
+
@Override
@DataClass.Generated.Member
public String toString() {
@@ -1113,7 +1174,9 @@ public final class SampleDataClass implements Parcelable {
"linkAddresses5 = " + java.util.Arrays.toString(mLinkAddresses5) + ", " +
"stringRes = " + mStringRes + ", " +
"dayOfWeek = " + mDayOfWeek + ", " +
- "coords = " + java.util.Arrays.toString(mCoords) +
+ "coords = " + java.util.Arrays.toString(mCoords) + ", " +
+ "token = " + mToken + ", " +
+ "iPCInterface = " + mIPCInterface +
" }";
}
@@ -1149,7 +1212,9 @@ public final class SampleDataClass implements Parcelable {
&& java.util.Arrays.equals(mLinkAddresses5, that.mLinkAddresses5)
&& mStringRes == that.mStringRes
&& mDayOfWeek == that.mDayOfWeek
- && java.util.Arrays.equals(mCoords, that.mCoords);
+ && java.util.Arrays.equals(mCoords, that.mCoords)
+ && Objects.equals(mToken, that.mToken)
+ && Objects.equals(mIPCInterface, that.mIPCInterface);
}
@Override
@@ -1179,6 +1244,8 @@ public final class SampleDataClass implements Parcelable {
_hash = 31 * _hash + mStringRes;
_hash = 31 * _hash + mDayOfWeek;
_hash = 31 * _hash + java.util.Arrays.hashCode(mCoords);
+ _hash = 31 * _hash + Objects.hashCode(mToken);
+ _hash = 31 * _hash + Objects.hashCode(mIPCInterface);
return _hash;
}
@@ -1206,6 +1273,8 @@ public final class SampleDataClass implements Parcelable {
actionInt.acceptInt(this, "stringRes", mStringRes);
actionInt.acceptInt(this, "dayOfWeek", mDayOfWeek);
actionObject.acceptObject(this, "coords", mCoords);
+ actionObject.acceptObject(this, "token", mToken);
+ actionObject.acceptObject(this, "iPCInterface", mIPCInterface);
}
/** @deprecated May cause boxing allocations - use with caution! */
@@ -1232,6 +1301,8 @@ public final class SampleDataClass implements Parcelable {
action.acceptObject(this, "stringRes", mStringRes);
action.acceptObject(this, "dayOfWeek", mDayOfWeek);
action.acceptObject(this, "coords", mCoords);
+ action.acceptObject(this, "token", mToken);
+ action.acceptObject(this, "iPCInterface", mIPCInterface);
}
@DataClass.Generated.Member
@@ -1267,6 +1338,7 @@ public final class SampleDataClass implements Parcelable {
if (mOtherParcelable != null) flg |= 0x40;
if (mLinkAddresses4 != null) flg |= 0x800;
if (mLinkAddresses5 != null) flg |= 0x10000;
+ if (mIPCInterface != null) flg |= 0x200000;
dest.writeLong(flg);
dest.writeInt(mNum);
dest.writeInt(mNum2);
@@ -1288,6 +1360,8 @@ public final class SampleDataClass implements Parcelable {
dest.writeInt(mStringRes);
dest.writeInt(mDayOfWeek);
dest.writeFloatArray(mCoords);
+ dest.writeStrongBinder(mToken);
+ if (mIPCInterface != null) dest.writeStrongInterface(mIPCInterface);
}
@Override
@@ -1324,6 +1398,8 @@ public final class SampleDataClass implements Parcelable {
int stringRes = in.readInt();
int dayOfWeek = in.readInt();
float[] coords = in.createFloatArray();
+ IBinder token = (IBinder) in.readStrongBinder();
+ ICompanionDeviceManager iPCInterface = (flg & 0x200000) == 0 ? null : ICompanionDeviceManager.Stub.asInterface(in.readStrongBinder());
this.mNum = num;
this.mNum2 = num2;
@@ -1372,14 +1448,14 @@ public final class SampleDataClass implements Parcelable {
| FLAG_AUGMENTED_REQUEST);
this.mState = state;
- if (!(mState == STATE_UNDEFINED)
- && !(mState == STATE_ON)
- && !(mState == STATE_OFF)) {
+ if (!(mState == STATE_ON)
+ && !(mState == STATE_OFF)
+ && !(mState == STATE_UNDEFINED)) {
throw new java.lang.IllegalArgumentException(
"state was " + mState + " but must be one of: "
- + "STATE_UNDEFINED(" + STATE_UNDEFINED + "), "
+ "STATE_ON(" + STATE_ON + "), "
- + "STATE_OFF(" + STATE_OFF + ")");
+ + "STATE_OFF(" + STATE_OFF + "), "
+ + "STATE_UNDEFINED(" + STATE_UNDEFINED + ")");
}
this.charSeq = _charSeq;
@@ -1407,6 +1483,10 @@ public final class SampleDataClass implements Parcelable {
"from", 0f);
}
+ this.mToken = token;
+ AnnotationValidations.validate(
+ NonNull.class, null, mToken);
+ this.mIPCInterface = iPCInterface;
onConstructed();
}
@@ -1452,6 +1532,8 @@ public final class SampleDataClass implements Parcelable {
private @StringRes int mStringRes;
private @android.annotation.IntRange(from = 0, to = 6) int mDayOfWeek;
private @Size(2) @NonNull @FloatRange(from = 0f) float[] mCoords;
+ private @NonNull IBinder mToken;
+ private @Nullable ICompanionDeviceManager mIPCInterface;
private long mBuilderFieldsSet = 0L;
@@ -1792,10 +1874,32 @@ public final class SampleDataClass implements Parcelable {
return this;
}
+ /**
+ * Binder types are also supported
+ */
+ @DataClass.Generated.Member
+ public @NonNull Builder setToken(@NonNull IBinder value) {
+ checkNotUsed();
+ mBuilderFieldsSet |= 0x100000;
+ mToken = value;
+ return this;
+ }
+
+ /**
+ * AIDL interface types are also supported
+ */
+ @DataClass.Generated.Member
+ public @NonNull Builder setIPCInterface(@NonNull ICompanionDeviceManager value) {
+ checkNotUsed();
+ mBuilderFieldsSet |= 0x200000;
+ mIPCInterface = value;
+ return this;
+ }
+
/** Builds the instance. This builder should not be touched after calling this! */
public @NonNull SampleDataClass build() {
checkNotUsed();
- mBuilderFieldsSet |= 0x100000; // Mark builder used
+ mBuilderFieldsSet |= 0x400000; // Mark builder used
if ((mBuilderFieldsSet & 0x10) == 0) {
mName2 = "Bob";
@@ -1839,6 +1943,12 @@ public final class SampleDataClass implements Parcelable {
if ((mBuilderFieldsSet & 0x80000) == 0) {
mCoords = new float[] { 0f, 0f };
}
+ if ((mBuilderFieldsSet & 0x100000) == 0) {
+ mToken = new Binder();
+ }
+ if ((mBuilderFieldsSet & 0x200000) == 0) {
+ mIPCInterface = null;
+ }
SampleDataClass o = new SampleDataClass(
mNum,
mNum2,
@@ -1859,12 +1969,14 @@ public final class SampleDataClass implements Parcelable {
mLinkAddresses5,
mStringRes,
mDayOfWeek,
- mCoords);
+ mCoords,
+ mToken,
+ mIPCInterface);
return o;
}
private void checkNotUsed() {
- if ((mBuilderFieldsSet & 0x100000) != 0) {
+ if ((mBuilderFieldsSet & 0x400000) != 0) {
throw new IllegalStateException(
"This Builder should not be reused. Use a new Builder instance instead");
}
@@ -1872,10 +1984,10 @@ public final class SampleDataClass implements Parcelable {
}
@DataClass.Generated(
- time = 1582685647656L,
- codegenVersion = "1.0.15",
+ time = 1616541539978L,
+ codegenVersion = "1.0.23",
sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/SampleDataClass.java",
- inputSignatures = "public static final java.lang.String STATE_NAME_UNDEFINED\npublic static final java.lang.String STATE_NAME_ON\npublic static final java.lang.String STATE_NAME_OFF\npublic static final int STATE_UNDEFINED\npublic static final int STATE_ON\npublic static final int STATE_OFF\npublic static final @com.android.codegentest.SampleDataClass.RequestFlags int FLAG_MANUAL_REQUEST\npublic static final @com.android.codegentest.SampleDataClass.RequestFlags int FLAG_COMPATIBILITY_MODE_REQUEST\npublic static final @com.android.codegentest.SampleDataClass.RequestFlags int FLAG_AUGMENTED_REQUEST\nprivate int mNum\nprivate int mNum2\nprivate int mNum4\nprivate @android.annotation.Nullable java.lang.String mName\nprivate @android.annotation.NonNull java.lang.String mName2\nprivate @android.annotation.NonNull java.lang.String mName4\nprivate @android.annotation.Nullable android.view.accessibility.AccessibilityNodeInfo mOtherParcelable\nprivate @com.android.internal.util.DataClass.ParcelWith(com.android.codegentest.MyDateParcelling.class) @android.annotation.NonNull java.util.Date mDate\nprivate @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForPattern.class) @android.annotation.NonNull java.util.regex.Pattern mPattern\nprivate @android.annotation.NonNull java.util.List<android.net.LinkAddress> mLinkAddresses2\nprivate @com.android.internal.util.DataClass.PluralOf(\"linkAddress\") @android.annotation.NonNull java.util.ArrayList<android.net.LinkAddress> mLinkAddresses\nprivate @android.annotation.Nullable android.net.LinkAddress[] mLinkAddresses4\nprivate @com.android.codegentest.SampleDataClass.StateName @android.annotation.NonNull java.lang.String mStateName\nprivate @com.android.codegentest.SampleDataClass.RequestFlags int mFlags\nprivate @com.android.codegentest.SampleDataClass.State int mState\npublic @android.annotation.NonNull java.lang.CharSequence charSeq\nprivate final @android.annotation.Nullable android.net.LinkAddress[] mLinkAddresses5\nprivate transient android.net.LinkAddress[] mLinkAddresses6\ntransient int[] mTmpStorage\nprivate @android.annotation.StringRes int mStringRes\nprivate @android.annotation.IntRange(from=0L, to=6L) int mDayOfWeek\nprivate @android.annotation.Size(2L) @android.annotation.NonNull @com.android.internal.util.DataClass.Each @android.annotation.FloatRange(from=0.0) float[] mCoords\nprivate static java.lang.String defaultName4()\nprivate int[] lazyInitTmpStorage()\npublic android.net.LinkAddress[] getLinkAddresses4()\nprivate boolean patternEquals(java.util.regex.Pattern)\nprivate int patternHashCode()\nprivate void onConstructed()\npublic void dump(java.io.PrintWriter)\nclass SampleDataClass extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genBuilder=true, genConstructor=true, genEqualsHashCode=true, genToString=true, genForEachField=true, genSetters=true)")
+ inputSignatures = "public static final java.lang.String STATE_NAME_UNDEFINED\npublic static final java.lang.String STATE_NAME_ON\npublic static final java.lang.String STATE_NAME_OFF\npublic static final int STATE_ON\npublic static final int STATE_OFF\npublic static final int STATE_UNDEFINED\npublic static final @com.android.codegentest.SampleDataClass.RequestFlags int FLAG_MANUAL_REQUEST\npublic static final @com.android.codegentest.SampleDataClass.RequestFlags int FLAG_COMPATIBILITY_MODE_REQUEST\npublic static final @com.android.codegentest.SampleDataClass.RequestFlags int FLAG_AUGMENTED_REQUEST\nprivate int mNum\nprivate int mNum2\nprivate int mNum4\nprivate @android.annotation.Nullable java.lang.String mName\nprivate @android.annotation.NonNull java.lang.String mName2\nprivate @android.annotation.NonNull java.lang.String mName4\nprivate @android.annotation.Nullable android.view.accessibility.AccessibilityNodeInfo mOtherParcelable\nprivate @com.android.internal.util.DataClass.ParcelWith(com.android.codegentest.MyDateParcelling.class) @android.annotation.NonNull java.util.Date mDate\nprivate @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForPattern.class) @android.annotation.NonNull java.util.regex.Pattern mPattern\nprivate @android.annotation.NonNull java.util.List<android.net.LinkAddress> mLinkAddresses2\nprivate @com.android.internal.util.DataClass.PluralOf(\"linkAddress\") @android.annotation.NonNull java.util.ArrayList<android.net.LinkAddress> mLinkAddresses\nprivate @android.annotation.Nullable android.net.LinkAddress[] mLinkAddresses4\nprivate @com.android.codegentest.SampleDataClass.StateName @android.annotation.NonNull java.lang.String mStateName\nprivate @com.android.codegentest.SampleDataClass.RequestFlags int mFlags\nprivate @com.android.codegentest.SampleDataClass.State int mState\npublic @android.annotation.NonNull java.lang.CharSequence charSeq\nprivate final @android.annotation.Nullable android.net.LinkAddress[] mLinkAddresses5\nprivate transient android.net.LinkAddress[] mLinkAddresses6\ntransient int[] mTmpStorage\nprivate @android.annotation.StringRes int mStringRes\nprivate @android.annotation.IntRange int mDayOfWeek\nprivate @android.annotation.Size @android.annotation.NonNull @com.android.internal.util.DataClass.Each @android.annotation.FloatRange float[] mCoords\nprivate @android.annotation.NonNull android.os.IBinder mToken\nprivate @android.annotation.Nullable android.companion.ICompanionDeviceManager mIPCInterface\nprivate static java.lang.String defaultName4()\nprivate int[] lazyInitTmpStorage()\npublic android.net.LinkAddress[] getLinkAddresses4()\nprivate boolean patternEquals(java.util.regex.Pattern)\nprivate int patternHashCode()\nprivate void onConstructed()\npublic void dump(java.io.PrintWriter)\nclass SampleDataClass extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genBuilder=true, genConstructor=true, genEqualsHashCode=true, genToString=true, genForEachField=true, genSetters=true)")
@Deprecated
private void __metadata() {}
diff --git a/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java b/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java
index d9fe1fd5a465..a535e227cccf 100644
--- a/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java
+++ b/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java
@@ -85,7 +85,7 @@ public class SampleWithCustomBuilder implements Parcelable {
- // Code below generated by codegen v1.0.15.
+ // Code below generated by codegen v1.0.23.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -253,10 +253,10 @@ public class SampleWithCustomBuilder implements Parcelable {
}
@DataClass.Generated(
- time = 1582685648622L,
- codegenVersion = "1.0.15",
+ time = 1616541540898L,
+ codegenVersion = "1.0.23",
sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java",
- inputSignatures = " long delayAmount\n @android.annotation.NonNull java.util.concurrent.TimeUnit delayUnit\n long creationTimestamp\nprivate static java.util.concurrent.TimeUnit unparcelDelayUnit(android.os.Parcel)\nprivate void parcelDelayUnit(android.os.Parcel,int)\nclass SampleWithCustomBuilder extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genBuilder=true, genAidl=false, genToString=true)\nabstract com.android.codegentest.SampleWithCustomBuilder.Builder setDelayAmount(long)\npublic abstract com.android.codegentest.SampleWithCustomBuilder.Builder setDelayUnit(java.util.concurrent.TimeUnit)\npublic com.android.codegentest.SampleWithCustomBuilder.Builder setDelay(long,java.util.concurrent.TimeUnit)\nclass BaseBuilder extends java.lang.Object implements []")
+ inputSignatures = " long delayAmount\n @android.annotation.NonNull java.util.concurrent.TimeUnit delayUnit\n long creationTimestamp\nprivate static java.util.concurrent.TimeUnit unparcelDelayUnit(android.os.Parcel)\nprivate void parcelDelayUnit(android.os.Parcel,int)\nclass SampleWithCustomBuilder extends java.lang.Object implements [android.os.Parcelable]\nabstract com.android.codegentest.SampleWithCustomBuilder.Builder setDelayAmount(long)\npublic abstract com.android.codegentest.SampleWithCustomBuilder.Builder setDelayUnit(java.util.concurrent.TimeUnit)\npublic com.android.codegentest.SampleWithCustomBuilder.Builder setDelay(long,java.util.concurrent.TimeUnit)\nclass BaseBuilder extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genBuilder=true, genAidl=false, genToString=true)\nabstract com.android.codegentest.SampleWithCustomBuilder.Builder setDelayAmount(long)\npublic abstract com.android.codegentest.SampleWithCustomBuilder.Builder setDelayUnit(java.util.concurrent.TimeUnit)\npublic com.android.codegentest.SampleWithCustomBuilder.Builder setDelay(long,java.util.concurrent.TimeUnit)\nclass BaseBuilder extends java.lang.Object implements []")
@Deprecated
private void __metadata() {}
diff --git a/tests/Codegen/src/com/android/codegentest/SampleWithNestedDataClasses.java b/tests/Codegen/src/com/android/codegentest/SampleWithNestedDataClasses.java
index f98d7b05c2d3..d40962456741 100644
--- a/tests/Codegen/src/com/android/codegentest/SampleWithNestedDataClasses.java
+++ b/tests/Codegen/src/com/android/codegentest/SampleWithNestedDataClasses.java
@@ -36,7 +36,7 @@ public class SampleWithNestedDataClasses {
- // Code below generated by codegen v1.0.15.
+ // Code below generated by codegen v1.0.23.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -135,8 +135,8 @@ public class SampleWithNestedDataClasses {
};
@DataClass.Generated(
- time = 1582685653406L,
- codegenVersion = "1.0.15",
+ time = 1616541545539L,
+ codegenVersion = "1.0.23",
sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/SampleWithNestedDataClasses.java",
inputSignatures = " @android.annotation.NonNull java.lang.String mBar\nclass NestedDataClass extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true)")
@Deprecated
@@ -160,7 +160,7 @@ public class SampleWithNestedDataClasses {
- // Code below generated by codegen v1.0.15.
+ // Code below generated by codegen v1.0.23.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -259,8 +259,8 @@ public class SampleWithNestedDataClasses {
};
@DataClass.Generated(
- time = 1582685653415L,
- codegenVersion = "1.0.15",
+ time = 1616541545548L,
+ codegenVersion = "1.0.23",
sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/SampleWithNestedDataClasses.java",
inputSignatures = " @android.annotation.NonNull long mBaz2\nclass NestedDataClass3 extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true)")
@Deprecated
@@ -274,7 +274,7 @@ public class SampleWithNestedDataClasses {
- // Code below generated by codegen v1.0.15.
+ // Code below generated by codegen v1.0.23.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -373,8 +373,8 @@ public class SampleWithNestedDataClasses {
};
@DataClass.Generated(
- time = 1582685653420L,
- codegenVersion = "1.0.15",
+ time = 1616541545552L,
+ codegenVersion = "1.0.23",
sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/SampleWithNestedDataClasses.java",
inputSignatures = " @android.annotation.NonNull java.lang.String mBaz\nclass NestedDataClass2 extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true)")
@Deprecated
diff --git a/tests/Codegen/src/com/android/codegentest/StaleDataclassDetectorFalsePositivesTest.java b/tests/Codegen/src/com/android/codegentest/StaleDataclassDetectorFalsePositivesTest.java
index 6b4fc2fa157f..3583b95fb4ce 100644
--- a/tests/Codegen/src/com/android/codegentest/StaleDataclassDetectorFalsePositivesTest.java
+++ b/tests/Codegen/src/com/android/codegentest/StaleDataclassDetectorFalsePositivesTest.java
@@ -15,10 +15,16 @@
*/
package com.android.codegentest;
+import android.annotation.IntRange;
import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.pm.PackageManager;
import com.android.internal.util.DataClass;
+import java.util.List;
+import java.util.Set;
+
/**
* Test for some false positive pitfalls for
* {@link android.processor.staledataclass.StaleDataclassProcessor}
@@ -46,12 +52,19 @@ public class StaleDataclassDetectorFalsePositivesTest {
/* Initializers should be ignored */
{}
+ /* Wildcard type argument should work correctly */
+ @Nullable
+ private List<Set<?>> mUsesWildcards = null;
+
/** Unrelated methods should be noted, without triggering staleness false positives */
public @NonNull String someMethod(int param) { return null; }
+ /** Inlined constants in annotation args should be fine */
+ private @IntRange(from = PackageManager.PERMISSION_GRANTED) void annotatedWithConstArg() {}
- // Code below generated by codegen v1.0.15.
+
+ // Code below generated by codegen v1.0.23.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -64,11 +77,22 @@ public class StaleDataclassDetectorFalsePositivesTest {
//@formatter:off
+ @DataClass.Generated.Member
+ public @Nullable List<Set<?>> getUsesWildcards() {
+ return mUsesWildcards;
+ }
+
+ @DataClass.Generated.Member
+ public @NonNull StaleDataclassDetectorFalsePositivesTest setUsesWildcards(@NonNull List<Set<?>> value) {
+ mUsesWildcards = value;
+ return this;
+ }
+
@DataClass.Generated(
- time = 1582685652436L,
- codegenVersion = "1.0.15",
+ time = 1616541544639L,
+ codegenVersion = "1.0.23",
sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/StaleDataclassDetectorFalsePositivesTest.java",
- inputSignatures = "public @android.annotation.NonNull java.lang.String someMethod(int)\nclass StaleDataclassDetectorFalsePositivesTest extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false, genBuilder=false)")
+ inputSignatures = "private @android.annotation.Nullable java.util.List<java.util.Set<?>> mUsesWildcards\npublic @android.annotation.NonNull java.lang.String someMethod(int)\nprivate @android.annotation.IntRange void annotatedWithConstArg()\nclass StaleDataclassDetectorFalsePositivesTest extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false, genBuilder=false)")
@Deprecated
private void __metadata() {}
diff --git a/tests/DozeTest/src/com/android/dreams/dozetest/DozeTestDream.java b/tests/DozeTest/src/com/android/dreams/dozetest/DozeTestDream.java
index fa292bd0d57a..6985702c24e6 100644
--- a/tests/DozeTest/src/com/android/dreams/dozetest/DozeTestDream.java
+++ b/tests/DozeTest/src/com/android/dreams/dozetest/DozeTestDream.java
@@ -83,7 +83,7 @@ public class DozeTestDream extends DreamService {
filter.addAction(intent.getAction());
registerReceiver(mAlarmReceiver, filter);
mAlarmIntent = PendingIntent.getBroadcast(this, 0, intent,
- PendingIntent.FLAG_CANCEL_CURRENT);
+ PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_MUTABLE_UNAUDITED);
setDozeScreenState(DISPLAY_STATE_WHEN_DOZING);
}
diff --git a/tests/DpiTest/AndroidManifest.xml b/tests/DpiTest/AndroidManifest.xml
index a4d8c7973141..cf4c21dbe128 100644
--- a/tests/DpiTest/AndroidManifest.xml
+++ b/tests/DpiTest/AndroidManifest.xml
@@ -15,26 +15,34 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.google.android.test.dpi">
- <uses-sdk android:minSdkVersion="3" android:targetSdkVersion="3" />
- <supports-screens android:smallScreens="true" />
+ package="com.google.android.test.dpi">
+ <uses-sdk android:minSdkVersion="3"
+ android:targetSdkVersion="3"/>
+ <supports-screens android:smallScreens="true"/>
<compatible-screens>
- <screen android:screenSize="small" android:screenDensity="ldpi" />
- <screen android:screenSize="small" android:screenDensity="xhdpi" />
- <screen android:screenSize="large" android:screenDensity="hdpi" />
- <screen android:screenSize="xlarge" android:screenDensity="mdpi" />
+ <screen android:screenSize="small"
+ android:screenDensity="ldpi"/>
+ <screen android:screenSize="small"
+ android:screenDensity="xhdpi"/>
+ <screen android:screenSize="large"
+ android:screenDensity="hdpi"/>
+ <screen android:screenSize="xlarge"
+ android:screenDensity="mdpi"/>
</compatible-screens>
<application android:label="DpiTest">
- <activity android:name="DpiTestActivity">
+ <activity android:name="DpiTestActivity"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="DpiTestNoCompatActivity" android:label="DpiTestNoCompat">
+ <activity android:name="DpiTestNoCompatActivity"
+ android:label="DpiTestNoCompat"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
diff --git a/tests/DpiTest/src/com/google/android/test/dpi/DpiTestActivity.java b/tests/DpiTest/src/com/google/android/test/dpi/DpiTestActivity.java
index 01c1c70f3f2a..cf501aed1dd5 100644
--- a/tests/DpiTest/src/com/google/android/test/dpi/DpiTestActivity.java
+++ b/tests/DpiTest/src/com/google/android/test/dpi/DpiTestActivity.java
@@ -19,23 +19,23 @@ package com.google.android.test.dpi;
import android.app.Activity;
import android.app.ActivityThread;
import android.app.Application;
-import android.os.Bundle;
-import android.graphics.BitmapFactory;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-import android.widget.ScrollView;
-import android.view.LayoutInflater;
-import android.view.View;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.res.CompatibilityInfo;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
import android.util.DisplayMetrics;
import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.LinearLayout;
+import android.widget.ScrollView;
+import android.widget.TextView;
public class DpiTestActivity extends Activity {
public DpiTestActivity() {
@@ -64,7 +64,7 @@ public class DpiTestActivity extends Activity {
| ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES;
app.getResources().setCompatibilityInfo(new CompatibilityInfo(ai,
getResources().getConfiguration().screenLayout,
- getResources().getConfiguration().smallestScreenWidthDp, false));
+ getResources().getConfiguration().smallestScreenWidthDp, false, 1f));
}
} catch (PackageManager.NameNotFoundException e) {
throw new RuntimeException("ouch", e);
diff --git a/tests/FeatureSplit/base/AndroidManifest.xml b/tests/FeatureSplit/base/AndroidManifest.xml
index e82b3b9d45fc..1bc07ef413df 100644
--- a/tests/FeatureSplit/base/AndroidManifest.xml
+++ b/tests/FeatureSplit/base/AndroidManifest.xml
@@ -15,15 +15,17 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.test.split.feature">
+ package="com.android.test.split.feature">
- <uses-sdk android:minSdkVersion="21" />
+ <uses-sdk android:minSdkVersion="21"/>
<application android:label="@string/app_title">
- <activity android:name=".ActivityMain" android:label="Feature Base">
+ <activity android:name=".ActivityMain"
+ android:label="Feature Base"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
diff --git a/tests/FeatureSplit/feature1/AndroidManifest.xml b/tests/FeatureSplit/feature1/AndroidManifest.xml
index 086c2c33422d..4581a85b3efb 100644
--- a/tests/FeatureSplit/feature1/AndroidManifest.xml
+++ b/tests/FeatureSplit/feature1/AndroidManifest.xml
@@ -15,17 +15,19 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.test.split.feature"
- featureSplit="feature1">
+ package="com.android.test.split.feature"
+ featureSplit="feature1">
- <uses-sdk android:minSdkVersion="21" />
- <uses-split android:name="feature2" />
+ <uses-sdk android:minSdkVersion="21"/>
+ <uses-split android:name="feature2"/>
<application>
- <activity android:name=".one.One" android:label="Feature One">
+ <activity android:name=".one.One"
+ android:label="Feature One"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
diff --git a/tests/FixVibrateSetting/AndroidManifest.xml b/tests/FixVibrateSetting/AndroidManifest.xml
index 007d6821498b..c2d5918a4681 100644
--- a/tests/FixVibrateSetting/AndroidManifest.xml
+++ b/tests/FixVibrateSetting/AndroidManifest.xml
@@ -1,13 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.fixvibratesetting">
- <uses-permission android:name="android.permission.VIBRATE" />
+ package="com.android.fixvibratesetting">
+ <uses-permission android:name="android.permission.VIBRATE"/>
<application>
- <activity android:name="FixVibrateSetting" android:label="@string/app_label">
+ <activity android:name="FixVibrateSetting"
+ android:label="@string/app_label"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
diff --git a/tests/FlickerTests/Android.bp b/tests/FlickerTests/Android.bp
index 4f463f964c77..217a72b90fd4 100644
--- a/tests/FlickerTests/Android.bp
+++ b/tests/FlickerTests/Android.bp
@@ -25,15 +25,51 @@ package {
android_test {
name: "FlickerTests",
- srcs: ["src/**/*.java"],
+ srcs: ["src/**/*.java", "src/**/*.kt"],
+ manifest: "AndroidManifest.xml",
+ test_config: "AndroidTest.xml",
platform_apis: true,
certificate: "platform",
test_suites: ["device-tests"],
libs: ["android.test.runner"],
static_libs: [
+ "androidx.test.ext.junit",
"flickertestapplib",
"flickerlib",
"truth-prebuilt",
- "app-helpers-core",
+ "launcher-helper-lib",
+ "launcher-aosp-tapl",
+ "platform-test-annotations",
],
}
+
+java_library {
+ name: "wm-flicker-common-assertions",
+ platform_apis: true,
+ srcs: [
+ "src/**/*Assertions.java",
+ "src/**/*Assertions.kt",
+ ],
+ exclude_srcs: [
+ "**/helpers/*",
+ ],
+ static_libs: [
+ "flickerlib",
+ "truth-prebuilt",
+ "app-helpers-core"
+ ],
+}
+
+java_library {
+ name: "wm-flicker-common-app-helpers",
+ platform_apis: true,
+ srcs: [
+ "**/helpers/*"
+ ],
+ static_libs: [
+ "flickerlib",
+ "flickertestapplib",
+ "truth-prebuilt",
+ "app-helpers-core"
+ ],
+} \ No newline at end of file
diff --git a/tests/FlickerTests/AndroidManifest.xml b/tests/FlickerTests/AndroidManifest.xml
index 91fb7c12b392..fda609196456 100644
--- a/tests/FlickerTests/AndroidManifest.xml
+++ b/tests/FlickerTests/AndroidManifest.xml
@@ -17,19 +17,31 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.server.wm.flicker">
- <uses-sdk android:minSdkVersion="27" android:targetSdkVersion="27"/>
+ <uses-sdk android:minSdkVersion="29" android:targetSdkVersion="29"/>
<!-- Read and write traces from external storage -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+ <!-- Allow the test to write directly to /sdcard/ -->
+ <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
<!-- Write secure settings -->
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
<!-- Capture screen contents -->
<uses-permission android:name="android.permission.ACCESS_SURFACE_FLINGER" />
<!-- Enable / Disable tracing !-->
<uses-permission android:name="android.permission.DUMP" />
+ <!-- Force-stop test apps -->
+ <uses-permission android:name="android.permission.FORCE_STOP_PACKAGES"/>
<!-- Run layers trace -->
<uses-permission android:name="android.permission.HARDWARE_TEST"/>
- <application>
+ <!-- Capture screen recording -->
+ <uses-permission android:name="android.permission.CAPTURE_VIDEO_OUTPUT"/>
+ <!-- Workaround grant runtime permission exception from b/152733071 -->
+ <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS"/>
+ <uses-permission android:name="android.permission.READ_LOGS"/>
+ <!-- ATM.removeRootTasksWithActivityTypes() -->
+ <uses-permission android:name="android.permission.MANAGE_ACTIVITY_TASKS" />
+ <!-- Allow the test to write directly to /sdcard/ -->
+ <application android:requestLegacyExternalStorage="true">
<uses-library android:name="android.test.runner"/>
</application>
diff --git a/tests/FlickerTests/AndroidTest.xml b/tests/FlickerTests/AndroidTest.xml
index a331ec5b52bd..896ec9ae922c 100644
--- a/tests/FlickerTests/AndroidTest.xml
+++ b/tests/FlickerTests/AndroidTest.xml
@@ -10,12 +10,14 @@
<!-- prevents the phone from restarting -->
<option name="force-skip-system-props" value="true" />
<!-- set WM tracing verbose level to all -->
- <option name="run-command" value="adb shell cmd window tracing level all" />
- <!-- inform WM to log all transactions -->
- <option name="run-command" value="adb shell cmd window tracing transaction" />
+ <option name="run-command" value="cmd window tracing level all" />
+ <!-- set WM tracing to frame (avoid incomplete states) -->
+ <option name="run-command" value="cmd window tracing frame" />
+ <!-- restart launcher to activate TAPL -->
+ <option name="run-command" value="setprop ro.test_harness 1 ; am force-stop com.google.android.apps.nexuslauncher" />
</target_preparer>
<target_preparer class="com.android.tradefed.targetprep.DeviceCleaner">
- <!-- keeps the screen on during tests -->
+ <!-- reboot the device to teardown any crashed tests -->
<option name="cleanup-action" value="REBOOT" />
</target_preparer>
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
@@ -25,9 +27,8 @@
</target_preparer>
<test class="com.android.tradefed.testtype.AndroidJUnitTest">
<option name="package" value="com.android.server.wm.flicker"/>
- <option name="exclude-annotation" value="org.junit.Ignore" />
<option name="shell-timeout" value="6600s" />
- <option name="test-timeout" value="6000s" />
+ <option name="test-timeout" value="6600s" />
<option name="hidden-api-checks" value="false" />
</test>
<metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
diff --git a/tests/FlickerTests/README.md b/tests/FlickerTests/README.md
index a7c9e20e0a07..6b28fdf8a8ef 100644
--- a/tests/FlickerTests/README.md
+++ b/tests/FlickerTests/README.md
@@ -1,146 +1,88 @@
# Flicker Test Library
## Motivation
-Detect *flicker* &mdash; any discontinuous, or unpredictable behavior seen during UI transitions that is not due to performance. This is often the result of a logic error in the code and difficult to identify because the issue is transient and at times difficult to reproduce. This library helps create integration tests between `SurfaceFlinger`, `WindowManager` and `SystemUI` to identify flicker.
+This set of tests use the flickerlib from `platform_testing/libraries/flicker` to execute a set of common UI transitions to detect discontinuous or unpredictable behavior.
-## Adding a Test
-The library builds and runs UI transitions, captures Winscope traces and exposes common assertions that can be tested against each trace.
-
-### Building Transitions
-Start by defining common or error prone transitions using `TransitionRunner`.
-```java
-// Example: Build a transition that cold launches an app from launcher
-TransitionRunner transition = TransitionRunner.newBuilder()
- // Specify a tag to identify the transition (optional)
- .withTag("OpenAppCold_" + testApp.getLauncherName())
-
- // Specify preconditions to setup the device
- // Wake up device and go to home screen
- .runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen)
-
- // Setup transition under test
- // Press the home button and close the app to test a cold start
- .runBefore(device::pressHome)
- .runBefore(testApp::exit)
-
- // Run the transition under test
- // Open the app and wait for UI to be idle
- // This is the part of the transition that will be tested.
- .run(testApp::open)
- .run(device::waitForIdle)
-
- // Perform any tear downs
- // Close the app
- .runAfterAll(testApp::exit)
-
- // Number of times to repeat the transition to catch any flaky issues
- .repeat(5);
-```
-
-
-Run the transition to get a list of `TransitionResult` for each time the transition is repeated.
-```java
- List<TransitionResult> results = transition.run();
-```
-`TransitionResult` contains paths to test artifacts such as Winscope traces and screen recordings.
-
-
-### Checking Assertions
-Each `TransitionResult` can be tested using an extension of the Google Truth library, `LayersTraceSubject` and `WmTraceSubject`. They try to balance test principles set out by Google Truth (not supporting nested assertions, keeping assertions simple) with providing support for common assertion use cases.
-
-Each trace can be represented as a ordered collection of trace entries, with an associated timestamp. Each trace entry has common assertion checks. The trace subjects expose methods to filter the range of entries and test for changing assertions.
-
-```java
- TransitionResult result = results.get(0);
- Rect displayBounds = getDisplayBounds();
+The tests are organized in packages according to the transitions they test (e.g., `rotation`, `splitscreen`).
- // check all trace entries
- assertThat(result).coversRegion(displayBounds).forAllEntries();
-
- // check a range of entries
- assertThat(result).coversRegion(displayBounds).forRange(startTime, endTime);
-
- // check first entry
- assertThat(result).coversRegion(displayBounds).inTheBeginning();
+## Adding a Test
- // check last entry
- assertThat(result).coversRegion(displayBounds).atTheEnd();
+By default tests should inherit from `RotationTestBase` or `NonRotationTestBase` and must override the variable `transitionToRun` (Kotlin) or the function `getTransitionToRun()` (Java).
+Only tests that are not supported by these classes should inherit directly from the `FlickerTestBase` class.
- // check a change in assertions, e.g. wallpaper window is visible,
- // then wallpaper window becomes and stays invisible
- assertThat(result)
- .showsBelowAppWindow("wallpaper")
- .then()
- .hidesBelowAppWindow("wallpaper")
- .forAllEntries();
-```
+### Rotation animations and transitions
-All assertions return `Result` which contains a `success` flag, `assertionName` string identifier, and `reason` string to provide actionable details to the user. The `reason` string is build along the way with all the details as to why the assertions failed and any hints which might help the user determine the root cause. Failed assertion message will also contain a path to the trace that was tested. Example of a failed test:
+Tests that rotate the device should inherit from `RotationTestBase`.
+Tests that inherit from the class automatically receive start and end rotation values.
+Moreover, these tests inherit the following checks:
+* all regions on the screen are covered
+* status bar is always visible
+* status bar rotates
+* nav bar is always visible
+* nav bar is rotates
-```
- java.lang.AssertionError: Not true that <com.android.server.wm.flicker.LayersTrace@65da4cc>
- Layers Trace can be found in: /layers_trace_emptyregion.pb
- Timestamp: 2308008331271
- Assertion: coversRegion
- Reason: Region to test: Rect(0, 0 - 1440, 2880)
- first empty point: 0, 99
- visible regions:
- StatusBar#0Rect(0, 0 - 1440, 98)
- NavigationBar#0Rect(0, 2712 - 1440, 2880)
- ScreenDecorOverlay#0Rect(0, 0 - 1440, 91)
- ...
- at com.google.common.truth.FailureStrategy.fail(FailureStrategy.java:24)
- ...
-```
+The default tests can be disabled by overriding the respective methods and including an `@Ignore` annotation.
----
+### Non-Rotation animations and transitions
-## Running Tests
+`NonRotationTestBase` was created to make it easier to write tests that do not involve rotation (e.g., `Pip`, `split screen` or `IME`).
+Tests that inherit from the class are automatically executed twice: once in portrait and once in landscape mode and the assertions are checked independently.
+Moreover, these tests inherit the following checks:
+* all regions on the screen are covered
+* status bar is always visible
+* nav bar is always visible
-The tests can be run as any other Android JUnit tests. `platform_testing/tests/flicker` uses the library to test common UI transitions. Run `atest FlickerTest` to execute these tests.
+The default tests can be disabled by overriding the respective methods and including an `@Ignore` annotation.
----
+### Exceptional cases
-## Other Topics
-### Monitors
-Monitors capture test artifacts for each transition run. They are started before each iteration of the test transition (after the `runBefore` calls) and stopped after the transition is completed. Each iteration will produce a new test artifact. The following monitors are available:
+Tests that rotate the device should inherit from `RotationTestBase`.
+This class allows the test to be freely configured and does not provide any assertions.
-#### LayersTraceMonitor
-Captures Layers trace. This monitor is started by default. Build a transition with `skipLayersTrace()` to disable this monitor.
-#### WindowManagerTraceMonitor
-Captures Window Manager trace. This monitor is started by default. Build a transition with `skipWindowManagerTrace()` to disable this monitor.
-#### WindowAnimationFrameStatsMonitor
-Captures WindowAnimationFrameStats for the transition. This monitor is started by default and is used to eliminate *janky* runs. If an iteration has skipped frames, as determined by WindowAnimationFrameStats, the results for the iteration is skipped. If the list of results is empty after all iterations are completed, then the test should fail. Build a transition with `includeJankyRuns()` to disable this monitor.
-#### ScreenRecorder
-Captures screen to a video file. This monitor is disabled by default. Build a transition with `recordEachRun()` to capture each transition or build with `recordAllRuns()` to capture every transition including setup and teardown.
----
+### Example
-### Extending Assertions
-
-To add a new assertion, add a function to one of the trace entry classes, `LayersTrace.Entry` or `WindowManagerTrace.Entry`.
+Start by defining common or error prone transitions using `TransitionRunner`.
+```kotlin
+@LargeTest
+@RunWith(Parameterized::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+class MyTest(
+ beginRotationName: String,
+ beginRotation: Int
+) : NonRotationTestBase(beginRotationName, beginRotation) {
+ init {
+ mTestApp = MyAppHelper(InstrumentationRegistry.getInstrumentation())
+ }
-```java
- // Example adds an assertion to the check if layer is hidden by parent.
- Result isHiddenByParent(String layerName) {
- // Result should contain a details if assertion fails for any reason
- // such as if layer is not found or layer is not hidden by parent
- // or layer has no parent.
- // ...
+ override val transitionToRun: TransitionRunner
+ get() = TransitionRunner.newBuilder()
+ .withTag("myTest")
+ .recordAllRuns()
+ .runBefore { device.pressHome() }
+ .runBefore { device.waitForIdle() }
+ .run { testApp.open() }
+ .runAfter{ testApp.exit() }
+ .repeat(2)
+ .includeJankyRuns()
+ .build()
+
+ @Test
+ fun myWMTest() {
+ checkResults {
+ WmTraceSubject.assertThat(it)
+ .showsAppWindow(MyTestApp)
+ .forAllEntries()
+ }
}
-```
-Then add a function to the trace subject `LayersTraceSubject` or `WmTraceSubject` which will add the assertion for testing. When the assertion is evaluated, the trace will first be filtered then the assertion will be applied to the remaining entries.
-```java
- public LayersTraceSubject isHiddenByParent(String layerName) {
- mChecker.add(entry -> entry.isHiddenByParent(layerName),
- "isHiddenByParent(" + layerName + ")");
- return this;
+ @Test
+ fun mySFTest() {
+ checkResults {
+ LayersTraceSubject.assertThat(it)
+ .showsLayer(MyTestApp)
+ .forAllEntries()
+ }
}
+}
```
-
-To use the new assertion:
-```java
- // Check if "Chrome" layer is hidden by parent in the first trace entry.
- assertThat(result).isHiddenByParent("Chrome").inTheBeginning();
-``` \ No newline at end of file
diff --git a/tests/FlickerTests/TEST_MAPPING b/tests/FlickerTests/TEST_MAPPING
deleted file mode 100644
index db251b907caa..000000000000
--- a/tests/FlickerTests/TEST_MAPPING
+++ /dev/null
@@ -1,13 +0,0 @@
-{
- "postsubmit": [
- // Run tests on real device
- {
- "name": "FlickerTests",
- "keywords": ["primary-device"]
- },
- // Also run the tests in the cloud
- {
- "name": "FlickerTests"
- }
- ]
-} \ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ChangeAppRotationTest.java b/tests/FlickerTests/src/com/android/server/wm/flicker/ChangeAppRotationTest.java
deleted file mode 100644
index ad64840aaee2..000000000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ChangeAppRotationTest.java
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- * Copyright (C) 2018 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.wm.flicker;
-
-import static android.view.Surface.rotationToString;
-
-import static com.android.server.wm.flicker.CommonTransitions.changeAppRotation;
-import static com.android.server.wm.flicker.WindowUtils.getAppPosition;
-import static com.android.server.wm.flicker.WindowUtils.getNavigationBarPosition;
-import static com.android.server.wm.flicker.WindowUtils.getStatusBarPosition;
-import static com.android.server.wm.flicker.WmTraceSubject.assertThat;
-
-import android.graphics.Rect;
-import android.util.Log;
-import android.view.Surface;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.FlakyTest;
-import androidx.test.filters.LargeTest;
-
-import org.junit.Before;
-import org.junit.FixMethodOrder;
-import org.junit.Ignore;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.MethodSorters;
-import org.junit.runners.Parameterized;
-import org.junit.runners.Parameterized.Parameters;
-
-import java.util.ArrayList;
-import java.util.Collection;
-
-/**
- * Cycle through supported app rotations.
- * To run this test: {@code atest FlickerTest:ChangeAppRotationTest}
- */
-@LargeTest
-@RunWith(Parameterized.class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-public class ChangeAppRotationTest extends FlickerTestBase {
- private int mBeginRotation;
- private int mEndRotation;
-
- public ChangeAppRotationTest(String beginRotationName, String endRotationName,
- int beginRotation, int endRotation) {
- this.mTestApp = new StandardAppHelper(InstrumentationRegistry.getInstrumentation(),
- "com.android.server.wm.flicker.testapp", "SimpleApp");
- this.mBeginRotation = beginRotation;
- this.mEndRotation = endRotation;
- }
-
- @Parameters(name = "{0}-{1}")
- public static Collection<Object[]> getParams() {
- int[] supportedRotations =
- {Surface.ROTATION_0, Surface.ROTATION_90};
- Collection<Object[]> params = new ArrayList<>();
- for (int begin : supportedRotations) {
- for (int end : supportedRotations) {
- if (begin != end) {
- params.add(new Object[]{rotationToString(begin), rotationToString(end), begin,
- end});
- }
- }
- }
- return params;
- }
-
- @Before
- public void runTransition() {
- super.runTransition(
- changeAppRotation(mTestApp, mUiDevice, mBeginRotation, mEndRotation)
- .includeJankyRuns().build());
- }
-
- @FlakyTest(bugId = 140855415)
- @Ignore("Waiting bug feedback")
- @Test
- public void checkVisibility_navBarWindowIsAlwaysVisible() {
- checkResults(result -> assertThat(result)
- .showsAboveAppWindow(NAVIGATION_BAR_WINDOW_TITLE).forAllEntries());
- }
-
- @FlakyTest(bugId = 140855415)
- @Ignore("Waiting bug feedback")
- @Test
- public void checkVisibility_statusBarWindowIsAlwaysVisible() {
- checkResults(result -> assertThat(result)
- .showsAboveAppWindow(STATUS_BAR_WINDOW_TITLE).forAllEntries());
- }
-
- @Test
- public void checkPosition_navBarLayerRotatesAndScales() {
- Rect startingPos = getNavigationBarPosition(mBeginRotation);
- Rect endingPos = getNavigationBarPosition(mEndRotation);
- checkResults(result -> {
- LayersTraceSubject.assertThat(result)
- .hasVisibleRegion(NAVIGATION_BAR_WINDOW_TITLE, startingPos)
- .inTheBeginning();
- LayersTraceSubject.assertThat(result)
- .hasVisibleRegion(NAVIGATION_BAR_WINDOW_TITLE, endingPos).atTheEnd();
- }
- );
- }
-
- @Test
- public void checkPosition_appLayerRotates() {
- Rect startingPos = getAppPosition(mBeginRotation);
- Rect endingPos = getAppPosition(mEndRotation);
- Log.e(TAG, "startingPos=" + startingPos + " endingPos=" + endingPos);
- checkResults(result -> {
- LayersTraceSubject.assertThat(result)
- .hasVisibleRegion(mTestApp.getPackage(), startingPos).inTheBeginning();
- LayersTraceSubject.assertThat(result)
- .hasVisibleRegion(mTestApp.getPackage(), endingPos).atTheEnd();
- }
- );
- }
-
- @Test
- public void checkPosition_statusBarLayerScales() {
- Rect startingPos = getStatusBarPosition(mBeginRotation);
- Rect endingPos = getStatusBarPosition(mEndRotation);
- checkResults(result -> {
- LayersTraceSubject.assertThat(result)
- .hasVisibleRegion(STATUS_BAR_WINDOW_TITLE, startingPos)
- .inTheBeginning();
- LayersTraceSubject.assertThat(result)
- .hasVisibleRegion(STATUS_BAR_WINDOW_TITLE, endingPos).atTheEnd();
- }
- );
- }
-
- @Test
- public void checkVisibility_screenshotLayerBecomesInvisible() {
- checkResults(result -> LayersTraceSubject.assertThat(result)
- .showsLayer(mTestApp.getPackage())
- .then()
- .replaceVisibleLayer(mTestApp.getPackage(), "Screenshot")
- .then()
- .showsLayer(mTestApp.getPackage()).and().showsLayer("Screenshot")
- .then()
- .replaceVisibleLayer("Screenshot", mTestApp.getPackage())
- .forAllEntries());
- }
-
- @FlakyTest(bugId = 140855415)
- @Ignore("Waiting bug feedback")
- @Test
- public void checkVisibility_navBarLayerIsAlwaysVisible() {
- checkResults(result -> LayersTraceSubject.assertThat(result)
- .showsLayer(NAVIGATION_BAR_WINDOW_TITLE).forAllEntries());
- }
-
- @FlakyTest(bugId = 140855415)
- @Ignore("Waiting bug feedback")
- @Test
- public void checkVisibility_statusBarLayerIsAlwaysVisible() {
- checkResults(result -> LayersTraceSubject.assertThat(result)
- .showsLayer(STATUS_BAR_WINDOW_TITLE).forAllEntries());
- }
-}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/CloseImeAutoOpenWindowToAppTest.java b/tests/FlickerTests/src/com/android/server/wm/flicker/CloseImeAutoOpenWindowToAppTest.java
deleted file mode 100644
index 022f798e82f5..000000000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/CloseImeAutoOpenWindowToAppTest.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (C) 2019 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.wm.flicker;
-
-import static com.android.server.wm.flicker.CommonTransitions.editTextLoseFocusToApp;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.FlakyTest;
-import androidx.test.filters.LargeTest;
-
-import com.android.server.wm.flicker.helpers.ImeAppAutoFocusHelper;
-
-import org.junit.Before;
-import org.junit.FixMethodOrder;
-import org.junit.Ignore;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.MethodSorters;
-import org.junit.runners.Parameterized;
-
-/**
- * Test IME window closing back to app window transitions.
- * To run this test: {@code atest FlickerTests:CloseImeWindowToAppTest}
- */
-@LargeTest
-@RunWith(Parameterized.class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-public class CloseImeAutoOpenWindowToAppTest extends CloseImeWindowToAppTest {
-
- public CloseImeAutoOpenWindowToAppTest(String beginRotationName, int beginRotation) {
- super(beginRotationName, beginRotation);
-
- mTestApp = new ImeAppAutoFocusHelper(InstrumentationRegistry.getInstrumentation());
- }
-
- @Before
- public void runTransition() {
- run(editTextLoseFocusToApp((ImeAppAutoFocusHelper) mTestApp, mUiDevice, mBeginRotation)
- .includeJankyRuns().build());
- }
-
- @FlakyTest(bugId = 141458352)
- @Ignore("Waiting bug feedback")
- @Test
- public void checkVisibility_imeLayerBecomesInvisible() {
- super.checkVisibility_imeLayerBecomesInvisible();
- }
-
- @FlakyTest(bugId = 141458352)
- @Ignore("Waiting bug feedback")
- @Test
- public void checkVisibility_imeAppLayerIsAlwaysVisible() {
- super.checkVisibility_imeAppLayerIsAlwaysVisible();
- }
-
- @FlakyTest(bugId = 141458352)
- @Ignore("Waiting bug feedback")
- @Test
- public void checkVisibility_imeAppWindowIsAlwaysVisible() {
- super.checkVisibility_imeAppWindowIsAlwaysVisible();
- }
-
-}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/CloseImeAutoOpenWindowToHomeTest.java b/tests/FlickerTests/src/com/android/server/wm/flicker/CloseImeAutoOpenWindowToHomeTest.java
deleted file mode 100644
index d6f994b5c0d5..000000000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/CloseImeAutoOpenWindowToHomeTest.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (C) 2019 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.wm.flicker;
-
-import static com.android.server.wm.flicker.CommonTransitions.editTextLoseFocusToHome;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.FlakyTest;
-import androidx.test.filters.LargeTest;
-
-import com.android.server.wm.flicker.helpers.ImeAppAutoFocusHelper;
-
-import org.junit.Before;
-import org.junit.FixMethodOrder;
-import org.junit.Ignore;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.MethodSorters;
-import org.junit.runners.Parameterized;
-
-/**
- * Test IME window closing back to app window transitions.
- * To run this test: {@code atest FlickerTests:CloseImeWindowToAppTest}
- */
-@LargeTest
-@RunWith(Parameterized.class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-public class CloseImeAutoOpenWindowToHomeTest extends CloseImeWindowToHomeTest {
-
- public CloseImeAutoOpenWindowToHomeTest(String beginRotationName, int beginRotation) {
- super(beginRotationName, beginRotation);
-
- mTestApp = new ImeAppAutoFocusHelper(InstrumentationRegistry.getInstrumentation());
- }
-
- @Before
- public void runTransition() {
- run(editTextLoseFocusToHome((ImeAppAutoFocusHelper) mTestApp, mUiDevice, mBeginRotation)
- .includeJankyRuns().build());
- }
-
- @FlakyTest(bugId = 141458352)
- @Ignore("Waiting bug feedback")
- @Test
- public void checkVisibility_imeWindowBecomesInvisible() {
- super.checkVisibility_imeWindowBecomesInvisible();
- }
-
- @FlakyTest(bugId = 141458352)
- @Ignore("Waiting bug feedback")
- @Test
- public void checkVisibility_imeLayerBecomesInvisible() {
- super.checkVisibility_imeLayerBecomesInvisible();
- }
-}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/CloseImeWindowToAppTest.java b/tests/FlickerTests/src/com/android/server/wm/flicker/CloseImeWindowToAppTest.java
deleted file mode 100644
index 28da3af2b7c5..000000000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/CloseImeWindowToAppTest.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright (C) 2018 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.wm.flicker;
-
-import static com.android.server.wm.flicker.CommonTransitions.editTextLoseFocusToApp;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.LargeTest;
-
-import com.android.server.wm.flicker.helpers.ImeAppHelper;
-
-import org.junit.Before;
-import org.junit.FixMethodOrder;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.MethodSorters;
-import org.junit.runners.Parameterized;
-
-/**
- * Test IME window closing back to app window transitions.
- * To run this test: {@code atest FlickerTests:CloseImeWindowToAppTest}
- */
-@LargeTest
-@RunWith(Parameterized.class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-public class CloseImeWindowToAppTest extends NonRotationTestBase {
-
- static final String IME_WINDOW_TITLE = "InputMethod";
-
- public CloseImeWindowToAppTest(String beginRotationName, int beginRotation) {
- super(beginRotationName, beginRotation);
-
- mTestApp = new ImeAppHelper(InstrumentationRegistry.getInstrumentation());
- }
-
- @Before
- public void runTransition() {
- run(editTextLoseFocusToApp((ImeAppHelper) mTestApp, mUiDevice, mBeginRotation)
- .includeJankyRuns().build());
- }
-
- @Test
- public void checkVisibility_imeLayerBecomesInvisible() {
- checkResults(result -> LayersTraceSubject.assertThat(result)
- .showsLayer(IME_WINDOW_TITLE)
- .then()
- .hidesLayer(IME_WINDOW_TITLE)
- .forAllEntries());
- }
-
- @Test
- public void checkVisibility_imeAppLayerIsAlwaysVisible() {
- checkResults(result -> LayersTraceSubject.assertThat(result)
- .showsLayer(mTestApp.getPackage())
- .forAllEntries());
- }
-
- @Test
- public void checkVisibility_imeAppWindowIsAlwaysVisible() {
- checkResults(result -> WmTraceSubject.assertThat(result)
- .showsAppWindowOnTop(mTestApp.getPackage())
- .forAllEntries());
- }
-}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/CloseImeWindowToHomeTest.java b/tests/FlickerTests/src/com/android/server/wm/flicker/CloseImeWindowToHomeTest.java
deleted file mode 100644
index f740af9b89bf..000000000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/CloseImeWindowToHomeTest.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright (C) 2018 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.wm.flicker;
-
-import static com.android.server.wm.flicker.CommonTransitions.editTextLoseFocusToHome;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.LargeTest;
-
-import com.android.server.wm.flicker.helpers.ImeAppHelper;
-
-import org.junit.Before;
-import org.junit.FixMethodOrder;
-import org.junit.Ignore;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.MethodSorters;
-import org.junit.runners.Parameterized;
-
-/**
- * Test IME window closing to home transitions.
- * To run this test: {@code atest FlickerTests:CloseImeWindowToHomeTest}
- */
-@LargeTest
-@RunWith(Parameterized.class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-public class CloseImeWindowToHomeTest extends NonRotationTestBase {
-
- static final String IME_WINDOW_TITLE = "InputMethod";
-
- public CloseImeWindowToHomeTest(String beginRotationName, int beginRotation) {
- super(beginRotationName, beginRotation);
-
- mTestApp = new ImeAppHelper(InstrumentationRegistry.getInstrumentation());
- }
-
- @Before
- public void runTransition() {
- run(editTextLoseFocusToHome((ImeAppHelper) mTestApp, mUiDevice, mBeginRotation)
- .includeJankyRuns().build());
- }
-
- @Test
- public void checkVisibility_imeWindowBecomesInvisible() {
- checkResults(result -> WmTraceSubject.assertThat(result)
- .showsImeWindow(IME_WINDOW_TITLE)
- .then()
- .hidesImeWindow(IME_WINDOW_TITLE)
- .forAllEntries());
- }
-
- @Ignore("Flaky")
- @Test
- public void checkVisibility_imeLayerBecomesInvisible() {
- checkResults(result -> LayersTraceSubject.assertThat(result)
- .showsLayer(IME_WINDOW_TITLE)
- .then()
- .hidesLayer(IME_WINDOW_TITLE)
- .forAllEntries());
- }
-
- @Ignore("Flaky")
- @Test
- public void checkVisibility_imeAppLayerBecomesInvisible() {
- checkResults(result -> LayersTraceSubject.assertThat(result)
- .showsLayer(mTestApp.getPackage())
- .then()
- .hidesLayer(mTestApp.getPackage())
- .forAllEntries());
- }
-
- @Test
- public void checkVisibility_imeAppWindowBecomesInvisible() {
- checkResults(result -> WmTraceSubject.assertThat(result)
- .showsAppWindowOnTop(mTestApp.getPackage())
- .then()
- .hidesAppWindowOnTop(mTestApp.getPackage())
- .forAllEntries());
- }
-}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt
new file mode 100644
index 000000000000..a540dffb3c9c
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt
@@ -0,0 +1,223 @@
+/*
+ * Copyright (C) 2020 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.wm.flicker
+
+import android.platform.helpers.IAppHelper
+import com.android.server.wm.flicker.helpers.WindowUtils
+import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper.Companion.NAV_BAR_LAYER_NAME
+import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper.Companion.NAV_BAR_WINDOW_NAME
+import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper.Companion.STATUS_BAR_LAYER_NAME
+import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper.Companion.STATUS_BAR_WINDOW_NAME
+
+val HOME_WINDOW_TITLE = arrayOf("Wallpaper", "Launcher")
+
+fun FlickerTestParameter.statusBarWindowIsAlwaysVisible() {
+ assertWm {
+ this.showsAboveAppWindow(STATUS_BAR_WINDOW_NAME)
+ }
+}
+
+fun FlickerTestParameter.navBarWindowIsAlwaysVisible() {
+ assertWm {
+ this.showsAboveAppWindow(NAV_BAR_WINDOW_NAME)
+ }
+}
+
+fun FlickerTestParameter.launcherReplacesAppWindowAsTopWindow(testApp: IAppHelper) {
+ assertWm {
+ this.showsAppWindowOnTop(testApp.getPackage())
+ .then()
+ .showsAppWindowOnTop(*HOME_WINDOW_TITLE)
+ }
+}
+
+fun FlickerTestParameter.launcherWindowBecomesVisible() {
+ assertWm {
+ this.hidesBelowAppWindow(*HOME_WINDOW_TITLE)
+ .then()
+ .showsBelowAppWindow(*HOME_WINDOW_TITLE)
+ }
+}
+
+fun FlickerTestParameter.launcherWindowBecomesInvisible() {
+ assertWm {
+ this.showsBelowAppWindow(*HOME_WINDOW_TITLE)
+ .then()
+ .hidesBelowAppWindow(*HOME_WINDOW_TITLE)
+ }
+}
+
+fun FlickerTestParameter.appWindowAlwaysVisibleOnTop(packageName: String) {
+ assertWm {
+ this.showsAppWindowOnTop(packageName)
+ }
+}
+
+fun FlickerTestParameter.appWindowBecomesVisible(appName: String) {
+ assertWm {
+ this.hidesAppWindow(appName)
+ .then()
+ .showsAppWindow(appName)
+ }
+}
+
+fun FlickerTestParameter.appWindowBecomesInVisible(appName: String) {
+ assertWm {
+ this.showsAppWindow(appName)
+ .then()
+ .hidesAppWindow(appName)
+ }
+}
+
+@JvmOverloads
+fun FlickerTestParameter.noUncoveredRegions(
+ beginRotation: Int,
+ endRotation: Int = beginRotation,
+ allStates: Boolean = true
+) {
+ val startingBounds = WindowUtils.getDisplayBounds(beginRotation)
+ val endingBounds = WindowUtils.getDisplayBounds(endRotation)
+ if (allStates) {
+ assertLayers {
+ if (startingBounds == endingBounds) {
+ this.coversAtLeast(startingBounds)
+ } else {
+ this.coversAtLeast(startingBounds)
+ .then()
+ .coversAtLeast(endingBounds)
+ }
+ }
+ } else {
+ assertLayersStart {
+ this.visibleRegion().coversAtLeast(startingBounds)
+ }
+ assertLayersEnd {
+ this.visibleRegion().coversAtLeast(endingBounds)
+ }
+ }
+}
+
+@JvmOverloads
+fun FlickerTestParameter.navBarLayerIsAlwaysVisible(rotatesScreen: Boolean = false) {
+ if (rotatesScreen) {
+ assertLayers {
+ this.isVisible(NAV_BAR_LAYER_NAME)
+ .then()
+ .isInvisible(NAV_BAR_LAYER_NAME)
+ .then()
+ .isVisible(NAV_BAR_LAYER_NAME)
+ }
+ } else {
+ assertLayers {
+ this.isVisible(NAV_BAR_LAYER_NAME)
+ }
+ }
+}
+
+@JvmOverloads
+fun FlickerTestParameter.statusBarLayerIsAlwaysVisible(rotatesScreen: Boolean = false) {
+ if (rotatesScreen) {
+ assertLayers {
+ this.isVisible(STATUS_BAR_LAYER_NAME)
+ .then()
+ .isInvisible(STATUS_BAR_LAYER_NAME)
+ .then()
+ .isVisible(STATUS_BAR_LAYER_NAME)
+ }
+ } else {
+ assertLayers {
+ this.isVisible(STATUS_BAR_LAYER_NAME)
+ }
+ }
+}
+
+@JvmOverloads
+fun FlickerTestParameter.navBarLayerRotatesAndScales(
+ beginRotation: Int,
+ endRotation: Int = beginRotation
+) {
+ val startingPos = WindowUtils.getNavigationBarPosition(beginRotation)
+ val endingPos = WindowUtils.getNavigationBarPosition(endRotation)
+
+ assertLayersStart {
+ this.visibleRegion(NAV_BAR_LAYER_NAME).coversExactly(startingPos)
+ }
+ assertLayersEnd {
+ this.visibleRegion(NAV_BAR_LAYER_NAME).coversExactly(endingPos)
+ }
+}
+
+@JvmOverloads
+fun FlickerTestParameter.statusBarLayerRotatesScales(
+ beginRotation: Int,
+ endRotation: Int = beginRotation
+) {
+ val startingPos = WindowUtils.getStatusBarPosition(beginRotation)
+ val endingPos = WindowUtils.getStatusBarPosition(endRotation)
+
+ assertLayersStart {
+ this.visibleRegion(STATUS_BAR_LAYER_NAME).coversExactly(startingPos)
+ }
+ assertLayersEnd {
+ this.visibleRegion(STATUS_BAR_LAYER_NAME).coversExactly(endingPos)
+ }
+}
+
+fun FlickerTestParameter.appLayerReplacesLauncher(appName: String) {
+ assertLayers {
+ this.isVisible(*HOME_WINDOW_TITLE)
+ .then()
+ .isVisible(appName)
+ }
+}
+
+fun FlickerTestParameter.launcherLayerReplacesApp(testApp: IAppHelper) {
+ assertLayers {
+ this.isVisible(testApp.getPackage())
+ .then()
+ .isInvisible(testApp.getPackage())
+ .isVisible(*HOME_WINDOW_TITLE)
+ }
+}
+
+fun FlickerTestParameter.layerBecomesVisible(packageName: String) {
+ assertLayers {
+ this.isInvisible(packageName)
+ .then()
+ .isVisible(packageName)
+ }
+}
+
+fun FlickerTestParameter.layerBecomesInvisible(packageName: String) {
+ assertLayers {
+ this.isVisible(packageName)
+ .then()
+ .isInvisible(packageName)
+ }
+}
+
+fun FlickerTestParameter.focusChanges(vararg windows: String) {
+ assertEventLog {
+ this.focusChanges(windows)
+ }
+}
+
+fun FlickerTestParameter.focusDoesNotChange() {
+ assertEventLog {
+ this.focusDoesNotChange()
+ }
+} \ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonTransitions.java b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonTransitions.java
deleted file mode 100644
index 0201a95b18bb..000000000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonTransitions.java
+++ /dev/null
@@ -1,339 +0,0 @@
-/*
- * Copyright (C) 2018 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.wm.flicker;
-
-import static android.os.SystemClock.sleep;
-import static android.view.Surface.rotationToString;
-
-import static com.android.server.wm.flicker.helpers.AutomationUtils.clearRecents;
-import static com.android.server.wm.flicker.helpers.AutomationUtils.exitSplitScreen;
-import static com.android.server.wm.flicker.helpers.AutomationUtils.expandPipWindow;
-import static com.android.server.wm.flicker.helpers.AutomationUtils.launchSplitScreen;
-import static com.android.server.wm.flicker.helpers.AutomationUtils.stopPackage;
-
-import android.content.Context;
-import android.content.Intent;
-import android.os.RemoteException;
-import android.platform.helpers.IAppHelper;
-import android.support.test.uiautomator.By;
-import android.support.test.uiautomator.UiDevice;
-import android.support.test.uiautomator.UiObject2;
-import android.support.test.uiautomator.Until;
-import android.util.Rational;
-import android.view.Surface;
-
-import com.android.server.wm.flicker.TransitionRunner.TransitionBuilder;
-import com.android.server.wm.flicker.helpers.AutomationUtils;
-import com.android.server.wm.flicker.helpers.ImeAppHelper;
-import com.android.server.wm.flicker.helpers.PipAppHelper;
-
-/**
- * Collection of common transitions which can be used to test different apps or scenarios.
- */
-class CommonTransitions {
-
- public static final int ITERATIONS = 1;
- private static final String TAG = "FLICKER";
- private static final long APP_LAUNCH_TIMEOUT = 10000;
-
- private static void setRotation(UiDevice device, int rotation) {
- try {
- switch (rotation) {
- case Surface.ROTATION_270:
- device.setOrientationLeft();
- break;
-
- case Surface.ROTATION_90:
- device.setOrientationRight();
- break;
-
- case Surface.ROTATION_0:
- default:
- device.setOrientationNatural();
- }
- // Wait for animation to complete
- sleep(1000);
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
- }
-
- static TransitionBuilder openAppWarm(IAppHelper testApp, UiDevice
- device, int beginRotation) {
- return TransitionRunner.newBuilder()
- .withTag("OpenAppWarm_" + testApp.getLauncherName()
- + rotationToString(beginRotation))
- .recordAllRuns()
- .runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen)
- .runBeforeAll(() -> setRotation(device, beginRotation))
- .runBeforeAll(testApp::open)
- .runBefore(device::pressHome)
- .runBefore(device::waitForIdle)
- .runBefore(() -> setRotation(device, beginRotation))
- .run(testApp::open)
- .runAfterAll(testApp::exit)
- .runAfterAll(AutomationUtils::setDefaultWait)
- .repeat(ITERATIONS);
- }
-
- static TransitionBuilder closeAppWithBackKey(IAppHelper testApp, UiDevice
- device) {
- return TransitionRunner.newBuilder()
- .withTag("closeAppWithBackKey_" + testApp.getLauncherName())
- .recordAllRuns()
- .runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen)
- .runBefore(testApp::open)
- .runBefore(device::waitForIdle)
- .run(device::pressBack)
- .run(device::waitForIdle)
- .runAfterAll(testApp::exit)
- .runAfterAll(AutomationUtils::setDefaultWait)
- .repeat(ITERATIONS);
- }
-
- static TransitionBuilder closeAppWithHomeKey(IAppHelper testApp, UiDevice
- device) {
- return TransitionRunner.newBuilder()
- .withTag("closeAppWithHomeKey_" + testApp.getLauncherName())
- .recordAllRuns()
- .runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen)
- .runBefore(testApp::open)
- .runBefore(device::waitForIdle)
- .run(device::pressHome)
- .run(device::waitForIdle)
- .runAfterAll(testApp::exit)
- .runAfterAll(AutomationUtils::setDefaultWait)
- .repeat(ITERATIONS);
- }
-
- static TransitionBuilder openAppCold(IAppHelper testApp,
- UiDevice device, int beginRotation) {
- return TransitionRunner.newBuilder()
- .withTag("OpenAppCold_" + testApp.getLauncherName()
- + rotationToString(beginRotation))
- .recordAllRuns()
- .runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen)
- .runBefore(device::pressHome)
- .runBeforeAll(() -> setRotation(device, beginRotation))
- .runBefore(testApp::exit)
- .runBefore(device::waitForIdle)
- .run(testApp::open)
- .runAfterAll(testApp::exit)
- .runAfterAll(() -> setRotation(device, Surface.ROTATION_0))
- .repeat(ITERATIONS);
- }
-
- static TransitionBuilder changeAppRotation(IAppHelper testApp, UiDevice
- device, int beginRotation, int endRotation) {
- return TransitionRunner.newBuilder()
- .withTag("changeAppRotation_" + testApp.getLauncherName()
- + rotationToString(beginRotation) + "_" +
- rotationToString(endRotation))
- .recordAllRuns()
- .runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen)
- .runBeforeAll(testApp::open)
- .runBefore(() -> setRotation(device, beginRotation))
- .run(() -> setRotation(device, endRotation))
- .runAfterAll(testApp::exit)
- .runAfterAll(() -> setRotation(device, Surface.ROTATION_0))
- .repeat(ITERATIONS);
- }
-
- static TransitionBuilder changeAppRotation(Intent intent, String intentId, Context context,
- UiDevice
- device, int beginRotation, int endRotation) {
- final String testTag = "changeAppRotation_" + intentId + "_" +
- rotationToString(beginRotation) + "_" + rotationToString(endRotation);
- return TransitionRunner.newBuilder()
- .withTag(testTag)
- .recordAllRuns()
- .runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen)
- .runBeforeAll(() -> {
- context.startActivity(intent);
- device.wait(Until.hasObject(By.pkg(intent.getComponent()
- .getPackageName()).depth(0)), APP_LAUNCH_TIMEOUT);
- }
- )
- .runBefore(() -> setRotation(device, beginRotation))
- .run(() -> setRotation(device, endRotation))
- .runAfterAll(() -> stopPackage(context, intent.getComponent().getPackageName()))
- .runAfterAll(() -> setRotation(device, Surface.ROTATION_0))
- .repeat(ITERATIONS);
- }
-
- static TransitionBuilder appToSplitScreen(IAppHelper testApp, UiDevice device,
- int beginRotation) {
- final String testTag = "appToSplitScreen_" + testApp.getLauncherName() + "_"
- + rotationToString(beginRotation);
- return TransitionRunner.newBuilder()
- .withTag(testTag)
- .recordAllRuns()
- .runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen)
- .runBeforeAll(() -> setRotation(device, beginRotation))
- .runBefore(testApp::open)
- .runBefore(device::waitForIdle)
- .runBefore(() -> sleep(500))
- .run(() -> launchSplitScreen(device))
- .runAfter(() -> exitSplitScreen(device))
- .runAfterAll(testApp::exit)
- .repeat(ITERATIONS);
- }
-
- static TransitionBuilder splitScreenToLauncher(IAppHelper testApp, UiDevice device) {
- return TransitionRunner.newBuilder()
- .withTag("splitScreenToLauncher_" + testApp.getLauncherName())
- .recordAllRuns()
- .runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen)
- .runBefore(testApp::open)
- .runBefore(device::waitForIdle)
- .runBefore(() -> launchSplitScreen(device))
- .run(() -> exitSplitScreen(device))
- .runAfterAll(testApp::exit)
- .repeat(ITERATIONS);
- }
-
- static TransitionBuilder editTextSetFocus(ImeAppHelper testApp, UiDevice device,
- int beginRotation) {
- return TransitionRunner.newBuilder()
- .withTag("editTextSetFocus_" + testApp.getLauncherName()
- + rotationToString(beginRotation))
- .recordAllRuns()
- .runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen)
- .runBefore(device::pressHome)
- .runBefore(() -> setRotation(device, beginRotation))
- .runBefore(testApp::open)
- .run(() -> testApp.clickEditTextWidget(device))
- .runAfterAll(testApp::exit)
- .repeat(ITERATIONS);
- }
-
- static TransitionBuilder resizeSplitScreen(IAppHelper testAppTop, ImeAppHelper testAppBottom,
- UiDevice device, int beginRotation, Rational startRatio, Rational stopRatio) {
- String testTag = "resizeSplitScreen_" + testAppTop.getLauncherName() + "_"
- + testAppBottom.getLauncherName() + "_"
- + startRatio.toString().replace("/", ":") + "_to_"
- + stopRatio.toString().replace("/", ":") + "_"
- + rotationToString(beginRotation);
- return TransitionRunner.newBuilder()
- .withTag(testTag)
- .recordAllRuns()
- .runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen)
- .runBeforeAll(() -> setRotation(device, beginRotation))
- .runBeforeAll(() -> clearRecents(device))
- .runBefore(testAppBottom::open)
- .runBefore(device::pressHome)
- .runBefore(testAppTop::open)
- .runBefore(device::waitForIdle)
- .runBefore(() -> launchSplitScreen(device))
- .runBefore(() -> {
- UiObject2 snapshot = device.findObject(
- By.res(device.getLauncherPackageName(), "snapshot"));
- snapshot.click();
- })
- .runBefore(() -> testAppBottom.clickEditTextWidget(device))
- .runBefore(() -> AutomationUtils.resizeSplitScreen(device, startRatio))
- .run(() -> AutomationUtils.resizeSplitScreen(device, stopRatio))
- .runAfter(() -> exitSplitScreen(device))
- .runAfter(device::pressHome)
- .runAfterAll(testAppTop::exit)
- .runAfterAll(testAppBottom::exit)
- .repeat(ITERATIONS);
- }
-
- static TransitionBuilder editTextLoseFocusToHome(ImeAppHelper testApp, UiDevice device,
- int beginRotation) {
- return TransitionRunner.newBuilder()
- .withTag("editTextLoseFocusToHome_" + testApp.getLauncherName()
- + rotationToString(beginRotation))
- .recordAllRuns()
- .runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen)
- .runBefore(device::pressHome)
- .runBefore(() -> setRotation(device, beginRotation))
- .runBefore(testApp::open)
- .runBefore(() -> testApp.clickEditTextWidget(device))
- .run(device::pressHome)
- .run(device::waitForIdle)
- .runAfterAll(testApp::exit)
- .repeat(ITERATIONS);
- }
-
- static TransitionBuilder editTextLoseFocusToApp(ImeAppHelper testApp, UiDevice device,
- int beginRotation) {
- return TransitionRunner.newBuilder()
- .withTag("editTextLoseFocusToApp_" + testApp.getLauncherName()
- + rotationToString(beginRotation))
- .recordAllRuns()
- .runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen)
- .runBefore(device::pressHome)
- .runBefore(() -> setRotation(device, beginRotation))
- .runBefore(testApp::open)
- .runBefore(() -> testApp.clickEditTextWidget(device))
- .run(device::pressBack)
- .run(device::waitForIdle)
- .runAfterAll(testApp::exit)
- .repeat(ITERATIONS);
- }
-
- static TransitionBuilder enterPipMode(PipAppHelper testApp, UiDevice device,
- int beginRotation) {
- return TransitionRunner.newBuilder()
- .withTag("enterPipMode_" + testApp.getLauncherName()
- + rotationToString(beginRotation))
- .runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen)
- .runBefore(device::pressHome)
- .runBefore(() -> setRotation(device, beginRotation))
- .runBefore(testApp::open)
- .run(() -> testApp.clickEnterPipButton(device))
- .runAfter(() -> testApp.closePipWindow(device))
- .runAfterAll(testApp::exit)
- .repeat(ITERATIONS);
- }
-
- static TransitionBuilder exitPipModeToHome(PipAppHelper testApp, UiDevice device,
- int beginRotation) {
- return TransitionRunner.newBuilder()
- .withTag("exitPipModeToHome_" + testApp.getLauncherName()
- + rotationToString(beginRotation))
- .recordAllRuns()
- .runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen)
- .runBefore(device::pressHome)
- .runBefore(() -> setRotation(device, beginRotation))
- .runBefore(testApp::open)
- .run(() -> testApp.clickEnterPipButton(device))
- .run(() -> testApp.closePipWindow(device))
- .run(device::waitForIdle)
- .run(testApp::exit)
- .repeat(ITERATIONS);
- }
-
- static TransitionBuilder exitPipModeToApp(PipAppHelper testApp, UiDevice device,
- int beginRotation) {
- return TransitionRunner.newBuilder()
- .withTag("exitPipModeToApp_" + testApp.getLauncherName()
- + rotationToString(beginRotation))
- .recordAllRuns()
- .runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen)
- .run(device::pressHome)
- .run(() -> setRotation(device, beginRotation))
- .run(testApp::open)
- .run(() -> testApp.clickEnterPipButton(device))
- .run(() -> expandPipWindow(device))
- .run(device::waitForIdle)
- .run(testApp::exit)
- .repeat(ITERATIONS);
- }
-}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/DebugTest.java b/tests/FlickerTests/src/com/android/server/wm/flicker/DebugTest.java
deleted file mode 100644
index 666a0b9be779..000000000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/DebugTest.java
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- * Copyright (C) 2018 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.wm.flicker;
-
-import android.platform.helpers.IAppHelper;
-import android.support.test.uiautomator.UiDevice;
-import android.util.Rational;
-import android.view.Surface;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.LargeTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.server.wm.flicker.helpers.ImeAppHelper;
-import com.android.server.wm.flicker.helpers.PipAppHelper;
-
-import org.junit.FixMethodOrder;
-import org.junit.Ignore;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.MethodSorters;
-
-/**
- * Tests to help debug individual transitions, capture video recordings and create test cases.
- */
-@LargeTest
-@Ignore("Used for debugging transitions used in FlickerTests.")
-@RunWith(AndroidJUnit4.class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-public class DebugTest {
- private IAppHelper testApp = new StandardAppHelper(InstrumentationRegistry.getInstrumentation(),
- "com.android.server.wm.flicker.testapp", "SimpleApp");
- private UiDevice uiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
-
- /**
- * atest FlickerTests:DebugTest#openAppCold
- */
- @Test
- public void openAppCold() {
- CommonTransitions.openAppCold(testApp, uiDevice, Surface.ROTATION_0)
- .recordAllRuns().build().run();
- }
-
- /**
- * atest FlickerTests:DebugTest#openAppWarm
- */
- @Test
- public void openAppWarm() {
- CommonTransitions.openAppWarm(testApp, uiDevice, Surface.ROTATION_0)
- .recordAllRuns().build().run();
- }
-
- /**
- * atest FlickerTests:DebugTest#changeOrientationFromNaturalToLeft
- */
- @Test
- public void changeOrientationFromNaturalToLeft() {
- CommonTransitions.changeAppRotation(testApp, uiDevice, Surface.ROTATION_0,
- Surface.ROTATION_270).recordAllRuns().build().run();
- }
-
- /**
- * atest FlickerTests:DebugTest#closeAppWithBackKey
- */
- @Test
- public void closeAppWithBackKey() {
- CommonTransitions.closeAppWithBackKey(testApp, uiDevice).recordAllRuns().build().run();
- }
-
- /**
- * atest FlickerTests:DebugTest#closeAppWithHomeKey
- */
- @Test
- public void closeAppWithHomeKey() {
- CommonTransitions.closeAppWithHomeKey(testApp, uiDevice).recordAllRuns().build().run();
- }
-
- /**
- * atest FlickerTests:DebugTest#openAppToSplitScreen
- */
- @Test
- public void openAppToSplitScreen() {
- CommonTransitions.appToSplitScreen(testApp, uiDevice,
- Surface.ROTATION_0).includeJankyRuns().recordAllRuns()
- .build().run();
- }
-
- /**
- * atest FlickerTests:DebugTest#splitScreenToLauncher
- */
- @Test
- public void splitScreenToLauncher() {
- CommonTransitions.splitScreenToLauncher(testApp,
- uiDevice).includeJankyRuns().recordAllRuns()
- .build().run();
- }
-
- /**
- * atest FlickerTests:DebugTest#resizeSplitScreen
- */
- @Test
- public void resizeSplitScreen() {
- ImeAppHelper bottomApp = new ImeAppHelper(InstrumentationRegistry.getInstrumentation());
- CommonTransitions.resizeSplitScreen(testApp, bottomApp, uiDevice, Surface.ROTATION_0,
- new Rational(1, 3), new Rational(2, 3))
- .includeJankyRuns().build().run();
- }
-
- // IME tests
-
- /**
- * atest FlickerTests:DebugTest#editTextSetFocus
- */
- @Test
- public void editTextSetFocus() {
- ImeAppHelper testApp = new ImeAppHelper(InstrumentationRegistry.getInstrumentation());
- CommonTransitions.editTextSetFocus(testApp, uiDevice, Surface.ROTATION_0)
- .includeJankyRuns()
- .build().run();
- }
-
- /**
- * atest FlickerTests:DebugTest#editTextLoseFocusToHome
- */
- @Test
- public void editTextLoseFocusToHome() {
- ImeAppHelper testApp = new ImeAppHelper(InstrumentationRegistry.getInstrumentation());
- CommonTransitions.editTextLoseFocusToHome(testApp, uiDevice, Surface.ROTATION_0)
- .includeJankyRuns()
- .build().run();
- }
-
- /**
- * atest FlickerTests:DebugTest#editTextLoseFocusToApp
- */
- @Test
- public void editTextLoseFocusToApp() {
- ImeAppHelper testApp = new ImeAppHelper(InstrumentationRegistry.getInstrumentation());
- CommonTransitions.editTextLoseFocusToHome(testApp, uiDevice, Surface.ROTATION_0)
- .includeJankyRuns()
- .build().run();
- }
-
- // PIP tests
-
- /**
- * atest FlickerTests:DebugTest#enterPipMode
- */
- @Test
- public void enterPipMode() {
- PipAppHelper testApp = new PipAppHelper(InstrumentationRegistry.getInstrumentation());
- CommonTransitions.enterPipMode(testApp, uiDevice, Surface.ROTATION_0).includeJankyRuns()
- .build().run();
- }
-
- /**
- * atest FlickerTests:DebugTest#exitPipModeToHome
- */
- @Test
- public void exitPipModeToHome() {
- PipAppHelper testApp = new PipAppHelper(InstrumentationRegistry.getInstrumentation());
- CommonTransitions.exitPipModeToHome(testApp, uiDevice, Surface.ROTATION_0)
- .includeJankyRuns()
- .build().run();
- }
-
- /**
- * atest FlickerTests:DebugTest#exitPipModeToApp
- */
- @Test
- public void exitPipModeToApp() {
- PipAppHelper testApp = new PipAppHelper(InstrumentationRegistry.getInstrumentation());
- CommonTransitions.exitPipModeToApp(testApp, uiDevice, Surface.ROTATION_0).includeJankyRuns()
- .build().run();
- }
-}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/FlickerTestBase.java b/tests/FlickerTests/src/com/android/server/wm/flicker/FlickerTestBase.java
deleted file mode 100644
index 4578fa3f0b9a..000000000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/FlickerTestBase.java
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * Copyright (C) 2018 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.wm.flicker;
-
-import static androidx.test.InstrumentationRegistry.getInstrumentation;
-
-import static com.android.server.wm.flicker.helpers.AutomationUtils.setDefaultWait;
-
-import static com.google.common.truth.Truth.assertWithMessage;
-
-import android.os.Bundle;
-import android.platform.helpers.IAppHelper;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.uiautomator.UiDevice;
-import android.util.Log;
-
-import com.android.server.wm.flicker.TransitionRunner.TransitionResult;
-
-import org.junit.After;
-import org.junit.AfterClass;
-import org.junit.Before;
-
-import java.util.HashMap;
-import java.util.List;
-import java.util.function.Consumer;
-
-/**
- * Base class of all Flicker test that performs common functions for all flicker tests:
- * <p>
- * - Caches transitions so that a transition is run once and the transition results are used by
- * tests multiple times. This is needed for parameterized tests which call the BeforeClass methods
- * multiple times.
- * - Keeps track of all test artifacts and deletes ones which do not need to be reviewed.
- * - Fails tests if results are not available for any test due to jank.
- */
-public class FlickerTestBase {
- public static final String TAG = "FLICKER";
- static final String NAVIGATION_BAR_WINDOW_TITLE = "NavigationBar";
- static final String STATUS_BAR_WINDOW_TITLE = "StatusBar";
- static final String DOCKED_STACK_DIVIDER = "DockedStackDivider";
- private static HashMap<String, List<TransitionResult>> transitionResults =
- new HashMap<>();
- IAppHelper mTestApp;
- UiDevice mUiDevice;
- private List<TransitionResult> mResults;
- private TransitionResult mLastResult = null;
-
- @Before
- public void setUp() {
- InstrumentationRegistry.registerInstance(getInstrumentation(), new Bundle());
- mUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
- }
-
- /**
- * Teardown any system settings and clean up test artifacts from the file system.
- *
- * Note: test artifacts for failed tests will remain on the device.
- */
- @AfterClass
- public static void teardown() {
- setDefaultWait();
- transitionResults.values().stream()
- .flatMap(List::stream)
- .forEach(result -> {
- if (result.canDelete()) {
- result.delete();
- } else {
- if (result.layersTraceExists()) {
- Log.e(TAG, "Layers trace saved to " + result.getLayersTracePath());
- }
- if (result.windowManagerTraceExists()) {
- Log.e(TAG, "WindowManager trace saved to " + result
- .getWindowManagerTracePath
- ());
- }
- if (result.screenCaptureVideoExists()) {
- Log.e(TAG, "Screen capture video saved to " + result
- .screenCaptureVideoPath().toString());
- }
- }
- });
- }
-
- /**
- * Runs a transition, returns a cached result if the transition has run before.
- */
- void run(TransitionRunner transition) {
- if (transitionResults.containsKey(transition.getTestTag())) {
- mResults = transitionResults.get(transition.getTestTag());
- return;
- }
- mResults = transition.run().getResults();
- /* Fail if we don't have any results due to jank */
- assertWithMessage("No results to test because all transition runs were invalid because "
- + "of Jank").that(mResults).isNotEmpty();
- transitionResults.put(transition.getTestTag(), mResults);
- }
-
- /**
- * Runs a transition, returns a cached result if the transition has run before.
- */
- void runTransition(TransitionRunner transition) {
- run(transition);
- }
-
- /**
- * Goes through a list of transition results and checks assertions on each result.
- */
- void checkResults(Consumer<TransitionResult> assertion) {
-
- for (TransitionResult result : mResults) {
- mLastResult = result;
- assertion.accept(result);
- }
- mLastResult = null;
- }
-
- /**
- * Kludge to mark a file for saving. If {@code checkResults} fails, the last result is not
- * cleared. This indicates the assertion failed for the result, so mark it for saving.
- */
- @After
- public void markArtifactsForSaving() {
- if (mLastResult != null) {
- mLastResult.flagForSaving();
- }
- }
-}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/NonRotationTestBase.java b/tests/FlickerTests/src/com/android/server/wm/flicker/NonRotationTestBase.java
deleted file mode 100644
index 54941dc0f585..000000000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/NonRotationTestBase.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright (C) 2019 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.wm.flicker;
-
-import static android.view.Surface.rotationToString;
-
-import static com.android.server.wm.flicker.WindowUtils.getDisplayBounds;
-
-import android.graphics.Rect;
-import android.view.Surface;
-
-import androidx.test.filters.FlakyTest;
-
-import org.junit.Ignore;
-import org.junit.Test;
-import org.junit.runners.Parameterized.Parameters;
-
-import java.util.ArrayList;
-import java.util.Collection;
-
-public abstract class NonRotationTestBase extends FlickerTestBase {
-
- int mBeginRotation;
-
- public NonRotationTestBase(String beginRotationName, int beginRotation) {
- this.mBeginRotation = beginRotation;
- }
-
- @Parameters(name = "{0}")
- public static Collection<Object[]> getParams() {
- int[] supportedRotations =
- {Surface.ROTATION_0, Surface.ROTATION_90};
- Collection<Object[]> params = new ArrayList<>();
-
- for (int begin : supportedRotations) {
- params.add(new Object[]{rotationToString(begin), begin});
- }
-
- return params;
- }
-
- @FlakyTest(bugId = 141361128)
- @Ignore("Waiting bug feedback")
- @Test
- public void checkCoveredRegion_noUncoveredRegions() {
- Rect displayBounds = getDisplayBounds(mBeginRotation);
- checkResults(result -> LayersTraceSubject.assertThat(result).coversRegion(
- displayBounds).forAllEntries());
- }
-
- @FlakyTest(bugId = 141361128)
- @Ignore("Waiting bug feedback")
- @Test
- public void checkVisibility_navBarLayerIsAlwaysVisible() {
- checkResults(result -> LayersTraceSubject.assertThat(result)
- .showsLayer(NAVIGATION_BAR_WINDOW_TITLE).forAllEntries());
- }
-
- @FlakyTest(bugId = 141361128)
- @Ignore("Waiting bug feedback")
- @Test
- public void checkVisibility_statusBarLayerIsAlwaysVisible() {
- checkResults(result -> LayersTraceSubject.assertThat(result)
- .showsLayer(STATUS_BAR_WINDOW_TITLE).forAllEntries());
- }
-}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/OpenAppColdTest.java b/tests/FlickerTests/src/com/android/server/wm/flicker/OpenAppColdTest.java
deleted file mode 100644
index 2981ff9aefe6..000000000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/OpenAppColdTest.java
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright (C) 2018 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.wm.flicker;
-
-import static com.android.server.wm.flicker.CommonTransitions.openAppCold;
-import static com.android.server.wm.flicker.WmTraceSubject.assertThat;
-
-import android.view.Surface;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.FlakyTest;
-import androidx.test.filters.LargeTest;
-
-import org.junit.Before;
-import org.junit.FixMethodOrder;
-import org.junit.Ignore;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.MethodSorters;
-import org.junit.runners.Parameterized;
-
-/**
- * Test cold launch app from launcher.
- * To run this test: {@code atest FlickerTests:OpenAppColdTest}
- */
-@LargeTest
-@RunWith(Parameterized.class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-public class OpenAppColdTest extends NonRotationTestBase {
-
- public OpenAppColdTest(String beginRotationName, int beginRotation) {
- super(beginRotationName, beginRotation);
-
- this.mTestApp = new StandardAppHelper(InstrumentationRegistry.getInstrumentation(),
- "com.android.server.wm.flicker.testapp", "SimpleApp");
- }
-
- @Before
- public void runTransition() {
- run(openAppCold(mTestApp, mUiDevice, mBeginRotation)
- .includeJankyRuns().build());
- }
-
- @Test
- public void checkVisibility_wallpaperWindowBecomesInvisible() {
- checkResults(result -> assertThat(result)
- .showsBelowAppWindow("Wallpaper")
- .then()
- .hidesBelowAppWindow("Wallpaper")
- .forAllEntries());
- }
-
- @FlakyTest(bugId = 140855415)
- @Ignore("Waiting bug feedback")
- @Test
- public void checkZOrder_appWindowReplacesLauncherAsTopWindow() {
- checkResults(result -> assertThat(result)
- .showsAppWindowOnTop(
- "com.android.launcher3/.Launcher")
- .then()
- .showsAppWindowOnTop(mTestApp.getPackage())
- .forAllEntries());
- }
-
- @Test
- public void checkVisibility_wallpaperLayerBecomesInvisible() {
- if (mBeginRotation == Surface.ROTATION_0) {
- checkResults(result -> LayersTraceSubject.assertThat(result)
- .showsLayer("Wallpaper")
- .then()
- .replaceVisibleLayer("Wallpaper", mTestApp.getPackage())
- .forAllEntries());
- } else {
- checkResults(result -> LayersTraceSubject.assertThat(result)
- .showsLayer("Wallpaper")
- .then()
- .replaceVisibleLayer("Wallpaper", "Screenshot")
- .then()
- .showsLayer(mTestApp.getPackage())
- .forAllEntries());
- }
- }
-}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/OpenAppToSplitScreenTest.java b/tests/FlickerTests/src/com/android/server/wm/flicker/OpenAppToSplitScreenTest.java
deleted file mode 100644
index ddead6d321a0..000000000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/OpenAppToSplitScreenTest.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright (C) 2018 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.wm.flicker;
-
-import static com.android.server.wm.flicker.CommonTransitions.appToSplitScreen;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.LargeTest;
-
-import org.junit.Before;
-import org.junit.FixMethodOrder;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.MethodSorters;
-import org.junit.runners.Parameterized;
-
-/**
- * Test open app to split screen.
- * To run this test: {@code atest FlickerTests:OpenAppToSplitScreenTest}
- */
-@LargeTest
-@RunWith(Parameterized.class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-public class OpenAppToSplitScreenTest extends NonRotationTestBase {
-
- public OpenAppToSplitScreenTest(String beginRotationName, int beginRotation) {
- super(beginRotationName, beginRotation);
-
- this.mTestApp = new StandardAppHelper(InstrumentationRegistry.getInstrumentation(),
- "com.android.server.wm.flicker.testapp", "SimpleApp");
- }
-
- @Before
- public void runTransition() {
- super.runTransition(appToSplitScreen(mTestApp, mUiDevice, mBeginRotation)
- .includeJankyRuns()
- .build());
- }
-
- @Test
- public void checkVisibility_navBarWindowIsAlwaysVisible() {
- checkResults(result -> WmTraceSubject.assertThat(result)
- .showsAboveAppWindow(NAVIGATION_BAR_WINDOW_TITLE).forAllEntries());
- }
-
- @Test
- public void checkVisibility_statusBarWindowIsAlwaysVisible() {
- checkResults(result -> WmTraceSubject.assertThat(result)
- .showsAboveAppWindow(STATUS_BAR_WINDOW_TITLE).forAllEntries());
- }
-
- @Test
- public void checkVisibility_dividerWindowBecomesVisible() {
- checkResults(result -> WmTraceSubject.assertThat(result)
- .hidesAboveAppWindow(DOCKED_STACK_DIVIDER)
- .then()
- .showsAboveAppWindow(DOCKED_STACK_DIVIDER)
- .forAllEntries());
- }
-
- @Test
- public void checkVisibility_dividerLayerBecomesVisible() {
- checkResults(result -> LayersTraceSubject.assertThat(result)
- .hidesLayer(DOCKED_STACK_DIVIDER)
- .then()
- .showsLayer(DOCKED_STACK_DIVIDER)
- .forAllEntries());
- }
-}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/OpenAppWarmTest.java b/tests/FlickerTests/src/com/android/server/wm/flicker/OpenAppWarmTest.java
deleted file mode 100644
index bb684d19d645..000000000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/OpenAppWarmTest.java
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright (C) 2018 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.wm.flicker;
-
-import static com.android.server.wm.flicker.CommonTransitions.openAppWarm;
-import static com.android.server.wm.flicker.WmTraceSubject.assertThat;
-
-import android.view.Surface;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.FlakyTest;
-import androidx.test.filters.LargeTest;
-
-import org.junit.Before;
-import org.junit.FixMethodOrder;
-import org.junit.Ignore;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.MethodSorters;
-import org.junit.runners.Parameterized;
-
-/**
- * Test warm launch app.
- * To run this test: {@code atest FlickerTests:OpenAppWarmTest}
- */
-@LargeTest
-@RunWith(Parameterized.class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-public class OpenAppWarmTest extends NonRotationTestBase {
-
- public OpenAppWarmTest(String beginRotationName, int beginRotation) {
- super(beginRotationName, beginRotation);
-
- this.mTestApp = new StandardAppHelper(InstrumentationRegistry.getInstrumentation(),
- "com.android.server.wm.flicker.testapp", "SimpleApp");
- }
-
- @Before
- public void runTransition() {
- super.runTransition(openAppWarm(mTestApp, mUiDevice, mBeginRotation)
- .includeJankyRuns().build());
- }
-
- @Test
- public void checkVisibility_wallpaperBecomesInvisible() {
- checkResults(result -> assertThat(result)
- .showsBelowAppWindow("Wallpaper")
- .then()
- .hidesBelowAppWindow("Wallpaper")
- .forAllEntries());
- }
-
- @FlakyTest(bugId = 140855415)
- @Ignore("Waiting bug feedback")
- @Test
- public void checkZOrder_appWindowReplacesLauncherAsTopWindow() {
- checkResults(result -> assertThat(result)
- .showsAppWindowOnTop(
- "com.android.launcher3/.Launcher")
- .then()
- .showsAppWindowOnTop(mTestApp.getPackage())
- .forAllEntries());
- }
-
- @Test
- public void checkVisibility_wallpaperLayerBecomesInvisible() {
- if (mBeginRotation == Surface.ROTATION_0) {
- checkResults(result -> LayersTraceSubject.assertThat(result)
- .showsLayer("Wallpaper")
- .then()
- .replaceVisibleLayer("Wallpaper", mTestApp.getPackage())
- .forAllEntries());
- } else {
- checkResults(result -> LayersTraceSubject.assertThat(result)
- .showsLayer("Wallpaper")
- .then()
- .replaceVisibleLayer("Wallpaper", "Screenshot")
- .then()
- .showsLayer(mTestApp.getPackage())
- .forAllEntries());
- }
- }
-}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/OpenImeWindowTest.java b/tests/FlickerTests/src/com/android/server/wm/flicker/OpenImeWindowTest.java
deleted file mode 100644
index 91d4a056d8fb..000000000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/OpenImeWindowTest.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (C) 2018 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.wm.flicker;
-
-import static com.android.server.wm.flicker.CommonTransitions.editTextSetFocus;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.LargeTest;
-
-import com.android.server.wm.flicker.helpers.ImeAppHelper;
-
-import org.junit.Before;
-import org.junit.FixMethodOrder;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.MethodSorters;
-import org.junit.runners.Parameterized;
-
-/**
- * Test IME window opening transitions.
- * To run this test: {@code atest FlickerTests:OpenImeWindowTest}
- */
-@LargeTest
-@RunWith(Parameterized.class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-public class OpenImeWindowTest extends NonRotationTestBase {
-
- private static final String IME_WINDOW_TITLE = "InputMethod";
-
- public OpenImeWindowTest(String beginRotationName, int beginRotation) {
- super(beginRotationName, beginRotation);
-
- mTestApp = new ImeAppHelper(InstrumentationRegistry.getInstrumentation());
- }
-
- @Before
- public void runTransition() {
- run(editTextSetFocus((ImeAppHelper) mTestApp, mUiDevice, mBeginRotation)
- .includeJankyRuns().build());
- }
-
- @Test
- public void checkVisibility_imeWindowBecomesVisible() {
- checkResults(result -> WmTraceSubject.assertThat(result)
- .hidesImeWindow(IME_WINDOW_TITLE)
- .then()
- .showsImeWindow(IME_WINDOW_TITLE)
- .forAllEntries());
- }
-
- @Test
- public void checkVisibility_imeLayerBecomesVisible() {
- checkResults(result -> LayersTraceSubject.assertThat(result)
- .hidesLayer(IME_WINDOW_TITLE)
- .then()
- .showsLayer(IME_WINDOW_TITLE)
- .forAllEntries());
- }
-}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/PipToAppTest.java b/tests/FlickerTests/src/com/android/server/wm/flicker/PipToAppTest.java
deleted file mode 100644
index 85706bd14c5e..000000000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/PipToAppTest.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright (C) 2019 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.wm.flicker;
-
-import static com.android.server.wm.flicker.CommonTransitions.exitPipModeToApp;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.LargeTest;
-
-import com.android.server.wm.flicker.helpers.PipAppHelper;
-
-import org.junit.Before;
-import org.junit.FixMethodOrder;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.MethodSorters;
-import org.junit.runners.Parameterized;
-
-/**
- * Test Pip launch.
- * To run this test: {@code atest FlickerTests:PipToAppTest}
- */
-@LargeTest
-@RunWith(Parameterized.class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-public class PipToAppTest extends NonRotationTestBase {
-
- static final String sPipWindowTitle = "PipMenuActivity";
-
- public PipToAppTest(String beginRotationName, int beginRotation) {
- super(beginRotationName, beginRotation);
-
- this.mTestApp = new PipAppHelper(InstrumentationRegistry.getInstrumentation());
- }
-
- @Before
- public void runTransition() {
- run(exitPipModeToApp((PipAppHelper) mTestApp, mUiDevice, mBeginRotation)
- .includeJankyRuns().build());
- }
-
- @Test
- public void checkVisibility_pipWindowBecomesVisible() {
- checkResults(result -> WmTraceSubject.assertThat(result)
- .skipUntilFirstAssertion()
- .showsAppWindowOnTop(sPipWindowTitle)
- .then()
- .hidesAppWindow(sPipWindowTitle)
- .forAllEntries());
- }
-
- @Test
- public void checkVisibility_pipLayerBecomesVisible() {
- checkResults(result -> LayersTraceSubject.assertThat(result)
- .skipUntilFirstAssertion()
- .showsLayer(sPipWindowTitle)
- .then()
- .hidesLayer(sPipWindowTitle)
- .forAllEntries());
- }
-
- @Test
- public void checkVisibility_backgroundWindowVisibleBehindPipLayer() {
- checkResults(result -> WmTraceSubject.assertThat(result)
- .skipUntilFirstAssertion()
- .showsAppWindowOnTop(sPipWindowTitle)
- .then()
- .showsBelowAppWindow("Wallpaper")
- .then()
- .showsAppWindowOnTop(mTestApp.getPackage())
- .then()
- .hidesAppWindowOnTop(mTestApp.getPackage())
- .forAllEntries());
- }
-}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/PipToHomeTest.java b/tests/FlickerTests/src/com/android/server/wm/flicker/PipToHomeTest.java
deleted file mode 100644
index ef856dc52167..000000000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/PipToHomeTest.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright (C) 2019 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.wm.flicker;
-
-import static com.android.server.wm.flicker.CommonTransitions.exitPipModeToHome;
-
-import android.view.Surface;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.LargeTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.server.wm.flicker.helpers.PipAppHelper;
-
-import org.junit.Before;
-import org.junit.FixMethodOrder;
-import org.junit.Ignore;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.MethodSorters;
-
-/**
- * Test Pip launch.
- * To run this test: {@code atest FlickerTests:PipToHomeTest}
- */
-@LargeTest
-@RunWith(AndroidJUnit4.class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-public class PipToHomeTest extends FlickerTestBase {
-
- static final String sPipWindowTitle = "PipActivity";
-
- // public PipToHomeTest(String beginRotationName, int beginRotation) {
- public PipToHomeTest() {
- // super(beginRotationName, beginRotation);
-
- this.mTestApp = new PipAppHelper(InstrumentationRegistry.getInstrumentation());
- }
-
- @Before
- public void runTransition() {
- // run(exitPipModeToHome((PipAppHelper) mTestApp, mUiDevice, mBeginRotation)
- run(exitPipModeToHome((PipAppHelper) mTestApp, mUiDevice, Surface.ROTATION_0)
- .includeJankyRuns().build());
- }
-
- @Ignore
- @Test
- public void checkVisibility_pipWindowBecomesVisible() {
- checkResults(result -> WmTraceSubject.assertThat(result)
- .skipUntilFirstAssertion()
- .showsAppWindowOnTop(sPipWindowTitle)
- .then()
- .hidesAppWindow(sPipWindowTitle)
- .forAllEntries());
- }
-
- @Test
- public void checkVisibility_pipLayerBecomesVisible() {
- checkResults(result -> LayersTraceSubject.assertThat(result)
- .skipUntilFirstAssertion()
- .showsLayer(sPipWindowTitle)
- .then()
- .hidesLayer(sPipWindowTitle)
- .forAllEntries());
- }
-
- @Ignore
- @Test
- public void checkVisibility_backgroundWindowVisibleBehindPipLayer() {
- checkResults(result -> WmTraceSubject.assertThat(result)
- .showsAppWindowOnTop(sPipWindowTitle)
- .then()
- .showsBelowAppWindow("Wallpaper")
- .then()
- .showsAppWindowOnTop("Wallpaper")
- .forAllEntries());
- }
-}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ResizeSplitScreenTest.java b/tests/FlickerTests/src/com/android/server/wm/flicker/ResizeSplitScreenTest.java
deleted file mode 100644
index e36701be0cad..000000000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ResizeSplitScreenTest.java
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- * Copyright (C) 2018 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.wm.flicker;
-
-import static com.android.server.wm.flicker.CommonTransitions.resizeSplitScreen;
-import static com.android.server.wm.flicker.WindowUtils.getDisplayBounds;
-import static com.android.server.wm.flicker.WindowUtils.getDockedStackDividerInset;
-import static com.android.server.wm.flicker.WindowUtils.getNavigationBarHeight;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.graphics.Rect;
-import android.util.Rational;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.FlakyTest;
-import androidx.test.filters.LargeTest;
-
-import com.android.server.wm.flicker.helpers.ImeAppHelper;
-
-import org.junit.Before;
-import org.junit.FixMethodOrder;
-import org.junit.Ignore;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.MethodSorters;
-import org.junit.runners.Parameterized;
-
-/**
- * Test split screen resizing window transitions.
- * To run this test: {@code atest FlickerTests:ResizeSplitScreenTest}
- */
-@LargeTest
-@RunWith(Parameterized.class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@FlakyTest(bugId = 140854698)
-@Ignore("Waiting bug feedback")
-public class ResizeSplitScreenTest extends NonRotationTestBase {
-
- private static String sSimpleActivity = "SimpleActivity";
- private static String sImeActivity = "ImeActivity";
-
- public ResizeSplitScreenTest(String beginRotationName, int beginRotation) {
- super(beginRotationName, beginRotation);
-
- this.mTestApp = new StandardAppHelper(InstrumentationRegistry.getInstrumentation(),
- "com.android.server.wm.flicker.testapp", "SimpleApp");
- }
-
- @Before
- public void runTransition() {
- ImeAppHelper bottomApp = new ImeAppHelper(InstrumentationRegistry.getInstrumentation());
- run(resizeSplitScreen(mTestApp, bottomApp, mUiDevice, mBeginRotation,
- new Rational(1, 3), new Rational(2, 3))
- .includeJankyRuns().build());
- }
-
- @Test
- public void checkVisibility_topAppLayerIsAlwaysVisible() {
- checkResults(result -> LayersTraceSubject.assertThat(result)
- .showsLayer(sSimpleActivity)
- .forAllEntries());
- }
-
- @Test
- public void checkVisibility_bottomAppLayerIsAlwaysVisible() {
- checkResults(result -> LayersTraceSubject.assertThat(result)
- .showsLayer(sImeActivity)
- .forAllEntries());
- }
-
- @Test
- public void checkVisibility_dividerLayerIsAlwaysVisible() {
- checkResults(result -> LayersTraceSubject.assertThat(result)
- .showsLayer(DOCKED_STACK_DIVIDER)
- .forAllEntries());
- }
-
- @Test
- public void checkPosition_appsStartingBounds() {
- Rect displayBounds = getDisplayBounds();
- checkResults(result -> {
- LayersTrace entries = LayersTrace.parseFrom(result.getLayersTrace(),
- result.getLayersTracePath(), result.getLayersTraceChecksum());
-
- assertThat(entries.getEntries()).isNotEmpty();
- Rect startingDividerBounds = entries.getEntries().get(0).getVisibleBounds
- (DOCKED_STACK_DIVIDER);
-
- Rect startingTopAppBounds = new Rect(0, 0, startingDividerBounds.right,
- startingDividerBounds.top + getDockedStackDividerInset());
-
- Rect startingBottomAppBounds = new Rect(0,
- startingDividerBounds.bottom - getDockedStackDividerInset(),
- displayBounds.right,
- displayBounds.bottom - getNavigationBarHeight());
-
- LayersTraceSubject.assertThat(result)
- .hasVisibleRegion("SimpleActivity", startingTopAppBounds)
- .inTheBeginning();
-
- LayersTraceSubject.assertThat(result)
- .hasVisibleRegion("ImeActivity", startingBottomAppBounds)
- .inTheBeginning();
- });
- }
-
- @Test
- public void checkPosition_appsEndingBounds() {
- Rect displayBounds = getDisplayBounds();
- checkResults(result -> {
- LayersTrace entries = LayersTrace.parseFrom(result.getLayersTrace(),
- result.getLayersTracePath(), result.getLayersTraceChecksum());
-
- assertThat(entries.getEntries()).isNotEmpty();
- Rect endingDividerBounds = entries.getEntries().get(
- entries.getEntries().size() - 1).getVisibleBounds(
- DOCKED_STACK_DIVIDER);
-
- Rect startingTopAppBounds = new Rect(0, 0, endingDividerBounds.right,
- endingDividerBounds.top + getDockedStackDividerInset());
-
- Rect startingBottomAppBounds = new Rect(0,
- endingDividerBounds.bottom - getDockedStackDividerInset(),
- displayBounds.right,
- displayBounds.bottom - getNavigationBarHeight());
-
- LayersTraceSubject.assertThat(result)
- .hasVisibleRegion(sSimpleActivity, startingTopAppBounds)
- .atTheEnd();
-
- LayersTraceSubject.assertThat(result)
- .hasVisibleRegion(sImeActivity, startingBottomAppBounds)
- .atTheEnd();
- });
- }
-
- @Test
- public void checkVisibility_navBarWindowIsAlwaysVisible() {
- checkResults(result -> WmTraceSubject.assertThat(result)
- .showsAboveAppWindow(NAVIGATION_BAR_WINDOW_TITLE)
- .forAllEntries());
- }
-
- @Test
- public void checkVisibility_statusBarWindowIsAlwaysVisible() {
- checkResults(result -> WmTraceSubject.assertThat(result)
- .showsAboveAppWindow(STATUS_BAR_WINDOW_TITLE)
- .forAllEntries());
- }
-
- @Test
- public void checkVisibility_topAppWindowIsAlwaysVisible() {
- checkResults(result -> WmTraceSubject.assertThat(result)
- .showsAppWindow(sSimpleActivity)
- .forAllEntries());
- }
-
- @Test
- public void checkVisibility_bottomAppWindowIsAlwaysVisible() {
- checkResults(result -> WmTraceSubject.assertThat(result)
- .showsAppWindow(sImeActivity)
- .forAllEntries());
- }
-
- @Test
- public void checkVisibility_dividerWindowIsAlwaysVisible() {
- checkResults(result -> WmTraceSubject.assertThat(result)
- .showsAboveAppWindow(DOCKED_STACK_DIVIDER)
- .forAllEntries());
- }
-}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/SeamlessAppRotationTest.java b/tests/FlickerTests/src/com/android/server/wm/flicker/SeamlessAppRotationTest.java
deleted file mode 100644
index 37d7c4ca2b46..000000000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/SeamlessAppRotationTest.java
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * Copyright (C) 2018 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.wm.flicker;
-
-import static android.view.Surface.rotationToString;
-
-import static com.android.server.wm.flicker.CommonTransitions.changeAppRotation;
-import static com.android.server.wm.flicker.WindowUtils.getAppPosition;
-import static com.android.server.wm.flicker.WindowUtils.getDisplayBounds;
-import static com.android.server.wm.flicker.WindowUtils.getNavigationBarPosition;
-import static com.android.server.wm.flicker.testapp.ActivityOptions.EXTRA_STARVE_UI_THREAD;
-import static com.android.server.wm.flicker.testapp.ActivityOptions.SEAMLESS_ACTIVITY_COMPONENT_NAME;
-
-import android.content.Intent;
-import android.graphics.Rect;
-import android.view.Surface;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.FlakyTest;
-import androidx.test.filters.LargeTest;
-
-import org.junit.Before;
-import org.junit.FixMethodOrder;
-import org.junit.Ignore;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.MethodSorters;
-import org.junit.runners.Parameterized;
-import org.junit.runners.Parameterized.Parameters;
-
-import java.util.ArrayList;
-import java.util.Collection;
-
-/**
- * Cycle through supported app rotations using seamless rotations.
- * To run this test: {@code atest FlickerTests:SeamlessAppRotationTest}
- */
-@LargeTest
-@RunWith(Parameterized.class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@FlakyTest(bugId = 147659548)
-@Ignore("Waiting bug feedback")
-public class SeamlessAppRotationTest extends FlickerTestBase {
- private int mBeginRotation;
- private int mEndRotation;
- private Intent mIntent;
-
- public SeamlessAppRotationTest(String testId, Intent intent, int beginRotation,
- int endRotation) {
- this.mIntent = intent;
- this.mBeginRotation = beginRotation;
- this.mEndRotation = endRotation;
- }
-
- @Parameters(name = "{0}")
- public static Collection<Object[]> getParams() {
- int[] supportedRotations =
- {Surface.ROTATION_0, Surface.ROTATION_90};
- Collection<Object[]> params = new ArrayList<>();
-
- ArrayList<Intent> testIntents = new ArrayList<>();
-
- // launch test activity that supports seamless rotation
- Intent intent = new Intent(Intent.ACTION_MAIN);
- intent.setComponent(SEAMLESS_ACTIVITY_COMPONENT_NAME);
- testIntents.add(intent);
-
- // launch test activity that supports seamless rotation with a busy UI thread to miss frames
- // when the app is asked to redraw
- intent = new Intent(intent);
- intent.putExtra(EXTRA_STARVE_UI_THREAD, true);
- testIntents.add(intent);
-
- for (Intent testIntent : testIntents) {
- for (int begin : supportedRotations) {
- for (int end : supportedRotations) {
- if (begin != end) {
- String testId = rotationToString(begin) + "_" + rotationToString(end);
- if (testIntent.getExtras() != null &&
- testIntent.getExtras().getBoolean(EXTRA_STARVE_UI_THREAD)) {
- testId += "_" + "BUSY_UI_THREAD";
- }
- params.add(new Object[]{testId, testIntent, begin, end});
- }
- }
- }
- }
- return params;
- }
-
- @Before
- public void runTransition() {
- String intentId = "";
- if (mIntent.getExtras() != null &&
- mIntent.getExtras().getBoolean(EXTRA_STARVE_UI_THREAD)) {
- intentId = "BUSY_UI_THREAD";
- }
-
- super.runTransition(
- changeAppRotation(mIntent, intentId, InstrumentationRegistry.getContext(),
- mUiDevice, mBeginRotation, mEndRotation).build());
- }
-
- @Test
- public void checkVisibility_navBarWindowIsAlwaysVisible() {
- checkResults(result -> WmTraceSubject.assertThat(result)
- .showsAboveAppWindow(NAVIGATION_BAR_WINDOW_TITLE).forAllEntries());
- }
-
- @Test
- public void checkPosition_navBarLayerRotatesAndScales() {
- Rect startingPos = getNavigationBarPosition(mBeginRotation);
- Rect endingPos = getNavigationBarPosition(mEndRotation);
- if (startingPos.equals(endingPos)) {
- checkResults(result -> LayersTraceSubject.assertThat(result)
- .hasVisibleRegion(NAVIGATION_BAR_WINDOW_TITLE, startingPos)
- .forAllEntries());
- } else {
- checkResults(result -> LayersTraceSubject.assertThat(result)
- .hasVisibleRegion(NAVIGATION_BAR_WINDOW_TITLE, startingPos)
- .inTheBeginning());
- checkResults(result -> LayersTraceSubject.assertThat(result)
- .hasVisibleRegion(NAVIGATION_BAR_WINDOW_TITLE, endingPos)
- .atTheEnd());
- }
- }
-
- @Test
- public void checkPosition_appLayerRotates() {
- Rect startingPos = getAppPosition(mBeginRotation);
- Rect endingPos = getAppPosition(mEndRotation);
- if (startingPos.equals(endingPos)) {
- checkResults(result -> LayersTraceSubject.assertThat(result)
- .hasVisibleRegion(mIntent.getComponent().getPackageName(), startingPos)
- .forAllEntries());
- } else {
- checkResults(result -> LayersTraceSubject.assertThat(result)
- .hasVisibleRegion(mIntent.getComponent().getPackageName(), startingPos)
- .then()
- .hasVisibleRegion(mIntent.getComponent().getPackageName(), endingPos)
- .forAllEntries());
- }
- }
-
- @Test
- public void checkCoveredRegion_noUncoveredRegions() {
- Rect startingBounds = getDisplayBounds(mBeginRotation);
- Rect endingBounds = getDisplayBounds(mEndRotation);
- if (startingBounds.equals(endingBounds)) {
- checkResults(result ->
- LayersTraceSubject.assertThat(result)
- .coversRegion(startingBounds)
- .forAllEntries());
- } else {
- checkResults(result ->
- LayersTraceSubject.assertThat(result)
- .coversRegion(startingBounds)
- .then()
- .coversRegion(endingBounds)
- .forAllEntries());
- }
- }
-}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/SplitScreenToLauncherTest.java b/tests/FlickerTests/src/com/android/server/wm/flicker/SplitScreenToLauncherTest.java
deleted file mode 100644
index 85a14941a7fd..000000000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/SplitScreenToLauncherTest.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright (C) 2018 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.wm.flicker;
-
-import static com.android.server.wm.flicker.CommonTransitions.splitScreenToLauncher;
-import static com.android.server.wm.flicker.WindowUtils.getDisplayBounds;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.FlakyTest;
-import androidx.test.filters.LargeTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Before;
-import org.junit.FixMethodOrder;
-import org.junit.Ignore;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.MethodSorters;
-
-/**
- * Test open app to split screen.
- * To run this test: {@code atest FlickerTests:SplitScreenToLauncherTest}
- */
-@LargeTest
-@RunWith(AndroidJUnit4.class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@FlakyTest(bugId = 140856143)
-@Ignore("Waiting bug feedback")
-public class SplitScreenToLauncherTest extends FlickerTestBase {
-
- public SplitScreenToLauncherTest() {
- this.mTestApp = new StandardAppHelper(InstrumentationRegistry.getInstrumentation(),
- "com.android.server.wm.flicker.testapp", "SimpleApp");
- }
-
- @Before
- public void runTransition() {
- super.runTransition(splitScreenToLauncher(mTestApp, mUiDevice).includeJankyRuns().build());
- }
-
- @Test
- public void checkCoveredRegion_noUncoveredRegions() {
- checkResults(result ->
- LayersTraceSubject.assertThat(result)
- .coversRegion(getDisplayBounds()).forAllEntries());
- }
-
- @Test
- public void checkVisibility_dividerLayerBecomesInVisible() {
- checkResults(result -> LayersTraceSubject.assertThat(result)
- .showsLayer(DOCKED_STACK_DIVIDER)
- .then()
- .hidesLayer(DOCKED_STACK_DIVIDER)
- .forAllEntries());
- }
-
- @Test
- public void checkVisibility_appLayerBecomesInVisible() {
- checkResults(result -> LayersTraceSubject.assertThat(result)
- .showsLayer(mTestApp.getPackage())
- .then()
- .hidesLayer(mTestApp.getPackage())
- .forAllEntries());
- }
-
- @Test
- public void checkVisibility_navBarWindowIsAlwaysVisible() {
- checkResults(result -> WmTraceSubject.assertThat(result)
- .showsAboveAppWindow(NAVIGATION_BAR_WINDOW_TITLE).forAllEntries());
- }
-
- @Test
- public void checkVisibility_statusBarWindowIsAlwaysVisible() {
- checkResults(result -> WmTraceSubject.assertThat(result)
- .showsAboveAppWindow(STATUS_BAR_WINDOW_TITLE).forAllEntries());
- }
-
- @Test
- public void checkVisibility_dividerWindowBecomesInVisible() {
- checkResults(result -> WmTraceSubject.assertThat(result)
- .showsAboveAppWindow(DOCKED_STACK_DIVIDER)
- .then()
- .hidesAboveAppWindow(DOCKED_STACK_DIVIDER)
- .forAllEntries());
- }
-}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
new file mode 100644
index 000000000000..71184c2e0aa2
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2020 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.wm.flicker.close
+
+import androidx.test.filters.RequiresDevice
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.annotation.Group1
+import com.android.server.wm.flicker.dsl.FlickerBuilder
+import org.junit.FixMethodOrder
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test app closes by pressing back button
+ * To run this test: `atest FlickerTests:CloseAppBackButtonTest`
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group1
+class CloseAppBackButtonTest(testSpec: FlickerTestParameter) : CloseAppTransition(testSpec) {
+ override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
+ get() = {
+ super.transition(this, it)
+ transitions {
+ device.pressBack()
+ wmHelper.waitForHomeActivityVisible()
+ }
+ }
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): List<FlickerTestParameter> {
+ return FlickerTestParameterFactory.getInstance()
+ .getConfigNonRotationTests(repetitions = 5)
+ }
+ }
+} \ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt
new file mode 100644
index 000000000000..6786279ae107
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2020 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.wm.flicker.close
+
+import androidx.test.filters.RequiresDevice
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.annotation.Group1
+import com.android.server.wm.flicker.dsl.FlickerBuilder
+import org.junit.FixMethodOrder
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test app closes by pressing home button.
+ * To run this test: `atest FlickerTests:CloseAppHomeButtonTest`
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group1
+class CloseAppHomeButtonTest(testSpec: FlickerTestParameter) : CloseAppTransition(testSpec) {
+ override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
+ get() = {
+ super.transition(this, it)
+ transitions {
+ device.pressHome()
+ wmHelper.waitForHomeActivityVisible()
+ }
+ }
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): Collection<FlickerTestParameter> {
+ return FlickerTestParameterFactory.getInstance()
+ .getConfigNonRotationTests(repetitions = 5)
+ }
+ }
+} \ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt
new file mode 100644
index 000000000000..f7f977d7bd0a
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt
@@ -0,0 +1,142 @@
+/*
+ * 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.server.wm.flicker.close
+
+import android.app.Instrumentation
+import android.platform.test.annotations.Presubmit
+import android.view.Surface
+import androidx.test.filters.FlakyTest
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.server.wm.flicker.FlickerBuilderProvider
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.helpers.SimpleAppHelper
+import com.android.server.wm.flicker.helpers.StandardAppHelper
+import com.android.server.wm.flicker.helpers.setRotation
+import com.android.server.wm.flicker.launcherReplacesAppWindowAsTopWindow
+import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.navBarLayerRotatesAndScales
+import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.noUncoveredRegions
+import com.android.server.wm.flicker.startRotation
+import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarLayerRotatesScales
+import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.launcherLayerReplacesApp
+import com.android.server.wm.flicker.launcherWindowBecomesVisible
+import org.junit.Test
+
+abstract class CloseAppTransition(protected val testSpec: FlickerTestParameter) {
+ protected val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ protected open val testApp: StandardAppHelper = SimpleAppHelper(instrumentation)
+ protected open val transition: FlickerBuilder.(Map<String, Any?>) -> Unit = {
+ setup {
+ eachRun {
+ testApp.launchViaIntent(wmHelper)
+ this.setRotation(testSpec.config.startRotation)
+ }
+ }
+ teardown {
+ test {
+ testApp.exit()
+ }
+ }
+ }
+
+ @FlickerBuilderProvider
+ fun buildFlicker(): FlickerBuilder {
+ return FlickerBuilder(instrumentation).apply {
+ transition(testSpec.config)
+ }
+ }
+
+ @Presubmit
+ @Test
+ open fun navBarWindowIsAlwaysVisible() {
+ testSpec.navBarWindowIsAlwaysVisible()
+ }
+
+ @Presubmit
+ @Test
+ open fun statusBarWindowIsAlwaysVisible() {
+ testSpec.statusBarWindowIsAlwaysVisible()
+ }
+
+ @FlakyTest
+ @Test
+ open fun navBarLayerIsAlwaysVisible() {
+ testSpec.navBarLayerIsAlwaysVisible(rotatesScreen = testSpec.isRotated)
+ }
+
+ @Presubmit
+ @Test
+ open fun statusBarLayerIsAlwaysVisible() {
+ testSpec.statusBarLayerIsAlwaysVisible(rotatesScreen = testSpec.isRotated)
+ }
+
+ @FlakyTest
+ @Test
+ open fun navBarLayerRotatesAndScales() {
+ testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, Surface.ROTATION_0)
+ }
+
+ @Presubmit
+ @Test
+ open fun statusBarLayerRotatesScales() {
+ testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, Surface.ROTATION_0)
+ }
+
+ @Presubmit
+ @Test
+ open fun visibleWindowsShownMoreThanOneConsecutiveEntry() {
+ testSpec.assertWm {
+ this.visibleWindowsShownMoreThanOneConsecutiveEntry()
+ }
+ }
+
+ @Presubmit
+ @Test
+ open fun visibleLayersShownMoreThanOneConsecutiveEntry() {
+ testSpec.assertLayers {
+ this.visibleLayersShownMoreThanOneConsecutiveEntry()
+ }
+ }
+
+ @Presubmit
+ @Test
+ open fun noUncoveredRegions() {
+ testSpec.noUncoveredRegions(testSpec.config.startRotation, Surface.ROTATION_0)
+ }
+
+ @Presubmit
+ @Test
+ open fun launcherReplacesAppWindowAsTopWindow() {
+ testSpec.launcherReplacesAppWindowAsTopWindow(testApp)
+ }
+
+ @Presubmit
+ @Test
+ open fun launcherWindowBecomesVisible() {
+ testSpec.launcherWindowBecomesVisible()
+ }
+
+ @Presubmit
+ @Test
+ open fun launcherLayerReplacesApp() {
+ testSpec.launcherLayerReplacesApp(testApp)
+ }
+} \ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FlickerAppHelper.java b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FlickerAppHelper.java
deleted file mode 100644
index 42977f549162..000000000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FlickerAppHelper.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2019 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.wm.flicker.helpers;
-
-import android.app.Instrumentation;
-
-import com.android.server.wm.flicker.StandardAppHelper;
-
-public abstract class FlickerAppHelper extends StandardAppHelper {
-
- static int sFindTimeout = 10000;
- static String sFlickerPackage = "com.android.server.wm.flicker.testapp";
-
- public FlickerAppHelper(Instrumentation instr, String launcherName) {
- super(instr, sFlickerPackage, launcherName);
- }
-}
diff --git a/tests/AutoVerify/app4/src/com/android/test/autoverify/MainActivity.java b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FlickerExtensions.kt
index 09ef47212622..fad25b4fa0b9 100644
--- a/tests/AutoVerify/app4/src/com/android/test/autoverify/MainActivity.java
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FlickerExtensions.kt
@@ -13,3 +13,16 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
+package com.android.server.wm.flicker.helpers
+
+import com.android.server.wm.flicker.Flicker
+import com.android.server.wm.flicker.rules.ChangeDisplayOrientationRule
+
+/**
+ * Changes the device [rotation] and wait for the rotation animation to complete
+ *
+ * @param rotation New device rotation
+ */
+fun Flicker.setRotation(rotation: Int) =
+ ChangeDisplayOrientationRule.setRotation(rotation, instrumentation, wmHelper)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppAutoFocusHelper.java b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppAutoFocusHelper.java
deleted file mode 100644
index 56e1118590ea..000000000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppAutoFocusHelper.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2019 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.wm.flicker.helpers;
-
-import android.app.Instrumentation;
-import android.support.test.uiautomator.UiDevice;
-
-public class ImeAppAutoFocusHelper extends ImeAppHelper {
-
- public ImeAppAutoFocusHelper(Instrumentation instr) {
- super(instr, "ImeAppAutoFocus");
- }
-
- public void clickEditTextWidget(UiDevice device) {
- // do nothing (the app is focused automatically)
- }
-}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppAutoFocusHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppAutoFocusHelper.kt
new file mode 100644
index 000000000000..bd7c1855fea9
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppAutoFocusHelper.kt
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2020 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.wm.flicker.helpers
+
+import android.app.Instrumentation
+import android.content.ComponentName
+import androidx.test.uiautomator.UiDevice
+import com.android.server.wm.flicker.testapp.ActivityOptions
+import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
+
+class ImeAppAutoFocusHelper @JvmOverloads constructor(
+ instr: Instrumentation,
+ private val rotation: Int,
+ private val imePackageName: String = IME_PACKAGE,
+ launcherName: String = ActivityOptions.IME_ACTIVITY_AUTO_FOCUS_LAUNCHER_NAME,
+ component: ComponentName = ActivityOptions.IME_ACTIVITY_AUTO_FOCUS_COMPONENT_NAME
+) : ImeAppHelper(instr, launcherName, component) {
+ override fun openIME(
+ device: UiDevice,
+ wmHelper: WindowManagerStateHelper?
+ ) {
+ // do nothing (the app is focused automatically)
+ waitIMEShown(device, wmHelper)
+ }
+
+ override fun open() {
+ val expectedPackage = if (rotation.isRotated()) {
+ imePackageName
+ } else {
+ getPackage()
+ }
+ launcherStrategy.launch(appName, expectedPackage)
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppHelper.java b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppHelper.java
deleted file mode 100644
index 098fd6d4250b..000000000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppHelper.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2019 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.wm.flicker.helpers;
-
-import static android.os.SystemClock.sleep;
-
-import android.app.Instrumentation;
-import android.support.test.uiautomator.By;
-import android.support.test.uiautomator.UiDevice;
-import android.support.test.uiautomator.UiObject2;
-
-public class ImeAppHelper extends FlickerAppHelper {
-
- ImeAppHelper(Instrumentation instr, String launcherName) {
- super(instr, launcherName);
- }
-
- public ImeAppHelper(Instrumentation instr) {
- this(instr, "ImeApp");
- }
-
- public void clickEditTextWidget(UiDevice device) {
- UiObject2 editText = device.findObject(By.res(getPackage(), "plain_text_input"));
- editText.click();
- sleep(500);
- }
-}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppHelper.kt
new file mode 100644
index 000000000000..83fddae5b1a7
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppHelper.kt
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2020 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.wm.flicker.helpers
+
+import android.app.Instrumentation
+import android.content.ComponentName
+import android.support.test.launcherhelper.ILauncherStrategy
+import android.support.test.launcherhelper.LauncherStrategyFactory
+import androidx.test.uiautomator.By
+import androidx.test.uiautomator.UiDevice
+import androidx.test.uiautomator.Until
+import com.android.server.wm.flicker.testapp.ActivityOptions
+import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
+
+open class ImeAppHelper @JvmOverloads constructor(
+ instr: Instrumentation,
+ launcherName: String = ActivityOptions.IME_ACTIVITY_LAUNCHER_NAME,
+ component: ComponentName = ActivityOptions.IME_ACTIVITY_COMPONENT_NAME,
+ launcherStrategy: ILauncherStrategy = LauncherStrategyFactory
+ .getInstance(instr)
+ .launcherStrategy
+) : StandardAppHelper(instr, launcherName, component, launcherStrategy) {
+ /**
+ * Opens the IME and wait for it to be displayed
+ *
+ * @param device UIDevice instance to interact with the device
+ * @param wmHelper Helper used to wait for WindowManager states
+ */
+ @JvmOverloads
+ open fun openIME(device: UiDevice, wmHelper: WindowManagerStateHelper? = null) {
+ val editText = device.wait(
+ Until.findObject(By.res(getPackage(), "plain_text_input")),
+ FIND_TIMEOUT)
+
+ require(editText != null) {
+ "Text field not found, this usually happens when the device " +
+ "was left in an unknown state (e.g. in split screen)"
+ }
+ editText.click()
+ waitIMEShown(device, wmHelper)
+ }
+
+ protected fun waitIMEShown(
+ device: UiDevice,
+ wmHelper: WindowManagerStateHelper? = null
+ ) {
+ if (wmHelper == null) {
+ device.waitForIdle()
+ } else {
+ wmHelper.waitImeWindowShown()
+ }
+ }
+
+ /**
+ * Opens the IME and wait for it to be gone
+ *
+ * @param device UIDevice instance to interact with the device
+ * @param wmHelper Helper used to wait for WindowManager states
+ */
+ @JvmOverloads
+ open fun closeIME(device: UiDevice, wmHelper: WindowManagerStateHelper? = null) {
+ device.pressBack()
+ // Using only the AccessibilityInfo it is not possible to identify if the IME is active
+ if (wmHelper == null) {
+ device.waitForIdle()
+ } else {
+ wmHelper.waitImeWindowGone()
+ }
+ }
+} \ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/PipAppHelper.java b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/PipAppHelper.java
deleted file mode 100644
index d5f9a2062a17..000000000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/PipAppHelper.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2019 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.wm.flicker.helpers;
-
-import static com.android.server.wm.flicker.helpers.AutomationUtils.getPipWindowSelector;
-
-import android.app.Instrumentation;
-import android.support.test.uiautomator.By;
-import android.support.test.uiautomator.UiDevice;
-import android.support.test.uiautomator.UiObject2;
-import android.support.test.uiautomator.Until;
-
-public class PipAppHelper extends FlickerAppHelper {
-
- public PipAppHelper(Instrumentation instr) {
- super(instr, "PipApp");
- }
-
- public void clickEnterPipButton(UiDevice device) {
- UiObject2 enterPipButton = device.findObject(By.res(getPackage(), "enter_pip"));
- enterPipButton.click();
- UiObject2 pipWindow = device.wait(Until.findObject(getPipWindowSelector()), sFindTimeout);
-
- if (pipWindow == null) {
- throw new RuntimeException("Unable to find PIP window");
- }
- }
-
- public void closePipWindow(UiDevice device) {
- AutomationUtils.closePipWindow(device);
- }
-
-}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/SeamlessRotationAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/SeamlessRotationAppHelper.kt
new file mode 100644
index 000000000000..02be3cf0a8a3
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/SeamlessRotationAppHelper.kt
@@ -0,0 +1,32 @@
+/*
+ * 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.server.wm.flicker.helpers
+
+import android.app.Instrumentation
+import android.content.ComponentName
+import android.support.test.launcherhelper.ILauncherStrategy
+import android.support.test.launcherhelper.LauncherStrategyFactory
+import com.android.server.wm.flicker.testapp.ActivityOptions
+
+class SeamlessRotationAppHelper @JvmOverloads constructor(
+ instr: Instrumentation,
+ launcherName: String = ActivityOptions.SEAMLESS_ACTIVITY_LAUNCHER_NAME,
+ component: ComponentName = ActivityOptions.SEAMLESS_ACTIVITY_COMPONENT_NAME,
+ launcherStrategy: ILauncherStrategy = LauncherStrategyFactory
+ .getInstance(instr)
+ .launcherStrategy
+) : StandardAppHelper(instr, launcherName, component, launcherStrategy) \ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/SimpleAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/SimpleAppHelper.kt
new file mode 100644
index 000000000000..d7cbaaee2627
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/SimpleAppHelper.kt
@@ -0,0 +1,32 @@
+/*
+ * 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.server.wm.flicker.helpers
+
+import android.app.Instrumentation
+import android.content.ComponentName
+import android.support.test.launcherhelper.ILauncherStrategy
+import android.support.test.launcherhelper.LauncherStrategyFactory
+import com.android.server.wm.flicker.testapp.ActivityOptions
+
+class SimpleAppHelper @JvmOverloads constructor(
+ instr: Instrumentation,
+ launcherName: String = ActivityOptions.SIMPLE_ACTIVITY_LAUNCHER_NAME,
+ component: ComponentName = ActivityOptions.SIMPLE_ACTIVITY_AUTO_FOCUS_COMPONENT_NAME,
+ launcherStrategy: ILauncherStrategy = LauncherStrategyFactory
+ .getInstance(instr)
+ .launcherStrategy
+) : StandardAppHelper(instr, launcherName, component, launcherStrategy) \ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt
new file mode 100644
index 000000000000..b5757fd21ee0
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2020 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.wm.flicker.ime
+
+import android.app.Instrumentation
+import android.platform.test.annotations.Presubmit
+import android.view.WindowManagerPolicyConstants
+import androidx.test.filters.FlakyTest
+import androidx.test.filters.RequiresDevice
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.server.wm.flicker.FlickerBuilderProvider
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.annotation.Group2
+import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.helpers.ImeAppAutoFocusHelper
+import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.navBarLayerRotatesAndScales
+import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.noUncoveredRegions
+import com.android.server.wm.flicker.startRotation
+import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarLayerRotatesScales
+import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
+import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test IME window closing back to app window transitions.
+ * To run this test: `atest FlickerTests:CloseImeAutoOpenWindowToAppTest`
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group2
+class CloseImeAutoOpenWindowToAppTest(private val testSpec: FlickerTestParameter) {
+ private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ private val testApp = ImeAppAutoFocusHelper(instrumentation, testSpec.config.startRotation)
+
+ @FlickerBuilderProvider
+ fun buildFlicker(): FlickerBuilder {
+ return FlickerBuilder(instrumentation).apply {
+ setup {
+ eachRun {
+ testApp.launchViaIntent(wmHelper)
+ testApp.openIME(device, wmHelper)
+ }
+ }
+ teardown {
+ eachRun {
+ testApp.exit(wmHelper)
+ }
+ }
+ transitions {
+ testApp.closeIME(device, wmHelper)
+ }
+ }
+ }
+
+ @Presubmit
+ @Test
+ fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ fun visibleWindowsShownMoreThanOneConsecutiveEntry() {
+ testSpec.assertWm {
+ this.visibleWindowsShownMoreThanOneConsecutiveEntry(listOf(IME_WINDOW_TITLE,
+ WindowManagerStateHelper.SPLASH_SCREEN_NAME,
+ WindowManagerStateHelper.SNAPSHOT_WINDOW_NAME))
+ }
+ }
+
+ @Presubmit
+ @Test
+ fun imeAppWindowIsAlwaysVisible() = testSpec.imeAppWindowIsAlwaysVisible(testApp)
+
+ @Presubmit
+ @Test
+ fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
+
+ @FlakyTest
+ @Test
+ fun noUncoveredRegions() = testSpec.noUncoveredRegions(testSpec.config.startRotation)
+
+ @Presubmit
+ @Test
+ fun imeLayerBecomesInvisible() = testSpec.imeLayerBecomesInvisible()
+
+ @Presubmit
+ @Test
+ fun imeAppLayerIsAlwaysVisible() = testSpec.imeAppLayerIsAlwaysVisible(testApp)
+
+ @FlakyTest
+ @Test
+ fun navBarLayerRotatesAndScales() {
+ testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation)
+ }
+
+ @FlakyTest
+ @Test
+ fun statusBarLayerRotatesScales() {
+ testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation)
+ }
+
+ @Presubmit
+ @Test
+ fun visibleLayersShownMoreThanOneConsecutiveEntry() {
+ testSpec.assertLayers {
+ this.visibleLayersShownMoreThanOneConsecutiveEntry()
+ }
+ }
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): Collection<FlickerTestParameter> {
+ return FlickerTestParameterFactory.getInstance()
+ .getConfigNonRotationTests(repetitions = 5,
+ supportedNavigationModes = listOf(
+ WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY)
+ )
+ }
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt
new file mode 100644
index 000000000000..549e44c511b9
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2020 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.wm.flicker.ime
+
+import android.app.Instrumentation
+import android.platform.test.annotations.Presubmit
+import android.view.Surface
+import android.view.WindowManagerPolicyConstants
+import androidx.test.filters.FlakyTest
+import androidx.test.filters.RequiresDevice
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.server.wm.flicker.FlickerBuilderProvider
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.annotation.Group2
+import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.helpers.ImeAppAutoFocusHelper
+import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.navBarLayerRotatesAndScales
+import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.noUncoveredRegions
+import com.android.server.wm.flicker.startRotation
+import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarLayerRotatesScales
+import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
+import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test IME window closing back to app window transitions.
+ * To run this test: `atest FlickerTests:CloseImeAutoOpenWindowToHomeTest`
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group2
+class CloseImeAutoOpenWindowToHomeTest(private val testSpec: FlickerTestParameter) {
+ private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ private val testApp = ImeAppAutoFocusHelper(instrumentation, testSpec.config.startRotation)
+
+ @FlickerBuilderProvider
+ fun buildFlicker(): FlickerBuilder {
+ return FlickerBuilder(instrumentation).apply {
+ setup {
+ eachRun {
+ testApp.launchViaIntent(wmHelper)
+ testApp.openIME(device, wmHelper)
+ }
+ }
+ teardown {
+ eachRun {
+ testApp.exit(wmHelper)
+ }
+ }
+ transitions {
+ device.pressHome()
+ wmHelper.waitForHomeActivityVisible()
+ wmHelper.waitImeWindowGone()
+ }
+ }
+ }
+
+ @Presubmit
+ @Test
+ fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ fun visibleWindowsShownMoreThanOneConsecutiveEntry() {
+ testSpec.assertWm {
+ this.visibleWindowsShownMoreThanOneConsecutiveEntry(listOf(IME_WINDOW_TITLE,
+ WindowManagerStateHelper.SPLASH_SCREEN_NAME,
+ WindowManagerStateHelper.SNAPSHOT_WINDOW_NAME))
+ }
+ }
+
+ @FlakyTest
+ @Test
+ fun imeWindowBecomesInvisible() = testSpec.imeWindowBecomesInvisible()
+
+ @FlakyTest
+ @Test
+ fun imeAppWindowBecomesInvisible() = testSpec.imeAppWindowBecomesInvisible(testApp)
+
+ @Presubmit
+ @Test
+ fun noUncoveredRegions() = testSpec.noUncoveredRegions(testSpec.config.startRotation,
+ Surface.ROTATION_0)
+
+ @FlakyTest
+ @Test
+ fun imeLayerBecomesInvisible() = testSpec.imeLayerBecomesInvisible()
+
+ @Presubmit
+ @Test
+ fun imeAppLayerBecomesInvisible() = testSpec.imeAppLayerBecomesInvisible(testApp)
+
+ @FlakyTest
+ @Test
+ fun navBarLayerRotatesAndScales() {
+ testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, Surface.ROTATION_0)
+ }
+
+ @Presubmit
+ @Test
+ fun statusBarLayerRotatesScales() {
+ testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, Surface.ROTATION_0)
+ }
+
+ @Presubmit
+ @Test
+ fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
+
+ @FlakyTest
+ @Test
+ fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ fun visibleLayersShownMoreThanOneConsecutiveEntry() {
+ testSpec.assertLayers {
+ this.visibleLayersShownMoreThanOneConsecutiveEntry(
+ listOf(IME_WINDOW_TITLE, WindowManagerStateHelper.SPLASH_SCREEN_NAME))
+ }
+ }
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): Collection<FlickerTestParameter> {
+ return FlickerTestParameterFactory.getInstance()
+ .getConfigNonRotationTests(repetitions = 1,
+ supportedNavigationModes = listOf(
+ WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY)
+ )
+ }
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt
new file mode 100644
index 000000000000..82ca074b5ef2
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2020 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.wm.flicker.ime
+
+import android.app.Instrumentation
+import android.platform.test.annotations.Presubmit
+import androidx.test.filters.FlakyTest
+import androidx.test.filters.RequiresDevice
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.server.wm.flicker.FlickerBuilderProvider
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.annotation.Group2
+import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.helpers.ImeAppHelper
+import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.navBarLayerRotatesAndScales
+import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.noUncoveredRegions
+import com.android.server.wm.flicker.startRotation
+import com.android.server.wm.flicker.statusBarLayerRotatesScales
+import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
+import org.junit.Assume
+import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test IME window closing back to app window transitions.
+ * To run this test: `atest FlickerTests:CloseImeWindowToAppTest`
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group2
+class CloseImeWindowToAppTest(private val testSpec: FlickerTestParameter) {
+ private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ private val testApp = ImeAppHelper(instrumentation)
+
+ @FlickerBuilderProvider
+ fun buildFlicker(): FlickerBuilder {
+ return FlickerBuilder(instrumentation).apply {
+ setup {
+ test {
+ testApp.launchViaIntent()
+ }
+ eachRun {
+ testApp.openIME(device, wmHelper)
+ }
+ }
+ teardown {
+ test {
+ testApp.exit(wmHelper)
+ }
+ }
+ transitions {
+ testApp.closeIME(device, wmHelper)
+ }
+ }
+ }
+
+ @Presubmit
+ @Test
+ fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ fun visibleWindowsShownMoreThanOneConsecutiveEntry() {
+ testSpec.assertWm {
+ this.visibleWindowsShownMoreThanOneConsecutiveEntry(listOf(IME_WINDOW_TITLE,
+ WindowManagerStateHelper.SPLASH_SCREEN_NAME,
+ WindowManagerStateHelper.SNAPSHOT_WINDOW_NAME))
+ }
+ }
+
+ @Presubmit
+ @Test
+ fun imeAppWindowIsAlwaysVisible() = testSpec.imeAppWindowIsAlwaysVisible(testApp)
+
+ @Presubmit
+ @Test
+ fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ fun statusBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ fun noUncoveredRegions() = testSpec.noUncoveredRegions(testSpec.config.startRotation)
+
+ @Presubmit
+ @Test
+ fun navBarLayerRotatesAndScales() {
+ Assume.assumeFalse(testSpec.isRotated)
+ testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation)
+ }
+
+ @FlakyTest
+ @Test
+ fun navBarLayerRotatesAndScales_Flaky() {
+ Assume.assumeTrue(testSpec.isRotated)
+ testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation)
+ }
+
+ @Presubmit
+ @Test
+ fun statusBarLayerRotatesScales() {
+ testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation)
+ }
+
+ @Presubmit
+ @Test
+ fun visibleLayersShownMoreThanOneConsecutiveEntry() {
+ testSpec.assertLayers {
+ this.visibleLayersShownMoreThanOneConsecutiveEntry()
+ }
+ }
+
+ @Presubmit
+ @Test
+ fun imeLayerBecomesInvisible() = testSpec.imeLayerBecomesInvisible()
+
+ @Presubmit
+ @Test
+ fun imeAppLayerIsAlwaysVisible() = testSpec.imeAppLayerIsAlwaysVisible(testApp)
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): Collection<FlickerTestParameter> {
+ return FlickerTestParameterFactory.getInstance()
+ .getConfigNonRotationTests(repetitions = 5)
+ }
+ }
+} \ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt
new file mode 100644
index 000000000000..703e4a125440
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2020 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.wm.flicker.ime
+
+import android.app.Instrumentation
+import android.platform.test.annotations.Presubmit
+import android.view.Surface
+import android.view.WindowManagerPolicyConstants
+import androidx.test.filters.FlakyTest
+import androidx.test.filters.RequiresDevice
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.server.wm.flicker.FlickerBuilderProvider
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.annotation.Group2
+import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.helpers.ImeAppHelper
+import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.navBarLayerRotatesAndScales
+import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.noUncoveredRegions
+import com.android.server.wm.flicker.startRotation
+import com.android.server.wm.flicker.statusBarLayerRotatesScales
+import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
+import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+/**
+ * Test IME window closing to home transitions.
+ * To run this test: `atest FlickerTests:CloseImeWindowToHomeTest`
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group2
+class CloseImeWindowToHomeTest(private val testSpec: FlickerTestParameter) {
+ private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ private val testApp = ImeAppHelper(instrumentation)
+
+ @FlickerBuilderProvider
+ fun buildFlicker(): FlickerBuilder {
+ return FlickerBuilder(instrumentation).apply {
+ setup {
+ eachRun {
+ testApp.launchViaIntent(wmHelper)
+ testApp.openIME(device, wmHelper)
+ }
+ }
+ transitions {
+ device.pressHome()
+ wmHelper.waitForHomeActivityVisible()
+ wmHelper.waitImeWindowGone()
+ }
+ teardown {
+ eachRun {
+ device.pressHome()
+ wmHelper.waitForHomeActivityVisible()
+ }
+ test {
+ testApp.exit()
+ }
+ }
+ }
+ }
+
+ @Presubmit
+ @Test
+ fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ fun visibleWindowsShownMoreThanOneConsecutiveEntry() {
+ testSpec.assertWm {
+ this.visibleWindowsShownMoreThanOneConsecutiveEntry(listOf(IME_WINDOW_TITLE,
+ WindowManagerStateHelper.SPLASH_SCREEN_NAME,
+ WindowManagerStateHelper.SNAPSHOT_WINDOW_NAME))
+ }
+ }
+
+ @Presubmit
+ @Test
+ fun imeWindowBecomesInvisible() = testSpec.imeWindowBecomesInvisible()
+
+ @FlakyTest
+ @Test
+ fun imeAppWindowBecomesInvisible() = testSpec.imeAppWindowBecomesInvisible(testApp)
+
+ @Presubmit
+ @Test
+ fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ fun statusBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ fun noUncoveredRegions() = testSpec.noUncoveredRegions(testSpec.config.startRotation,
+ Surface.ROTATION_0)
+
+ @Presubmit
+ @Test
+ fun imeLayerBecomesInvisible() = testSpec.imeLayerBecomesInvisible()
+
+ @Presubmit
+ @Test
+ fun imeAppLayerBecomesInvisible() = testSpec.imeAppLayerBecomesInvisible(testApp)
+
+ @Presubmit
+ @Test
+ fun navBarLayerRotatesAndScales() =
+ testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, Surface.ROTATION_0)
+
+ @Presubmit
+ @Test
+ fun statusBarLayerRotatesScales() {
+ testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, Surface.ROTATION_0)
+ }
+
+ @Presubmit
+ @Test
+ fun visibleLayersShownMoreThanOneConsecutiveEntry() {
+ testSpec.assertLayers {
+ this.visibleLayersShownMoreThanOneConsecutiveEntry(
+ listOf(IME_WINDOW_TITLE, WindowManagerStateHelper.SPLASH_SCREEN_NAME))
+ }
+ }
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): Collection<FlickerTestParameter> {
+ return FlickerTestParameterFactory.getInstance()
+ .getConfigNonRotationTests(
+ repetitions = 5,
+ supportedRotations = listOf(Surface.ROTATION_0),
+ supportedNavigationModes = listOf(
+ WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY,
+ WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY
+ )
+ )
+ }
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CommonAssertions.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CommonAssertions.kt
new file mode 100644
index 000000000000..7e34469b8188
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CommonAssertions.kt
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2020 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.wm.flicker.ime
+
+import android.platform.helpers.IAppHelper
+import com.android.server.wm.flicker.FlickerTestParameter
+
+const val IME_WINDOW_TITLE = "InputMethod"
+
+fun FlickerTestParameter.imeLayerIsAlwaysVisible(rotatesScreen: Boolean = false) {
+ if (rotatesScreen) {
+ assertLayers {
+ this.isVisible(IME_WINDOW_TITLE)
+ .then()
+ .isInvisible(IME_WINDOW_TITLE)
+ .then()
+ .isVisible(IME_WINDOW_TITLE)
+ }
+ } else {
+ assertLayers {
+ this.isVisible(IME_WINDOW_TITLE)
+ }
+ }
+}
+
+fun FlickerTestParameter.imeLayerBecomesVisible() {
+ assertLayers {
+ this.isInvisible(IME_WINDOW_TITLE)
+ .then()
+ .isVisible(IME_WINDOW_TITLE)
+ }
+}
+
+fun FlickerTestParameter.imeLayerBecomesInvisible() {
+ assertLayers {
+ this.isVisible(IME_WINDOW_TITLE)
+ .then()
+ .isInvisible(IME_WINDOW_TITLE)
+ }
+}
+
+fun FlickerTestParameter.imeAppLayerIsAlwaysVisible(testApp: IAppHelper) {
+ assertLayers {
+ this.isVisible(testApp.getPackage())
+ }
+}
+
+fun FlickerTestParameter.imeAppWindowIsAlwaysVisible(testApp: IAppHelper) {
+ assertWm {
+ this.showsAppWindowOnTop(testApp.getPackage())
+ }
+}
+
+fun FlickerTestParameter.imeWindowIsAlwaysVisible(rotatesScreen: Boolean = false) {
+ if (rotatesScreen) {
+ assertWm {
+ this.showsNonAppWindow(IME_WINDOW_TITLE)
+ .then()
+ .hidesNonAppWindow(IME_WINDOW_TITLE)
+ .then()
+ .showsNonAppWindow(IME_WINDOW_TITLE)
+ }
+ } else {
+ assertWm {
+ this.showsNonAppWindow(IME_WINDOW_TITLE)
+ }
+ }
+}
+
+fun FlickerTestParameter.imeWindowBecomesVisible() {
+ assertWm {
+ this.hidesNonAppWindow(IME_WINDOW_TITLE)
+ .then()
+ .showsNonAppWindow(IME_WINDOW_TITLE)
+ }
+}
+
+fun FlickerTestParameter.imeWindowBecomesInvisible() {
+ assertWm {
+ this.showsNonAppWindow(IME_WINDOW_TITLE)
+ .then()
+ .hidesNonAppWindow(IME_WINDOW_TITLE)
+ }
+}
+
+fun FlickerTestParameter.imeAppWindowIsAlwaysVisible(
+ testApp: IAppHelper,
+ rotatesScreen: Boolean = false
+) {
+ if (rotatesScreen) {
+ assertWm {
+ this.showsAppWindow(testApp.getPackage())
+ .then()
+ .hidesAppWindow(testApp.getPackage())
+ .then()
+ .showsAppWindow(testApp.getPackage())
+ }
+ } else {
+ assertWm {
+ this.showsAppWindow(testApp.getPackage())
+ }
+ }
+}
+
+fun FlickerTestParameter.imeAppWindowBecomesVisible(windowName: String) {
+ assertWm {
+ this.hidesAppWindow(windowName)
+ .then()
+ .showsAppWindow(windowName)
+ }
+}
+
+fun FlickerTestParameter.imeAppWindowBecomesInvisible(testApp: IAppHelper) {
+ assertWm {
+ this.showsAppWindowOnTop(testApp.getPackage())
+ .then()
+ .appWindowNotOnTop(testApp.getPackage())
+ }
+}
+
+fun FlickerTestParameter.imeAppLayerBecomesInvisible(testApp: IAppHelper) {
+ assertLayers {
+ this.isVisible(testApp.getPackage())
+ .then()
+ .isInvisible(testApp.getPackage())
+ }
+} \ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt
new file mode 100644
index 000000000000..cae1b16c1c8c
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2020 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.wm.flicker.ime
+
+import android.app.Instrumentation
+import android.platform.test.annotations.Presubmit
+import android.view.Surface
+import android.view.WindowManagerPolicyConstants
+import androidx.test.filters.RequiresDevice
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.server.wm.flicker.FlickerBuilderProvider
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.annotation.Group2
+import com.android.server.wm.flicker.helpers.ImeAppHelper
+import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.navBarLayerRotatesAndScales
+import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.noUncoveredRegions
+import com.android.server.wm.flicker.appWindowAlwaysVisibleOnTop
+import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.startRotation
+import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarLayerRotatesScales
+import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test IME window opening transitions.
+ * To run this test: `atest FlickerTests:OpenImeWindowTest`
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group2
+class OpenImeWindowTest(private val testSpec: FlickerTestParameter) {
+ private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ private val testApp = ImeAppHelper(instrumentation)
+
+ @FlickerBuilderProvider
+ fun buildFlicker(): FlickerBuilder {
+ return FlickerBuilder(instrumentation).apply {
+ setup {
+ test {
+ testApp.launchViaIntent(wmHelper)
+ }
+ }
+ transitions {
+ testApp.openIME(device, wmHelper)
+ }
+ teardown {
+ eachRun {
+ testApp.closeIME(device, wmHelper)
+ }
+ test {
+ testApp.exit()
+ }
+ }
+ }
+ }
+
+ @Presubmit
+ @Test
+ fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ fun imeWindowBecomesVisible() = testSpec.imeWindowBecomesVisible()
+
+ @Presubmit
+ @Test
+ fun appWindowAlwaysVisibleOnTop() = testSpec.appWindowAlwaysVisibleOnTop(testApp.`package`)
+
+ @Presubmit
+ @Test
+ fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ fun noUncoveredRegions() = testSpec.noUncoveredRegions(testSpec.config.startRotation)
+
+ @Presubmit
+ @Test
+ fun imeLayerBecomesVisible() = testSpec.imeLayerBecomesVisible()
+
+ @Presubmit
+ @Test
+ fun layerAlwaysVisible() {
+ testSpec.assertLayers {
+ this.isVisible(testApp.`package`)
+ }
+ }
+
+ @Presubmit
+ @Test
+ fun navBarLayerRotatesAndScales() {
+ testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation)
+ }
+
+ @Presubmit
+ @Test
+ fun statusBarLayerRotatesScales() {
+ testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation)
+ }
+
+ @Presubmit
+ @Test
+ fun visibleLayersShownMoreThanOneConsecutiveEntry() {
+ testSpec.assertLayers {
+ this.visibleLayersShownMoreThanOneConsecutiveEntry()
+ }
+ }
+
+ @Presubmit
+ @Test
+ fun visibleWindowsShownMoreThanOneConsecutiveEntry() {
+ testSpec.assertWm {
+ this.visibleWindowsShownMoreThanOneConsecutiveEntry()
+ }
+ }
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): Collection<FlickerTestParameter> {
+ return FlickerTestParameterFactory.getInstance()
+ .getConfigNonRotationTests(
+ repetitions = 5,
+ supportedRotations = listOf(Surface.ROTATION_0),
+ supportedNavigationModes = listOf(
+ WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY,
+ WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY
+ )
+ )
+ }
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt
new file mode 100644
index 000000000000..b7673d5b0107
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2020 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.wm.flicker.ime
+
+import android.app.Instrumentation
+import android.platform.test.annotations.Presubmit
+import android.view.Surface
+import android.view.WindowManagerPolicyConstants
+import androidx.test.filters.RequiresDevice
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.server.wm.flicker.FlickerBuilderProvider
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.annotation.Group2
+import com.android.server.wm.flicker.helpers.ImeAppAutoFocusHelper
+import com.android.server.wm.flicker.helpers.reopenAppFromOverview
+import com.android.server.wm.flicker.helpers.setRotation
+import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.navBarLayerRotatesAndScales
+import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.launcherWindowBecomesInvisible
+import com.android.server.wm.flicker.appLayerReplacesLauncher
+import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.noUncoveredRegions
+import com.android.server.wm.flicker.startRotation
+import com.android.server.wm.flicker.endRotation
+import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarLayerRotatesScales
+import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.testapp.ActivityOptions
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test IME window opening transitions.
+ * To run this test: `atest FlickerTests:ReOpenImeWindowTest`
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group2
+class ReOpenImeWindowTest(private val testSpec: FlickerTestParameter) {
+ private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ private val testApp = ImeAppAutoFocusHelper(instrumentation, testSpec.config.startRotation)
+ private val testAppComponentName = ActivityOptions.IME_ACTIVITY_AUTO_FOCUS_COMPONENT_NAME
+
+ @FlickerBuilderProvider
+ fun buildFlicker(): FlickerBuilder {
+ return FlickerBuilder(instrumentation).apply {
+ setup {
+ test {
+ testApp.launchViaIntent(wmHelper)
+ testApp.openIME(device, wmHelper)
+ }
+ eachRun {
+ device.pressRecentApps()
+ wmHelper.waitImeWindowGone()
+ wmHelper.waitForAppTransitionIdle()
+ this.setRotation(testSpec.config.startRotation)
+ }
+ }
+ transitions {
+ device.reopenAppFromOverview(wmHelper)
+ wmHelper.waitImeWindowShown()
+ }
+ teardown {
+ test {
+ testApp.exit()
+ }
+ }
+ }
+ }
+
+ @Presubmit
+ @Test
+ fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ fun visibleWindowsShownMoreThanOneConsecutiveEntry() {
+ testSpec.assertWm {
+ this.visibleWindowsShownMoreThanOneConsecutiveEntry()
+ }
+ }
+
+ @Presubmit
+ @Test
+ fun launcherWindowBecomesInvisible() = testSpec.launcherWindowBecomesInvisible()
+
+ @Presubmit
+ @Test
+ fun imeWindowIsAlwaysVisible() = testSpec.imeWindowIsAlwaysVisible(true)
+
+ @Presubmit
+ @Test
+ fun imeAppWindowIsAlwaysVisible() = testSpec.imeAppWindowIsAlwaysVisible(testApp, true)
+
+ @Presubmit
+ @Test
+ // During testing the launcher is always in portrait mode
+ fun noUncoveredRegions() = testSpec.noUncoveredRegions(testSpec.config.startRotation,
+ testSpec.config.endRotation)
+
+ @Presubmit
+ @Test
+ fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ fun imeLayerIsAlwaysVisible() = testSpec.imeLayerIsAlwaysVisible(true)
+
+ @Presubmit
+ @Test
+ fun appLayerReplacesLauncher() =
+ testSpec.appLayerReplacesLauncher(testAppComponentName.className)
+
+ @Presubmit
+ @Test
+ fun navBarLayerRotatesAndScales() {
+ testSpec.navBarLayerRotatesAndScales(Surface.ROTATION_0, testSpec.config.endRotation)
+ }
+
+ @Presubmit
+ @Test
+ fun statusBarLayerRotatesScales() {
+ testSpec.statusBarLayerRotatesScales(Surface.ROTATION_0, testSpec.config.endRotation)
+ }
+
+ @Presubmit
+ @Test
+ fun visibleLayersShownMoreThanOneConsecutiveEntry() {
+ testSpec.assertLayers {
+ this.visibleLayersShownMoreThanOneConsecutiveEntry()
+ }
+ }
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): Collection<FlickerTestParameter> {
+ return FlickerTestParameterFactory.getInstance()
+ .getConfigNonRotationTests(
+ repetitions = 1,
+ supportedRotations = listOf(Surface.ROTATION_0),
+ supportedNavigationModes = listOf(
+ WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY
+ )
+ )
+ }
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/SwitchImeWindowsFromGestureNavTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/SwitchImeWindowsFromGestureNavTest.kt
new file mode 100644
index 000000000000..0cae37c8d5ab
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/SwitchImeWindowsFromGestureNavTest.kt
@@ -0,0 +1,143 @@
+/*
+ * 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.server.wm.flicker.ime
+
+import android.app.Instrumentation
+import android.platform.test.annotations.Presubmit
+import android.view.WindowManagerPolicyConstants
+import androidx.test.filters.FlakyTest
+import androidx.test.filters.RequiresDevice
+import androidx.test.platform.app.InstrumentationRegistry
+
+import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.FlickerBuilderProvider
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.annotation.Group2
+import com.android.server.wm.flicker.helpers.ImeAppHelper
+import com.android.server.wm.flicker.helpers.SimpleAppHelper
+import com.android.server.wm.flicker.helpers.WindowUtils
+import com.android.server.wm.flicker.helpers.setRotation
+import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.startRotation
+import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
+
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test IME windows switching with 2-Buttons or gestural navigation.
+ * To run this test: `atest FlickerTests:SwitchImeWindowsFromGestureNavTest`
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group2
+class SwitchImeWindowsFromGestureNavTest(private val testSpec: FlickerTestParameter) {
+ private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ private val testApp = SimpleAppHelper(instrumentation)
+ private val imeTestApp = ImeAppHelper(instrumentation)
+
+ @FlickerBuilderProvider
+ fun buildFlicker(): FlickerBuilder {
+ return FlickerBuilder(instrumentation).apply {
+ setup {
+ eachRun {
+ this.setRotation(testSpec.config.startRotation)
+ testApp.launchViaIntent(wmHelper)
+ imeTestApp.launchViaIntent(wmHelper)
+ imeTestApp.openIME(device, wmHelper)
+ }
+ }
+ teardown {
+ eachRun {
+ device.pressHome()
+ wmHelper.waitForHomeActivityVisible()
+ }
+ test {
+ imeTestApp.exit(wmHelper)
+ }
+ }
+ transitions {
+ // [Step1]: Swipe right from imeTestApp to testApp task
+ val displayBounds = WindowUtils.getDisplayBounds(testSpec.config.startRotation)
+ val displayCenterX = displayBounds.bounds.width() / 2
+ device.swipe(displayCenterX, displayBounds.bounds.height(),
+ displayBounds.bounds.width(), displayBounds.bounds.height(), 20)
+ wmHelper.waitForFullScreenApp(testApp.component)
+ }
+ transitions {
+ // [Step2]: Swipe left to back to imeTestApp task
+ val displayBounds = WindowUtils.getDisplayBounds(testSpec.config.startRotation)
+ val displayCenterX = displayBounds.bounds.width() / 2
+ device.swipe(displayBounds.bounds.width(), displayBounds.bounds.height(),
+ displayCenterX, displayBounds.bounds.height(), 20)
+ wmHelper.waitForFullScreenApp(imeTestApp.component)
+ }
+ }
+ }
+
+ @FlakyTest
+ @Test
+ fun imeAppWindowIsAlwaysVisible() = testSpec.imeAppWindowIsAlwaysVisible(imeTestApp)
+
+ @FlakyTest
+ @Test
+ fun imeLayerBecomesVisible() = testSpec.imeLayerBecomesVisible()
+
+ @FlakyTest
+ @Test
+ fun imeLayerBecomesInvisible() = testSpec.imeLayerBecomesInvisible()
+
+ @Presubmit
+ @Test
+ fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
+
+ @FlakyTest
+ @Test
+ fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
+
+ @FlakyTest
+ @Test
+ fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): Collection<FlickerTestParameter> {
+ return FlickerTestParameterFactory.getInstance()
+ .getConfigNonRotationTests(
+ repetitions = 3,
+ supportedNavigationModes = listOf(
+ WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY,
+ WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY
+ )
+ )
+ }
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/CommonAssertions.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/CommonAssertions.kt
new file mode 100644
index 000000000000..01e34d9f8f97
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/CommonAssertions.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2020 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.wm.flicker.launch
+
+import android.platform.helpers.IAppHelper
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.HOME_WINDOW_TITLE
+
+fun FlickerTestParameter.appWindowReplacesLauncherAsTopWindow(testApp: IAppHelper) {
+ assertWm {
+ this.showsAppWindowOnTop(*HOME_WINDOW_TITLE)
+ .then()
+ .showsAppWindowOnTop("Snapshot", testApp.getPackage())
+ }
+} \ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
new file mode 100644
index 000000000000..9ff0bdfe66ba
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2020 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.wm.flicker.launch
+
+import androidx.test.filters.FlakyTest
+import androidx.test.filters.RequiresDevice
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.annotation.Group1
+import com.android.server.wm.flicker.helpers.setRotation
+import com.android.server.wm.flicker.startRotation
+import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.rules.RemoveAllTasksButHomeRule.Companion.removeAllTasksButHome
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test cold launch app from launcher.
+ * To run this test: `atest FlickerTests:OpenAppColdTest`
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group1
+class OpenAppColdTest(testSpec: FlickerTestParameter) : OpenAppTransition(testSpec) {
+ override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
+ get() = {
+ super.transition(this, it)
+ setup {
+ eachRun {
+ removeAllTasksButHome()
+ this.setRotation(testSpec.config.startRotation)
+ }
+ }
+ teardown {
+ eachRun {
+ testApp.exit(wmHelper)
+ }
+ }
+ transitions {
+ testApp.launchViaIntent(wmHelper)
+ wmHelper.waitForFullScreenApp(testApp.component)
+ }
+ }
+
+ @FlakyTest
+ @Test
+ override fun visibleLayersShownMoreThanOneConsecutiveEntry() {
+ super.visibleLayersShownMoreThanOneConsecutiveEntry()
+ }
+
+ @FlakyTest
+ @Test
+ override fun navBarLayerIsAlwaysVisible() {
+ super.navBarLayerIsAlwaysVisible()
+ }
+
+ @FlakyTest
+ @Test
+ override fun navBarLayerRotatesAndScales() {
+ super.navBarLayerRotatesAndScales()
+ }
+
+ @FlakyTest
+ @Test
+ override fun statusBarLayerIsAlwaysVisible() {
+ super.statusBarLayerIsAlwaysVisible()
+ }
+
+ @FlakyTest
+ @Test
+ override fun appLayerReplacesLauncher() {
+ super.appLayerReplacesLauncher()
+ }
+
+ @FlakyTest
+ @Test
+ override fun appWindowReplacesLauncherAsTopWindow() {
+ super.appWindowReplacesLauncherAsTopWindow()
+ }
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): Collection<FlickerTestParameter> {
+ return FlickerTestParameterFactory.getInstance()
+ .getConfigNonRotationTests()
+ }
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
new file mode 100644
index 000000000000..b073a7ca1495
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2020 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.wm.flicker.launch
+
+import androidx.test.filters.FlakyTest
+import androidx.test.filters.RequiresDevice
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.annotation.Group1
+import com.android.server.wm.flicker.helpers.reopenAppFromOverview
+import com.android.server.wm.flicker.helpers.setRotation
+import com.android.server.wm.flicker.startRotation
+import com.android.server.wm.flicker.dsl.FlickerBuilder
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Launch an app from the recents app view (the overview)
+ * To run this test: `atest FlickerTests:OpenAppFromOverviewTest`
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group1
+class OpenAppFromOverviewTest(testSpec: FlickerTestParameter) : OpenAppTransition(testSpec) {
+ override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
+ get() = {
+ super.transition(this, it)
+ setup {
+ test {
+ testApp.launchViaIntent(wmHelper)
+ }
+ eachRun {
+ device.pressHome()
+ wmHelper.waitForAppTransitionIdle()
+ device.pressRecentApps()
+ wmHelper.waitForAppTransitionIdle()
+ this.setRotation(testSpec.config.startRotation)
+ }
+ }
+ transitions {
+ device.reopenAppFromOverview(wmHelper)
+ wmHelper.waitForFullScreenApp(testApp.component)
+ }
+ }
+
+ @FlakyTest
+ @Test
+ override fun navBarLayerIsAlwaysVisible() {
+ super.navBarLayerIsAlwaysVisible()
+ }
+
+ @FlakyTest
+ @Test
+ override fun statusBarLayerIsAlwaysVisible() {
+ super.statusBarLayerIsAlwaysVisible()
+ }
+
+ @FlakyTest
+ @Test
+ override fun navBarLayerRotatesAndScales() {
+ super.navBarLayerRotatesAndScales()
+ }
+
+ @FlakyTest
+ @Test
+ override fun statusBarLayerRotatesScales() {
+ super.statusBarLayerRotatesScales()
+ }
+
+ @FlakyTest
+ @Test
+ override fun visibleLayersShownMoreThanOneConsecutiveEntry() {
+ super.visibleLayersShownMoreThanOneConsecutiveEntry()
+ }
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): Collection<FlickerTestParameter> {
+ return FlickerTestParameterFactory.getInstance()
+ .getConfigNonRotationTests(repetitions = 5)
+ }
+ }
+} \ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt
new file mode 100644
index 000000000000..b304d5f999df
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt
@@ -0,0 +1,154 @@
+/*
+ * 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.server.wm.flicker.launch
+
+import android.app.Instrumentation
+import android.platform.test.annotations.Presubmit
+import android.view.Surface
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.server.wm.flicker.FlickerBuilderProvider
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.appLayerReplacesLauncher
+import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.endRotation
+import com.android.server.wm.flicker.focusChanges
+import com.android.server.wm.flicker.helpers.SimpleAppHelper
+import com.android.server.wm.flicker.helpers.StandardAppHelper
+import com.android.server.wm.flicker.helpers.setRotation
+import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
+import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.navBarLayerRotatesAndScales
+import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.noUncoveredRegions
+import com.android.server.wm.flicker.repetitions
+import com.android.server.wm.flicker.startRotation
+import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarLayerRotatesScales
+import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.launcherWindowBecomesInvisible
+import org.junit.Test
+
+abstract class OpenAppTransition(protected val testSpec: FlickerTestParameter) {
+ protected val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ protected val testApp: StandardAppHelper = SimpleAppHelper(instrumentation)
+
+ protected open val transition: FlickerBuilder.(Map<String, Any?>) -> Unit = {
+ withTestName { testSpec.name }
+ repeat { testSpec.config.repetitions }
+ setup {
+ test {
+ device.wakeUpAndGoToHomeScreen()
+ this.setRotation(testSpec.config.startRotation)
+ }
+ }
+ teardown {
+ test {
+ testApp.exit()
+ }
+ }
+ }
+
+ @FlickerBuilderProvider
+ fun buildFlicker(): FlickerBuilder {
+ return FlickerBuilder(instrumentation).apply {
+ transition(testSpec.config)
+ }
+ }
+
+ @Presubmit
+ @Test
+ open fun navBarWindowIsAlwaysVisible() {
+ testSpec.navBarWindowIsAlwaysVisible()
+ }
+
+ @Presubmit
+ @Test
+ open fun navBarLayerIsAlwaysVisible() {
+ testSpec.navBarLayerIsAlwaysVisible(rotatesScreen = testSpec.isRotated)
+ }
+
+ @Presubmit
+ @Test
+ open fun navBarLayerRotatesAndScales() {
+ testSpec.navBarLayerRotatesAndScales(Surface.ROTATION_0, testSpec.config.endRotation)
+ }
+
+ @Presubmit
+ @Test
+ open fun statusBarWindowIsAlwaysVisible() {
+ testSpec.statusBarWindowIsAlwaysVisible()
+ }
+
+ @Presubmit
+ @Test
+ open fun statusBarLayerIsAlwaysVisible() {
+ testSpec.statusBarLayerIsAlwaysVisible(rotatesScreen = testSpec.isRotated)
+ }
+
+ @Presubmit
+ @Test
+ open fun statusBarLayerRotatesScales() {
+ testSpec.statusBarLayerRotatesScales(Surface.ROTATION_0, testSpec.config.endRotation)
+ }
+
+ @Presubmit
+ @Test
+ open fun visibleWindowsShownMoreThanOneConsecutiveEntry() {
+ testSpec.assertWm {
+ this.visibleWindowsShownMoreThanOneConsecutiveEntry()
+ }
+ }
+
+ @Presubmit
+ @Test
+ open fun visibleLayersShownMoreThanOneConsecutiveEntry() {
+ testSpec.assertLayers {
+ this.visibleLayersShownMoreThanOneConsecutiveEntry()
+ }
+ }
+
+ @Presubmit
+ @Test
+ // During testing the launcher is always in portrait mode
+ open fun noUncoveredRegions() {
+ testSpec.noUncoveredRegions(Surface.ROTATION_0, testSpec.config.endRotation)
+ }
+
+ @Presubmit
+ @Test
+ open fun focusChanges() {
+ testSpec.focusChanges("NexusLauncherActivity", testApp.`package`)
+ }
+
+ @Presubmit
+ @Test
+ open fun appLayerReplacesLauncher() {
+ testSpec.appLayerReplacesLauncher(testApp.`package`)
+ }
+
+ @Presubmit
+ @Test
+ open fun appWindowReplacesLauncherAsTopWindow() {
+ testSpec.appWindowReplacesLauncherAsTopWindow(testApp)
+ }
+
+ @Presubmit
+ @Test
+ open fun launcherWindowBecomesInvisible() {
+ testSpec.launcherWindowBecomesInvisible()
+ }
+} \ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
new file mode 100644
index 000000000000..e2705c764917
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2020 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.wm.flicker.launch
+
+import androidx.test.filters.FlakyTest
+import androidx.test.filters.RequiresDevice
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.annotation.Group1
+import com.android.server.wm.flicker.helpers.setRotation
+import com.android.server.wm.flicker.startRotation
+import com.android.server.wm.flicker.dsl.FlickerBuilder
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test warm launch app.
+ * To run this test: `atest FlickerTests:OpenAppWarmTest`
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group1
+class OpenAppWarmTest(testSpec: FlickerTestParameter) : OpenAppTransition(testSpec) {
+ override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
+ get() = {
+ super.transition(this, it)
+ setup {
+ test {
+ testApp.launchViaIntent(wmHelper)
+ }
+ eachRun {
+ device.pressHome()
+ wmHelper.waitForHomeActivityVisible()
+ this.setRotation(testSpec.config.startRotation)
+ }
+ }
+ teardown {
+ eachRun {
+ testApp.exit(wmHelper)
+ }
+ }
+ transitions {
+ testApp.launchViaIntent(wmHelper)
+ wmHelper.waitForFullScreenApp(testApp.component)
+ }
+ }
+
+ @FlakyTest
+ @Test
+ override fun navBarLayerIsAlwaysVisible() {
+ super.navBarLayerIsAlwaysVisible()
+ }
+
+ @FlakyTest
+ @Test
+ override fun navBarLayerRotatesAndScales() {
+ super.navBarLayerRotatesAndScales()
+ }
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): Collection<FlickerTestParameter> {
+ return FlickerTestParameterFactory.getInstance()
+ .getConfigNonRotationTests()
+ }
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
new file mode 100644
index 000000000000..69e8a8d08e58
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2020 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.wm.flicker.rotation
+
+import android.platform.test.annotations.Postsubmit
+import android.platform.test.annotations.Presubmit
+import androidx.test.filters.FlakyTest
+import androidx.test.filters.RequiresDevice
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.annotation.Group3
+import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.helpers.SimpleAppHelper
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Cycle through supported app rotations.
+ * To run this test: `atest FlickerTests:ChangeAppRotationTest`
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group3
+class ChangeAppRotationTest(
+ testSpec: FlickerTestParameter
+) : RotationTransition(testSpec) {
+ override val testApp = SimpleAppHelper(instrumentation)
+ override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
+ get() = {
+ super.transition(this, it)
+ setup {
+ test {
+ testApp.launchViaIntent(wmHelper)
+ }
+ }
+ }
+
+ @FlakyTest(bugId = 190185577)
+ @Test
+ override fun focusDoesNotChange() {
+ super.focusDoesNotChange()
+ }
+
+ @Postsubmit
+ @Test
+ fun screenshotLayerBecomesInvisible() {
+ testSpec.assertLayers {
+ this.isVisible(testApp.getPackage())
+ .then()
+ .isVisible(SCREENSHOT_LAYER)
+ .then()
+ .isVisible(testApp.getPackage())
+ }
+ }
+
+ @Postsubmit
+ @Test
+ override fun statusBarLayerRotatesScales() {
+ super.statusBarLayerRotatesScales()
+ }
+
+ @Presubmit
+ @Test
+ override fun navBarWindowIsAlwaysVisible() {
+ super.navBarWindowIsAlwaysVisible()
+ }
+
+ @FlakyTest
+ @Test
+ override fun statusBarLayerIsAlwaysVisible() {
+ super.statusBarLayerIsAlwaysVisible()
+ }
+
+ companion object {
+ private const val SCREENSHOT_LAYER = "RotationLayer"
+
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): Collection<FlickerTestParameter> {
+ return FlickerTestParameterFactory.getInstance()
+ .getConfigRotationTests(repetitions = 5)
+ }
+ }
+} \ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/RotationTransition.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/RotationTransition.kt
new file mode 100644
index 000000000000..4b888cd5aad0
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/RotationTransition.kt
@@ -0,0 +1,159 @@
+/*
+ * 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.server.wm.flicker.rotation
+
+import android.app.Instrumentation
+import android.platform.test.annotations.Presubmit
+import androidx.test.filters.FlakyTest
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.server.wm.flicker.FlickerBuilderProvider
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.endRotation
+import com.android.server.wm.flicker.focusDoesNotChange
+import com.android.server.wm.flicker.helpers.StandardAppHelper
+import com.android.server.wm.flicker.helpers.WindowUtils
+import com.android.server.wm.flicker.helpers.setRotation
+import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.navBarLayerRotatesAndScales
+import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.noUncoveredRegions
+import com.android.server.wm.flicker.startRotation
+import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarLayerRotatesScales
+import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
+import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
+import org.junit.Test
+
+abstract class RotationTransition(protected val testSpec: FlickerTestParameter) {
+ protected abstract val testApp: StandardAppHelper
+
+ protected val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ protected val startingPos get() = WindowUtils.getDisplayBounds(testSpec.config.startRotation)
+ protected val endingPos get() = WindowUtils.getDisplayBounds(testSpec.config.endRotation)
+
+ protected open val transition: FlickerBuilder.(Map<String, Any?>) -> Unit = {
+ setup {
+ eachRun {
+ this.setRotation(testSpec.config.startRotation)
+ }
+ }
+ teardown {
+ test {
+ testApp.exit()
+ }
+ }
+ transitions {
+ this.setRotation(testSpec.config.endRotation)
+ }
+ }
+
+ @FlickerBuilderProvider
+ fun buildFlicker(): FlickerBuilder {
+ return FlickerBuilder(instrumentation).apply {
+ transition(testSpec.config)
+ }
+ }
+
+ @FlakyTest
+ @Test
+ open fun navBarWindowIsAlwaysVisible() {
+ testSpec.navBarWindowIsAlwaysVisible()
+ }
+
+ @FlakyTest
+ @Test
+ open fun navBarLayerIsAlwaysVisible() {
+ testSpec.navBarLayerIsAlwaysVisible(rotatesScreen = true)
+ }
+
+ @FlakyTest
+ @Test
+ open fun navBarLayerRotatesAndScales() {
+ testSpec.navBarLayerRotatesAndScales(
+ testSpec.config.startRotation, testSpec.config.endRotation)
+ }
+
+ @Presubmit
+ @Test
+ open fun statusBarWindowIsAlwaysVisible() {
+ testSpec.statusBarWindowIsAlwaysVisible()
+ }
+
+ @FlakyTest
+ @Test
+ open fun statusBarLayerIsAlwaysVisible() {
+ testSpec.statusBarLayerIsAlwaysVisible(rotatesScreen = true)
+ }
+
+ @FlakyTest
+ @Test
+ open fun statusBarLayerRotatesScales() {
+ testSpec.statusBarLayerRotatesScales(
+ testSpec.config.startRotation, testSpec.config.endRotation)
+ }
+
+ @FlakyTest
+ @Test
+ open fun visibleLayersShownMoreThanOneConsecutiveEntry() {
+ testSpec.assertLayers {
+ this.visibleLayersShownMoreThanOneConsecutiveEntry(
+ ignoreLayers = listOf(WindowManagerStateHelper.SPLASH_SCREEN_NAME,
+ WindowManagerStateHelper.SNAPSHOT_WINDOW_NAME,
+ "SecondaryHomeHandle"
+ )
+ )
+ }
+ }
+
+ @Presubmit
+ @Test
+ open fun visibleWindowsShownMoreThanOneConsecutiveEntry() {
+ testSpec.assertWm {
+ this.visibleWindowsShownMoreThanOneConsecutiveEntry()
+ }
+ }
+
+ @Presubmit
+ @Test
+ open fun noUncoveredRegions() {
+ testSpec.noUncoveredRegions(testSpec.config.startRotation,
+ testSpec.config.endRotation, allStates = false)
+ }
+
+ @Presubmit
+ @Test
+ open fun focusDoesNotChange() {
+ testSpec.focusDoesNotChange()
+ }
+
+ @Presubmit
+ @Test
+ open fun appLayerRotates_StartingPos() {
+ testSpec.assertLayersStart {
+ this.visibleRegion(testApp.getPackage()).coversExactly(startingPos)
+ }
+ }
+
+ @Presubmit
+ @Test
+ open fun appLayerRotates_EndingPos() {
+ testSpec.assertLayersEnd {
+ this.visibleRegion(testApp.getPackage()).coversExactly(endingPos)
+ }
+ }
+} \ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
new file mode 100644
index 000000000000..b153bece1133
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2020 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.wm.flicker.rotation
+
+import android.platform.test.annotations.Postsubmit
+import android.platform.test.annotations.Presubmit
+import androidx.test.filters.FlakyTest
+import androidx.test.filters.RequiresDevice
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.annotation.Group3
+import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.helpers.SeamlessRotationAppHelper
+import com.android.server.wm.flicker.testapp.ActivityOptions
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Cycle through supported app rotations using seamless rotations.
+ * To run this test: `atest FlickerTests:SeamlessAppRotationTest`
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group3
+class SeamlessAppRotationTest(
+ testSpec: FlickerTestParameter
+) : RotationTransition(testSpec) {
+ override val testApp = SeamlessRotationAppHelper(instrumentation)
+
+ override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
+ get() = {
+ super.transition(this, it)
+ setup {
+ test {
+ testApp.launchViaIntent(wmHelper,
+ stringExtras = mapOf(
+ ActivityOptions.EXTRA_STARVE_UI_THREAD to it.starveUiThread.toString())
+ )
+ }
+ }
+ }
+
+ @FlakyTest(bugId = 140855415)
+ @Test
+ override fun statusBarWindowIsAlwaysVisible() {
+ super.statusBarWindowIsAlwaysVisible()
+ }
+
+ @FlakyTest(bugId = 140855415)
+ @Test
+ override fun statusBarLayerIsAlwaysVisible() {
+ super.statusBarLayerIsAlwaysVisible()
+ }
+
+ @Presubmit
+ @Test
+ fun appLayerAlwaysVisible() {
+ testSpec.assertLayers {
+ isVisible(testApp.`package`)
+ }
+ }
+
+ @FlakyTest(bugId = 185400889)
+ @Test
+ fun appLayerRotates() {
+ testSpec.assertLayers {
+ this.coversExactly(startingPos, testApp.`package`)
+ .then()
+ .coversExactly(endingPos, testApp.`package`)
+ }
+ }
+
+ @Postsubmit
+ @Test
+ override fun visibleLayersShownMoreThanOneConsecutiveEntry() {
+ super.visibleLayersShownMoreThanOneConsecutiveEntry()
+ }
+
+ companion object {
+ private val testFactory = FlickerTestParameterFactory.getInstance()
+
+ private val Map<String, Any?>.starveUiThread
+ get() = this.getOrDefault(ActivityOptions.EXTRA_STARVE_UI_THREAD, false) as Boolean
+
+ private fun FlickerTestParameter.createConfig(
+ starveUiThread: Boolean
+ ): MutableMap<String, Any?> {
+ val config = this.config.toMutableMap()
+ config[ActivityOptions.EXTRA_STARVE_UI_THREAD] = starveUiThread
+ return config
+ }
+
+ @JvmStatic
+ private fun getConfigurations(): List<FlickerTestParameter> {
+ return testFactory.getConfigRotationTests(repetitions = 2).flatMap {
+ val defaultRun = it.createConfig(starveUiThread = false)
+ val busyUiRun = it.createConfig(starveUiThread = true)
+ listOf(
+ FlickerTestParameter(defaultRun),
+ FlickerTestParameter(busyUiRun,
+ name = "${FlickerTestParameter.defaultName(busyUiRun)}_BUSY_UI_THREAD"
+ )
+ )
+ }
+ }
+
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): Collection<FlickerTestParameter> {
+ return getConfigurations()
+ }
+ }
+}
diff --git a/tests/FlickerTests/test-apps/flickerapp/Android.bp b/tests/FlickerTests/test-apps/flickerapp/Android.bp
index 1d5f732ed04f..78660c04d8d4 100644
--- a/tests/FlickerTests/test-apps/flickerapp/Android.bp
+++ b/tests/FlickerTests/test-apps/flickerapp/Android.bp
@@ -28,7 +28,7 @@ android_test {
test_suites: ["device-tests"],
}
-java_test {
+java_library {
name: "flickertestapplib",
sdk_version: "current",
srcs: ["src/com/android/server/wm/flicker/testapp/ActivityOptions.java"],
diff --git a/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml b/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
index 0fe968273567..1599ed4b280f 100644
--- a/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
+++ b/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
@@ -14,60 +14,50 @@
limitations under the License.
-->
-<manifest
- xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.server.wm.flicker.testapp">
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.server.wm.flicker.testapp">
- <uses-sdk android:minSdkVersion="17" android:targetSdkVersion="27"/>
- <application
- android:allowBackup="false"
- android:supportsRtl="true">
+ <uses-sdk android:minSdkVersion="29"
+ android:targetSdkVersion="29"/>
+ <application android:allowBackup="false"
+ android:supportsRtl="true">
<activity android:name=".SimpleActivity"
- android:taskAffinity="com.android.server.wm.flicker.testapp.SimpleActivity"
- android:label="SimpleApp">
+ android:taskAffinity="com.android.server.wm.flicker.testapp.SimpleActivity"
+ android:label="SimpleApp"
+ android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:name=".ImeActivity"
- android:taskAffinity="com.android.server.wm.flicker.testapp.ImeActivity"
- android:label="ImeApp">
+ android:taskAffinity="com.android.server.wm.flicker.testapp.ImeActivity"
+ android:label="ImeApp"
+ android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:name=".ImeActivityAutoFocus"
- android:taskAffinity="com.android.server.wm.flicker.testapp.ImeActivityAutoFocus"
- android:windowSoftInputMode="stateVisible"
- android:label="ImeAppAutoFocus">
- <intent-filter>
- <action android:name="android.intent.action.MAIN"/>
- <category android:name="android.intent.category.LAUNCHER"/>
- </intent-filter>
- </activity>
- <activity android:name=".PipActivity"
- android:resizeableActivity="true"
- android:supportsPictureInPicture="true"
- android:configChanges=
- "screenSize|smallestScreenSize|screenLayout|orientation"
- android:taskAffinity="com.android.server.wm.flicker.testapp.PipActivity"
- android:label="PipApp">
+ android:taskAffinity="com.android.server.wm.flicker.testapp.ImeActivityAutoFocus"
+ android:windowSoftInputMode="stateVisible"
+ android:label="ImeAppAutoFocus"
+ android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:name=".SeamlessRotationActivity"
- android:taskAffinity=
- "com.android.server.wm.flicker.testapp.SeamlessRotationActivity"
- android:configChanges="orientation|screenSize"
- android:label="SeamlessApp">
+ android:taskAffinity="com.android.server.wm.flicker.testapp.SeamlessRotationActivity"
+ android:configChanges="orientation|screenSize"
+ android:label="SeamlessApp"
+ android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
-</manifest> \ No newline at end of file
+</manifest>
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java
index 18994111324e..0ccc49897202 100644
--- a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java
@@ -20,7 +20,25 @@ import android.content.ComponentName;
public class ActivityOptions {
public static final String EXTRA_STARVE_UI_THREAD = "StarveUiThread";
+ public static final String FLICKER_APP_PACKAGE = "com.android.server.wm.flicker.testapp";
+
+ public static final String SEAMLESS_ACTIVITY_LAUNCHER_NAME = "SeamlessApp";
public static final ComponentName SEAMLESS_ACTIVITY_COMPONENT_NAME =
- new ComponentName("com.android.server.wm.flicker.testapp",
- "com.android.server.wm.flicker.testapp.SeamlessRotationActivity");
+ new ComponentName(FLICKER_APP_PACKAGE,
+ FLICKER_APP_PACKAGE + ".SeamlessRotationActivity");
+
+ public static final String IME_ACTIVITY_AUTO_FOCUS_LAUNCHER_NAME = "ImeAppAutoFocus";
+ public static final ComponentName IME_ACTIVITY_AUTO_FOCUS_COMPONENT_NAME =
+ new ComponentName(FLICKER_APP_PACKAGE,
+ FLICKER_APP_PACKAGE + ".ImeActivityAutoFocus");
+
+ public static final String IME_ACTIVITY_LAUNCHER_NAME = "ImeActivity";
+ public static final ComponentName IME_ACTIVITY_COMPONENT_NAME =
+ new ComponentName(FLICKER_APP_PACKAGE,
+ FLICKER_APP_PACKAGE + ".ImeActivity");
+
+ public static final String SIMPLE_ACTIVITY_LAUNCHER_NAME = "SimpleApp";
+ public static final ComponentName SIMPLE_ACTIVITY_AUTO_FOCUS_COMPONENT_NAME =
+ new ComponentName(FLICKER_APP_PACKAGE,
+ FLICKER_APP_PACKAGE + ".SimpleActivity");
}
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/PipActivity.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/PipActivity.java
deleted file mode 100644
index 9a8f39907877..000000000000
--- a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/PipActivity.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2018 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.wm.flicker.testapp;
-
-import android.app.Activity;
-import android.app.PictureInPictureParams;
-import android.graphics.Rect;
-import android.os.Bundle;
-import android.util.Rational;
-import android.view.WindowManager;
-import android.widget.Button;
-
-public class PipActivity extends Activity {
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- WindowManager.LayoutParams p = getWindow().getAttributes();
- p.layoutInDisplayCutoutMode = WindowManager.LayoutParams
- .LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
- getWindow().setAttributes(p);
- setContentView(R.layout.activity_pip);
- Button enterPip = (Button) findViewById(R.id.enter_pip);
-
- PictureInPictureParams params = new PictureInPictureParams.Builder()
- .setAspectRatio(new Rational(1, 1))
- .setSourceRectHint(new Rect(0, 0, 100, 100))
- .build();
-
- enterPip.setOnClickListener((v) -> enterPictureInPictureMode(params));
- }
-}
diff --git a/tests/FrameworkPerf/AndroidManifest.xml b/tests/FrameworkPerf/AndroidManifest.xml
index 4fd2043ce938..07e775aeb838 100644
--- a/tests/FrameworkPerf/AndroidManifest.xml
+++ b/tests/FrameworkPerf/AndroidManifest.xml
@@ -1,30 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.frameworkperf">
+ package="com.android.frameworkperf">
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
- <uses-permission android:name="android.permission.WAKE_LOCK" />
- <uses-sdk android:minSdkVersion="5" />
+ <uses-permission android:name="android.permission.WAKE_LOCK"/>
+ <uses-sdk android:minSdkVersion="5"/>
<application android:hardwareAccelerated="false">
- <uses-library android:name="android.test.runner" />
- <activity android:name="FrameworkPerfActivity" android:label="Framework Perf">
+ <uses-library android:name="android.test.runner"/>
+ <activity android:name="FrameworkPerfActivity"
+ android:label="Framework Perf"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<service android:name="SchedulerService"
- android:foregroundServiceType="dataSync|mediaPlayback|phoneCall|location|connectedDevice">
+ android:foregroundServiceType="dataSync|mediaPlayback|phoneCall|location|connectedDevice">
</service>
- <service android:name="TestService" android:process=":test">
+ <service android:name="TestService"
+ android:process=":test">
</service>
<service android:name="LocalTestService">
</service>
- <receiver android:name="Receiver" android:exported="true">
+ <receiver android:name="Receiver"
+ android:exported="true">
</receiver>
</application>
<instrumentation android:name="android.test.InstrumentationTestRunner"
- android:targetPackage="com.android.frameworkperf"
- android:label="Framework Perf Runner"
- />
+ android:targetPackage="com.android.frameworkperf"
+ android:label="Framework Perf Runner"/>
</manifest>
diff --git a/tests/FrameworkPerf/src/com/android/frameworkperf/SchedulerService.java b/tests/FrameworkPerf/src/com/android/frameworkperf/SchedulerService.java
index d4cbbf9c8271..11a26d6c727a 100644
--- a/tests/FrameworkPerf/src/com/android/frameworkperf/SchedulerService.java
+++ b/tests/FrameworkPerf/src/com/android/frameworkperf/SchedulerService.java
@@ -41,7 +41,7 @@ public class SchedulerService extends Service {
new Intent(this, FrameworkPerfActivity.class)
.setAction(Intent.ACTION_MAIN)
.addCategory(Intent.CATEGORY_LAUNCHER)
- .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK), 0))
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK), PendingIntent.FLAG_MUTABLE_UNAUDITED))
.setOngoing(true)
.build();
startForeground(1, status);
diff --git a/tests/GamePerformance/Android.bp b/tests/GamePerformance/Android.bp
index 07d0f42e8df2..f250a1bbdaca 100644
--- a/tests/GamePerformance/Android.bp
+++ b/tests/GamePerformance/Android.bp
@@ -31,7 +31,7 @@ android_test_helper_app {
enabled: false,
},
srcs: ["src/**/*.java"],
- static_libs: ["android-support-test"],
+ static_libs: ["androidx.test.rules"],
libs: [
"android.test.base",
"android.test.runner",
diff --git a/tests/GamePerformance/AndroidManifest.xml b/tests/GamePerformance/AndroidManifest.xml
index 2ff7fa65664e..8e6054bca0d8 100644
--- a/tests/GamePerformance/AndroidManifest.xml
+++ b/tests/GamePerformance/AndroidManifest.xml
@@ -16,28 +16,30 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="android.gameperformance"
- android:versionCode="3"
- android:versionName="3.0" >
+ package="android.gameperformance"
+ android:versionCode="3"
+ android:versionName="3.0">
<uses-sdk android:minSdkVersion="25"/>
- <uses-feature android:glEsVersion="0x00020000" android:required="true" />
+ <uses-feature android:glEsVersion="0x00020000"
+ android:required="true"/>
- <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<application android:theme="@style/noeffects">
- <uses-library android:name="android.test.runner" />
+ <uses-library android:name="android.test.runner"/>
<activity android:name="android.gameperformance.GamePerformanceActivity"
- android:screenOrientation="landscape" >
+ android:screenOrientation="landscape"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <uses-library android:name="android.test.runner" />
+ <uses-library android:name="android.test.runner"/>
</application>
<!-- self-instrumenting test package. -->
<instrumentation android:name="android.test.InstrumentationTestRunner"
- android:targetPackage="android.gameperformance">
+ android:targetPackage="android.gameperformance">
</instrumentation>
</manifest>
diff --git a/tests/GridLayoutTest/AndroidManifest.xml b/tests/GridLayoutTest/AndroidManifest.xml
index 677220db8a53..6fdcda3e6ce7 100644
--- a/tests/GridLayoutTest/AndroidManifest.xml
+++ b/tests/GridLayoutTest/AndroidManifest.xml
@@ -15,76 +15,96 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.test.layout">
+ package="com.android.test.layout">
<uses-permission android:name="android.permission.INTERNET"/>
<uses-sdk android:minSdkVersion="11"/>
<application>
- <activity android:name="Activity0" android:label="Activity0">
+ <activity android:name="Activity0"
+ android:label="Activity0"
+ android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="Activity1" android:label="Activity1">
+ <activity android:name="Activity1"
+ android:label="Activity1"
+ android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="Activity4" android:label="Activity4">
+ <activity android:name="Activity4"
+ android:label="Activity4"
+ android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="Activity5" android:label="Activity5">
+ <activity android:name="Activity5"
+ android:label="Activity5"
+ android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="Activity6" android:label="Activity6">
+ <activity android:name="Activity6"
+ android:label="Activity6"
+ android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="Activity7" android:label="Activity7">
+ <activity android:name="Activity7"
+ android:label="Activity7"
+ android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="AlignmentTest" android:label="AlignmentTest">
+ <activity android:name="AlignmentTest"
+ android:label="AlignmentTest"
+ android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="LinearLayoutTest" android:label="LinearLayoutTest">
+ <activity android:name="LinearLayoutTest"
+ android:label="LinearLayoutTest"
+ android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="GridLayoutTest" android:label="GridLayoutTest">
+ <activity android:name="GridLayoutTest"
+ android:label="GridLayoutTest"
+ android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="LayoutInsetsTest" android:label="LayoutInsetsTest">
+ <activity android:name="LayoutInsetsTest"
+ android:label="LayoutInsetsTest"
+ android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
diff --git a/tests/HierarchyViewerTest/AndroidManifest.xml b/tests/HierarchyViewerTest/AndroidManifest.xml
index 65f2fd3e1a9c..f4414b0c4d00 100644
--- a/tests/HierarchyViewerTest/AndroidManifest.xml
+++ b/tests/HierarchyViewerTest/AndroidManifest.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2015 The Android Open Source Project
~
@@ -15,22 +16,21 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.test.hierarchyviewer">
+ package="com.android.test.hierarchyviewer">
<application>
- <uses-library android:name="android.test.runner" />
+ <uses-library android:name="android.test.runner"/>
- <activity
- android:name=".MainActivity"
- android:label="HvTest" >
+ <activity android:name=".MainActivity"
+ android:label="HvTest"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
- <instrumentation
- android:name="android.test.InstrumentationTestRunner"
- android:targetPackage="com.android.test.hierarchyviewer" />
+ <instrumentation android:name="android.test.InstrumentationTestRunner"
+ android:targetPackage="com.android.test.hierarchyviewer"/>
</manifest>
diff --git a/tests/HugeBackup/AndroidManifest.xml b/tests/HugeBackup/AndroidManifest.xml
index 923881b9b0b0..945e59bd36ed 100644
--- a/tests/HugeBackup/AndroidManifest.xml
+++ b/tests/HugeBackup/AndroidManifest.xml
@@ -13,30 +13,32 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-
<!-- Declare the contents of this Android application. The namespace
attribute brings in the Android platform namespace, and the package
supplies a unique name for the application. When writing your
own application, the package name must be changed from "com.example.*"
to come from a domain that you own or have control over. -->
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.hugebackup"
- android:versionCode="1"
- android:versionName="1.0">
+ package="com.android.hugebackup"
+ android:versionCode="1"
+ android:versionName="1.0">
<!-- The backup/restore mechanism was introduced in API version 8 -->
- <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="8" />
+ <uses-sdk android:minSdkVersion="8"
+ android:targetSdkVersion="8"/>
<application android:label="Huge Backup"
- android:backupAgent="HugeAgent">
+ android:backupAgent="HugeAgent">
<meta-data android:name="com.google.android.backup.api_key"
- android:value="AEdPqrEAAAAINyoagzQOEEpIH3yw7LYCFN7CRX4FMd6TGIGVaA" />
+ android:value="AEdPqrEAAAAINyoagzQOEEpIH3yw7LYCFN7CRX4FMd6TGIGVaA"/>
- <activity android:name="HugeBackupActivity">
+ <activity android:name="HugeBackupActivity"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml
index 7b8c154dea1e..04a55d6038b0 100644
--- a/tests/HwAccelerationTest/AndroidManifest.xml
+++ b/tests/HwAccelerationTest/AndroidManifest.xml
@@ -15,1045 +15,1107 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.test.hwui">
+ package="com.android.test.hwui">
- <uses-permission android:name="android.permission.INTERNET" />
- <uses-permission android:name="android.permission.CAMERA" />
- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.INTERNET"/>
+ <uses-permission android:name="android.permission.CAMERA"/>
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
- <uses-feature android:name="android.hardware.camera" />
- <uses-feature android:name="android.hardware.camera.autofocus" />
+ <uses-feature android:name="android.hardware.camera"/>
+ <uses-feature android:name="android.hardware.camera.autofocus"/>
- <uses-sdk android:minSdkVersion="21" />
+ <uses-sdk android:minSdkVersion="21"/>
- <application
- android:label="HwUi"
- android:theme="@android:style/Theme.Material.Light">
+ <application android:label="HwUi"
+ android:theme="@android:style/Theme.Material.Light">
- <activity
- android:name="HwTests"
- android:label="OpenGL Renderer Tests">
+ <activity android:name="HwTests"
+ android:label="OpenGL Renderer Tests"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity
- android:name="PathOpsActivity"
- android:label="Path/Ops">
+ <activity android:name="PathOpsActivity"
+ android:label="Path/Ops"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="AssetsAtlasActivity"
- android:label="Atlas/Framework">
+ <activity android:name="AssetsAtlasActivity"
+ android:label="Atlas/Framework"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="ScaledTextActivity"
- android:label="Text/Scaled">
+ <activity android:name="ScaledTextActivity"
+ android:label="Text/Scaled"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="Rotate3dTextActivity"
- android:label="Text/3D Rotation">
+ <activity android:name="Rotate3dTextActivity"
+ android:label="Text/3D Rotation"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="NoAATextActivity"
- android:label="Text/Aliased">
+ <activity android:name="NoAATextActivity"
+ android:label="Text/Aliased"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="ScaledPathsActivity"
- android:label="Path/Scaled">
+ <activity android:name="ScaledPathsActivity"
+ android:label="Path/Scaled"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="Alpha8BitmapActivity"
- android:label="Bitmaps/Alpha8">
+ <activity android:name="Alpha8BitmapActivity"
+ android:label="Bitmaps/Alpha8"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="MipMapActivity"
- android:label="Bitmaps/MipMap">
+ <activity android:name="MipMapActivity"
+ android:label="Bitmaps/MipMap"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="DrawIntoHwBitmapActivity"
- android:label="Bitmaps/DrawIntoHwBitmap">
+ <activity android:name="DrawIntoHwBitmapActivity"
+ android:label="Bitmaps/DrawIntoHwBitmap"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="PathOffsetActivity"
- android:label="Path/Offset">
+ <activity android:name="PathOffsetActivity"
+ android:label="Path/Offset"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="MultiLayersActivity"
- android:label="Layers/Multiple">
+ <activity android:name="MultiLayersActivity"
+ android:label="Layers/Multiple"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="TJunctionActivity"
- android:label="Layers/T-Junction">
+ <activity android:name="TJunctionActivity"
+ android:label="Layers/T-Junction"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="TextPathActivity"
- android:label="Text/As Path">
+ <activity android:name="TextPathActivity"
+ android:label="Text/As Path"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="GradientStopsActivity"
- android:label="Gradients/Multi-stops">
+ <activity android:name="GradientStopsActivity"
+ android:label="Gradients/Multi-stops"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="PaintDrawFilterActivity"
- android:label="Paint/Draw Filter">
+ <activity android:name="PaintDrawFilterActivity"
+ android:label="Paint/Draw Filter"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="BigGradientActivity"
- android:label="Gradients/Large">
+ <activity android:name="BigGradientActivity"
+ android:label="Gradients/Large"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
-
- <activity
- android:name="DatePickerActivity"
- android:label="View/DatePicker">
+
+ <activity android:name="DatePickerActivity"
+ android:label="View/DatePicker"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
+ </intent-filter>
+ </activity>
+
+ <activity android:name="ClipRegionActivity"
+ android:label="Clip/Region 1"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
+ </intent-filter>
+ </activity>
+
+ <activity android:name="ClipRegion2Activity"
+ android:label="Clip/Region 2"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
+ </intent-filter>
+ </activity>
+
+ <activity android:name="ClipRegion3Activity"
+ android:label="Clip/Region 3"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
+ </intent-filter>
+ </activity>
+
+ <activity android:name="ClipOutlineActivity"
+ android:label="Clip/Outline"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
+ </intent-filter>
+ </activity>
+
+ <activity android:name="DisplayListLayersActivity"
+ android:label="Layers/Display Lists"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
+ </intent-filter>
+ </activity>
+
+ <activity android:name="MatrixActivity"
+ android:label="Misc/Matrix"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
+ </intent-filter>
+ </activity>
+
+ <activity android:name="LooperAcceleration"
+ android:label="Misc/LooperAcceleration"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="ClipRegionActivity"
- android:label="Clip/Region 1">
+ <activity android:name="TextFadeActivity"
+ android:label="Text/Fade"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="ClipRegion2Activity"
- android:label="Clip/Region 2">
+ <activity android:name="MaxBitmapSizeActivity"
+ android:label="Bitmaps/Max Size"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="ClipRegion3Activity"
- android:label="Clip/Region 3">
+ <activity android:name="TimeDialogActivity"
+ android:label="View/TimeDialog"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="ClipOutlineActivity"
- android:label="Clip/Outline">
+ <activity android:name="ColoredShadowsActivity"
+ android:label="View/ColoredShadows"
+ android:theme="@style/ThemeColoredShadows"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="DisplayListLayersActivity"
- android:label="Layers/Display Lists">
+ <activity android:name="OpaqueActivity"
+ android:label="Window/Opaque"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="MatrixActivity"
- android:label="Misc/Matrix">
+ <activity android:name="GetBitmapActivity"
+ android:label="TextureView/Get Bitmap"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="LooperAcceleration"
- android:label="Misc/LooperAcceleration">
+ <activity android:name="PictureCaptureDemo"
+ android:label="Debug/Picture Capture"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
-
- <activity
- android:name="TextFadeActivity"
- android:label="Text/Fade">
+
+ <activity android:name="SmallCircleActivity"
+ android:label="Draw/Small Circle"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="MaxBitmapSizeActivity"
- android:label="Bitmaps/Max Size">
+ <activity android:name="ClearActivity"
+ android:label="Window/Clear"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="TimeDialogActivity"
- android:label="View/TimeDialog">
+ <activity android:name="TextureViewActivity"
+ android:label="TextureView/Camera"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="ColoredShadowsActivity"
- android:label="View/ColoredShadows"
- android:theme="@style/ThemeColoredShadows">
+ <activity android:name="GlyphCacheActivity"
+ android:label="Text/Glyph Cache"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
-
- <activity
- android:name="OpaqueActivity"
- android:label="Window/Opaque">
+
+ <activity android:name="CanvasTextureViewActivity"
+ android:label="TextureView/Canvas"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="GetBitmapActivity"
- android:label="TextureView/Get Bitmap">
+ <activity android:name="HardwareCanvasTextureViewActivity"
+ android:label="TextureView/HardwareCanvas"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="PictureCaptureDemo"
- android:label="Debug/Picture Capture">
+ <activity android:name="SingleFrameTextureViewTestActivity"
+ android:label="TextureView/SingleFrameTextureViewTest"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
-
- <activity
- android:name="SmallCircleActivity"
- android:label="Draw/Small Circle">
+
+ <activity android:name="HardwareCanvasSurfaceViewActivity"
+ android:label="SurfaceView/HardwareCanvas"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="ClearActivity"
- android:label="Window/Clear">
+ <activity android:name="MovingSurfaceViewActivity"
+ android:label="SurfaceView/Animated Movement"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="TextureViewActivity"
- android:label="TextureView/Camera">
+ <activity android:name="StretchySurfaceViewActivity"
+ android:label="SurfaceView/Stretchy Movement"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="GlyphCacheActivity"
- android:label="Text/Glyph Cache">
+ <activity android:name="ScrollingStretchSurfaceViewActivity"
+ android:label="SurfaceView/Scrolling Stretched SurfaceView"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="CanvasTextureViewActivity"
- android:label="TextureView/Canvas">
+ <activity android:name="GetBitmapSurfaceViewActivity"
+ android:label="SurfaceView/GetBitmap with Camera source"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="HardwareCanvasTextureViewActivity"
- android:label="TextureView/HardwareCanvas">
+ <activity android:name="VideoViewCaptureActivity"
+ android:label="SurfaceView/GetBitmap with Video source"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="SingleFrameTextureViewTestActivity"
- android:label="TextureView/SingleFrameTextureViewTest">
+ <activity android:name="GLTextureViewActivity"
+ android:label="TextureView/OpenGL"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="HardwareCanvasSurfaceViewActivity"
- android:label="SurfaceView/HardwareCanvas">
+ <activity android:name="BitmapMeshActivity"
+ android:label="Bitmaps/Mesh"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="MovingSurfaceViewActivity"
- android:label="SurfaceView/Animated Movement">
+ <activity android:name="BitmapMutateActivity"
+ android:label="Bitmaps/Mutate"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="GetBitmapSurfaceViewActivity"
- android:label="SurfaceView/GetBitmap with Camera source">
+ <activity android:name="BitmapMeshLayerActivity"
+ android:label="Bitmaps/Mesh in Layer"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="VideoViewCaptureActivity"
- android:label="SurfaceView/GetBitmap with Video source">
+ <activity android:name="MarqueeActivity"
+ android:label="Text/Marquee"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="GLTextureViewActivity"
- android:label="TextureView/OpenGL">
+ <activity android:name="ShapesActivity"
+ android:label="Path/Shapes"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="BitmapMeshActivity"
- android:label="Bitmaps/Mesh">
+ <activity android:name="ColoredRectsActivity"
+ android:label="Draw/Rects"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="BitmapMutateActivity"
- android:label="Bitmaps/Mutate">
+ <activity android:name="SimplePatchActivity"
+ android:label="Draw/9-Patch"
+ android:theme="@android:style/Theme.Translucent.NoTitleBar"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="BitmapMeshLayerActivity"
- android:label="Bitmaps/Mesh in Layer">
+ <activity android:name="ViewLayersActivity"
+ android:label="Layers/Views 1"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
-
- <activity
- android:name="MarqueeActivity"
- android:label="Text/Marquee">
+
+ <activity android:name="ViewLayersActivity2"
+ android:label="Layers/Views 2"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="ShapesActivity"
- android:label="Path/Shapes">
+ <activity android:name="ViewLayersActivity3"
+ android:label="Layers/Views 3"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
-
- <activity
- android:name="ColoredRectsActivity"
- android:label="Draw/Rects">
+
+ <activity android:name="ViewLayersActivity4"
+ android:label="Layers/Views 4"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="SimplePatchActivity"
- android:label="Draw/9-Patch"
- android:theme="@android:style/Theme.Translucent.NoTitleBar">
+ <activity android:name="ViewLayersActivity5"
+ android:label="Layers/Views 5"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="ViewLayersActivity"
- android:label="Layers/Views 1">
+ <activity android:name="AlphaLayersActivity"
+ android:label="Layers/Alpha"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
-
- <activity
- android:name="ViewLayersActivity2"
- android:label="Layers/Views 2">
+
+ <activity android:name="AdvancedGradientsActivity"
+ android:label="Gradients/Advanced"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
-
- <activity
- android:name="ViewLayersActivity3"
- android:label="Layers/Views 3">
+
+ <activity android:name="Bitmaps3dActivity"
+ android:label="Bitmaps/3D Rotation"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="ViewLayersActivity4"
- android:label="Layers/Views 4">
+ <activity android:name="LabelsActivity"
+ android:label="View/TextView"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
-
- <activity
- android:name="ViewLayersActivity5"
- android:label="Layers/Views 5">
+
+ <activity android:name="ViewFlipperActivity"
+ android:label="View/ViewFlipper"
+ android:theme="@android:style/Theme.Translucent.NoTitleBar"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="AlphaLayersActivity"
- android:label="Layers/Alpha">
+ <activity android:name="ResizeActivity"
+ android:label="Window/Resize"
+ android:windowSoftInputMode="adjustResize"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
-
- <activity
- android:name="AdvancedGradientsActivity"
- android:label="Gradients/Advanced">
+
+ <activity android:name="TextGammaActivity"
+ android:label="Text/Gamma"
+ android:theme="@android:style/Theme.Translucent.NoTitleBar"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
-
- <activity
- android:name="Bitmaps3dActivity"
- android:label="Bitmaps/3D Rotation">
+
+ <activity android:name="TextGammaActivity$SubGammaActivity"
+ android:label="Text/Sub Gamma"
+ android:theme="@android:style/Theme.Translucent.NoTitleBar"
+ android:hardwareAccelerated="false"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
</intent-filter>
</activity>
-
- <activity
- android:name="LabelsActivity"
- android:label="View/TextView">
+
+ <activity android:name="LayersActivity"
+ android:label="Layers/Canvas Layers"
+ android:theme="@android:style/Theme.Translucent.NoTitleBar"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="ViewFlipperActivity"
- android:label="View/ViewFlipper"
- android:theme="@android:style/Theme.Translucent.NoTitleBar">
+ <activity android:name="NewLayersActivity"
+ android:label="Layers/Overlapping Layers"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="ResizeActivity"
- android:label="Window/Resize"
- android:windowSoftInputMode="adjustResize">
+ <activity android:name="XfermodeActivity"
+ android:label="Draw/Xfermodes"
+ android:theme="@android:style/Theme.Translucent.NoTitleBar"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
-
- <activity
- android:name="TextGammaActivity"
- android:label="Text/Gamma"
- android:theme="@android:style/Theme.Translucent.NoTitleBar">
+
+ <activity android:name="BitmapsActivity"
+ android:label="Bitmaps/Draw Bitmaps"
+ android:theme="@android:style/Theme.Translucent.NoTitleBar"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="TextGammaActivity$SubGammaActivity"
- android:label="Text/Sub Gamma"
- android:theme="@android:style/Theme.Translucent.NoTitleBar"
- android:hardwareAccelerated="false">
+ <activity android:name="BitmapsSkewActivity"
+ android:label="Bitmaps/Skew"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
-
- <activity
- android:name="LayersActivity"
- android:label="Layers/Canvas Layers"
- android:theme="@android:style/Theme.Translucent.NoTitleBar">
+
+ <activity android:name="BitmapsAlphaActivity"
+ android:label="Bitmaps/Alpha"
+ android:theme="@android:style/Theme.Translucent.NoTitleBar"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="NewLayersActivity"
- android:label="Layers/Overlapping Layers">
+ <activity android:name="BitmapsRectActivity"
+ android:label="Bitmaps/Rect"
+ android:theme="@android:style/Theme.Translucent.NoTitleBar"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
-
- <activity
- android:name="XfermodeActivity"
- android:label="Draw/Xfermodes"
- android:theme="@android:style/Theme.Translucent.NoTitleBar">
+
+ <activity android:name="ThinPatchesActivity"
+ android:label="Draw/9-Patch Thin Drawable"
+ android:theme="@android:style/Theme.Translucent.NoTitleBar"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
-
- <activity
- android:name="BitmapsActivity"
- android:label="Bitmaps/Draw Bitmaps"
- android:theme="@android:style/Theme.Translucent.NoTitleBar">
+
+ <activity android:name="NinePatchesActivity"
+ android:label="Draw/9-Patch Drawable"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
-
- <activity
- android:name="BitmapsSkewActivity"
- android:label="Bitmaps/Skew">
+
+ <activity android:name="MoreNinePatchesActivity"
+ android:label="Draw/9-Patch Vertical Drawable"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="BitmapsAlphaActivity"
- android:label="Bitmaps/Alpha"
- android:theme="@android:style/Theme.Translucent.NoTitleBar">
+ <activity android:name="QuickRejectActivity"
+ android:label="Clip/QuickReject"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
-
- <activity
- android:name="BitmapsRectActivity"
- android:label="Bitmaps/Rect"
- android:theme="@android:style/Theme.Translucent.NoTitleBar">
+
+ <activity android:name="RotationActivity"
+ android:label="View/Rotation"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="ThinPatchesActivity"
- android:label="Draw/9-Patch Thin Drawable"
- android:theme="@android:style/Theme.Translucent.NoTitleBar">
+ <activity android:name="GradientsActivity"
+ android:label="Gradients/Gradients"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
-
- <activity
- android:name="NinePatchesActivity"
- android:label="Draw/9-Patch Drawable">
+
+ <activity android:name="ShadersActivity"
+ android:label="Shaders/Shaders"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="MoreNinePatchesActivity"
- android:label="Draw/9-Patch Vertical Drawable">
+ <activity android:name="BlurActivity"
+ android:label="RenderEffect/Blur"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
-
- <activity
- android:name="QuickRejectActivity"
- android:label="Clip/QuickReject">
+
+ <activity android:name="RenderEffectShaderActivity"
+ android:label="RenderEffect/Shader"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
-
- <activity
- android:name="RotationActivity"
- android:label="View/Rotation">
+
+ <activity android:name="StretchShaderActivity"
+ android:label="RenderEffect/Stretch"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
-
- <activity
- android:name="GradientsActivity"
- android:label="Gradients/Gradients">
+
+ <activity android:name="EdgeEffectStretchActivity"
+ android:label="RenderEffect/EdgeEffect stretch"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="ShadersActivity"
- android:label="Shaders/Shaders">
+ <activity android:name="TextActivity"
+ android:label="Text/Simple Text"
+ android:theme="@android:style/Theme.NoTitleBar"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
-
- <activity
- android:name="TextActivity"
- android:label="Text/Simple Text"
- android:theme="@android:style/Theme.NoTitleBar">
+
+ <activity android:name="PosTextActivity"
+ android:label="Text/Pos Text"
+ android:theme="@android:style/Theme.NoTitleBar"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="PosTextActivity"
- android:label="Text/Pos Text"
- android:theme="@android:style/Theme.NoTitleBar">
+ <activity android:name="ListActivity"
+ android:label="View/List"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="ListActivity"
- android:label="View/List">
+ <activity android:name="TransparentListActivity"
+ android:label="View/Transparent List"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="TransparentListActivity"
- android:label="View/Transparent List">
+ <activity android:name="MoreShadersActivity"
+ android:label="Shaders/Compose Shaders"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
-
- <activity
- android:name="MoreShadersActivity"
- android:label="Shaders/Compose Shaders">
+
+ <activity android:name="ColorFiltersActivity"
+ android:label="ColorFilters/Filters"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="ColorFiltersActivity"
- android:label="ColorFilters/Filters">
+ <activity android:name="ColorFiltersMutateActivity"
+ android:label="ColorFilters/Mutate Filters"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="ColorFiltersMutateActivity"
- android:label="ColorFilters/Mutate Filters">
+ <activity android:name="LinesActivity"
+ android:label="Draw/Lines"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="LinesActivity"
- android:label="Draw/Lines">
+ <activity android:name="Lines2Activity"
+ android:label="Draw/Lines 2"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="Lines2Activity"
- android:label="Draw/Lines 2">
+ <activity android:name="PathsActivity"
+ android:label="Path/Paths"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="PathsActivity"
- android:label="Path/Paths">
+ <activity android:name="TextOnPathActivity"
+ android:label="Text/Text on Path"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="TextOnPathActivity"
- android:label="Text/Text on Path">
+ <activity android:name="PathsCacheActivity"
+ android:label="Path/Cache"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>`
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="PathsCacheActivity"
- android:label="Path/Cache">
+ <activity android:name="PointsActivity"
+ android:label="Draw/Points"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />`
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="PointsActivity"
- android:label="Draw/Points">
+ <activity android:name="Transform3dActivity"
+ android:label="Draw/3D Transform"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="Transform3dActivity"
- android:label="Draw/3D Transform">
+ <activity android:name="Animated3dActivity"
+ android:label="Draw/Animated 3D Transform"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="Animated3dActivity"
- android:label="Draw/Animated 3D Transform">
+ <activity android:name="SimplePathsActivity"
+ android:label="Path/Simple Paths"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="SimplePathsActivity"
- android:label="Path/Simple Paths">
+ <activity android:name="AdvancedBlendActivity"
+ android:label="Draw/Advanced Blend"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="AdvancedBlendActivity"
- android:label="Draw/Advanced Blend">
+ <activity android:name="FramebufferBlendActivity"
+ android:label="Draw/Framebuffer Blend"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="FramebufferBlendActivity"
- android:label="Draw/Framebuffer Blend">
+ <activity android:name="StackActivity"
+ android:label="View/Stacks"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="StackActivity"
- android:label="View/Stacks">
+ <activity android:name="PathDestructionActivity"
+ android:label="Path/Path Destruction"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="PathDestructionActivity"
- android:label="Path/Path Destruction">
+ <activity android:name="TransformsAndAnimationsActivity"
+ android:label="Draw/Transforms and Animations"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="TransformsAndAnimationsActivity"
- android:label="Draw/Transforms and Animations">
+ <activity android:name="ViewPropertyAlphaActivity"
+ android:label="View/Alpha Property"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="ViewPropertyAlphaActivity"
- android:label="View/Alpha Property">
+ <activity android:name="ViewLayerInvalidationActivity"
+ android:label="Layers/Invalidation"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="ViewLayerInvalidationActivity"
- android:label="Layers/Invalidation">
+ <activity android:name="ProjectionActivity"
+ android:label="Reordering/Projection"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="ProjectionActivity"
- android:label="Reordering/Projection">
+ <activity android:name=".ProjectionClippingActivity"
+ android:label="Reordering/Projection Clipping"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name=".ProjectionClippingActivity"
- android:label="Reordering/Projection Clipping">
+ <activity android:name=".ZOrderingActivity"
+ android:label="Reordering/Z Ordering"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name=".ZOrderingActivity"
- android:label="Reordering/Z Ordering">
+ <activity android:name="GLDepthTestActivity"
+ android:label="Reordering/OpenGL Depth Test"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="GLDepthTestActivity"
- android:label="Reordering/OpenGL Depth Test">
+ <activity android:name="CirclePropActivity"
+ android:label="Animation/Circle Props"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="CirclePropActivity"
- android:label="Animation/Circle Props">
+ <activity android:name="RevealActivity"
+ android:label="Animation/Reveal Animation"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="RevealActivity"
- android:label="Animation/Reveal Animation">
+ <activity android:name="RippleActivity"
+ android:label="Animation/Ripple Animation"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="MultiProducerActivity"
- android:label="Threads/Multiple Producers">
+ <activity android:name="MultiProducerActivity"
+ android:label="Threads/Multiple Producers"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="PixelCopyWindow"
- android:label="Readback/Window"
- android:screenOrientation="fullSensor">
+ <activity android:name="PixelCopyWindow"
+ android:label="Readback/Window"
+ android:screenOrientation="fullSensor"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="PositionListenerActivity"
- android:label="RenderNode/PositionListener"
- android:screenOrientation="fullSensor">
+ <activity android:name="PositionListenerActivity"
+ android:label="RenderNode/PositionListener"
+ android:screenOrientation="fullSensor"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="CustomRenderer"
- android:label="HardwareRenderer/HelloTakeSurface"
- android:screenOrientation="fullSensor">
+ <activity android:name="CustomRenderer"
+ android:label="HardwareRenderer/HelloTakeSurface"
+ android:screenOrientation="fullSensor"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="MyLittleTextureView"
- android:label="HardwareRenderer/MyLittleTextureView"
- android:screenOrientation="fullSensor">
+ <activity android:name="MyLittleTextureView"
+ android:label="HardwareRenderer/MyLittleTextureView"
+ android:screenOrientation="fullSensor"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
diff --git a/tests/HwAccelerationTest/res/layout/image_filter_activity.xml b/tests/HwAccelerationTest/res/layout/image_filter_activity.xml
new file mode 100644
index 000000000000..a0ee67ae0bef
--- /dev/null
+++ b/tests/HwAccelerationTest/res/layout/image_filter_activity.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 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.
+ -->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="center">
+
+ <ImageView
+ android:id="@+id/image_filter_test_view"
+ android:background="#FF0000"
+ android:layout_width="200dp"
+ android:layout_height="200dp" />
+</FrameLayout> \ No newline at end of file
diff --git a/tests/HwAccelerationTest/res/layout/scrolling_stretch_surfaceview.xml b/tests/HwAccelerationTest/res/layout/scrolling_stretch_surfaceview.xml
new file mode 100644
index 000000000000..77f5e60dc091
--- /dev/null
+++ b/tests/HwAccelerationTest/res/layout/scrolling_stretch_surfaceview.xml
@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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.
+ -->
+
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:overScrollMode="always"
+ android:fillViewport="true"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ >
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="100dp"
+ android:layout_marginTop="100dp"
+ android:orientation="horizontal"
+ >
+
+ <ImageView
+ android:id="@+id/vertical_imageview"
+ android:layout_width="0dp"
+ android:layout_weight="1"
+ android:layout_height="match_parent"/>
+ <FrameLayout
+ android:id="@+id/vertical_surfaceview_container"
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1"/>
+ </LinearLayout>
+
+ <HorizontalScrollView
+ android:overScrollMode="always"
+ android:layout_width="400dp"
+ android:layout_height="0dp"
+ android:background="#FF0000"
+ android:layout_weight="1"
+ >
+ <LinearLayout
+ android:layout_width="400dp"
+ android:layout_height="400dp"
+ android:layout_marginLeft="100dp"
+ android:orientation="vertical">
+
+ <ImageView
+ android:id="@+id/horizontal_imageview"
+ android:layout_width="100dp"
+ android:layout_weight="1"
+ android:layout_height="0dp"/>
+
+ <FrameLayout
+ android:id="@+id/horizontal_surfaceview_container"
+ android:layout_width="100dp"
+ android:layout_height="0dp"
+ android:layout_weight="1"/>
+
+ </LinearLayout>
+ </HorizontalScrollView>
+ </LinearLayout>
+</ScrollView> \ No newline at end of file
diff --git a/tests/HwAccelerationTest/res/layout/stretch_layout.xml b/tests/HwAccelerationTest/res/layout/stretch_layout.xml
new file mode 100644
index 000000000000..81e0c019490f
--- /dev/null
+++ b/tests/HwAccelerationTest/res/layout/stretch_layout.xml
@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 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.
+-->
+<ScrollView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/scroll_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" >
+ <LinearLayout
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <HorizontalScrollView
+ android:id="@+id/horizontal_scroll_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ <LinearLayout
+ android:orientation="horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ <ImageView
+ android:layout_width="match_parent"
+ android:layout_height="200dp"
+ android:src="@drawable/sunset1"/>
+ <ImageView
+ android:layout_width="match_parent"
+ android:layout_height="200dp"
+ android:src="@drawable/sunset1"/>
+ <ImageView
+ android:layout_width="match_parent"
+ android:layout_height="200dp"
+ android:src="@drawable/sunset1"/>
+ <ImageView
+ android:layout_width="match_parent"
+ android:layout_height="200dp"
+ android:src="@drawable/sunset1"/>
+ <ImageView
+ android:layout_width="match_parent"
+ android:layout_height="200dp"
+ android:src="@drawable/sunset1"/>
+ <ImageView
+ android:layout_width="match_parent"
+ android:layout_height="200dp"
+ android:src="@drawable/sunset1"/>
+ </LinearLayout>
+ </HorizontalScrollView>
+ <ImageView
+ android:layout_width="match_parent"
+ android:layout_height="200dp"
+ android:src="@drawable/sunset1"/>
+ <ImageView
+ android:layout_width="match_parent"
+ android:layout_height="200dp"
+ android:src="@drawable/sunset1"/>
+ <ImageView
+ android:layout_width="match_parent"
+ android:layout_height="200dp"
+ android:src="@drawable/sunset1"/>
+ <ImageView
+ android:layout_width="match_parent"
+ android:layout_height="200dp"
+ android:src="@drawable/sunset1"/>
+ <ImageView
+ android:layout_width="match_parent"
+ android:layout_height="200dp"
+ android:src="@drawable/sunset1"/>
+ <ImageView
+ android:layout_width="match_parent"
+ android:layout_height="200dp"
+ android:src="@drawable/sunset1"/>
+
+ </LinearLayout>
+</ScrollView>
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/BlurActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/BlurActivity.java
new file mode 100644
index 000000000000..e4ca7881f796
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/BlurActivity.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2020 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.test.hwui;
+
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.LinearGradient;
+import android.graphics.Paint;
+import android.graphics.RenderEffect;
+import android.graphics.RenderNode;
+import android.graphics.Shader;
+import android.os.Bundle;
+import android.view.Gravity;
+import android.view.View;
+import android.widget.LinearLayout;
+
+@SuppressWarnings({"UnusedDeclaration"})
+public class BlurActivity extends Activity {
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ LinearLayout layout = new LinearLayout(this);
+ layout.setClipChildren(false);
+ layout.setGravity(Gravity.CENTER);
+ layout.setOrientation(LinearLayout.VERTICAL);
+
+
+ LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(500, 500);
+ params.bottomMargin = 100;
+
+ layout.addView(new BlurGradientView(this), params);
+ layout.addView(new BlurView(this), params);
+
+ setContentView(layout);
+ }
+
+ public static class BlurGradientView extends View {
+ private final float mBlurRadius = 25f;
+ private final Paint mPaint;
+ private final RenderNode mRenderNode;
+
+ public BlurGradientView(Context c) {
+ super(c);
+ mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ mRenderNode = new RenderNode("BlurGradientView");
+ mRenderNode.setRenderEffect(
+ RenderEffect.createBlurEffect(
+ mBlurRadius,
+ mBlurRadius,
+ null,
+ Shader.TileMode.DECAL
+ )
+ );
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ if (changed) {
+ LinearGradient gradient = new LinearGradient(
+ 0f,
+ 0f,
+ right - left,
+ bottom - top,
+ Color.CYAN,
+ Color.YELLOW,
+ Shader.TileMode.CLAMP
+ );
+
+ mPaint.setShader(gradient);
+
+ final int width = right - left;
+ final int height = bottom - top;
+ mRenderNode.setPosition(0, 0, width, height);
+
+ Canvas canvas = mRenderNode.beginRecording();
+ canvas.drawRect(
+ mBlurRadius * 2,
+ mBlurRadius * 2,
+ width - mBlurRadius * 2,
+ height - mBlurRadius * 2,
+ mPaint
+ );
+ mRenderNode.endRecording();
+ }
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+ canvas.drawRenderNode(mRenderNode);
+ }
+ }
+
+ public static class BlurView extends View {
+
+ private final Paint mPaint;
+ private final RenderNode mRenderNode;
+ private final float mBlurRadius = 20f;
+
+ public BlurView(Context c) {
+ super(c);
+
+ mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ mRenderNode = new RenderNode("blurNode");
+ mRenderNode.setRenderEffect(
+ RenderEffect.createBlurEffect(
+ mBlurRadius,
+ mBlurRadius,
+ null,
+ Shader.TileMode.DECAL
+ )
+ );
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ if (changed) {
+ int width = right - left;
+ int height = bottom - top;
+ mRenderNode.setPosition(0, 0, width, height);
+ Canvas canvas = mRenderNode.beginRecording(width, height);
+ mPaint.setColor(Color.BLUE);
+
+ canvas.drawRect(
+ mBlurRadius * 2,
+ mBlurRadius * 2,
+ width - mBlurRadius * 2,
+ height - mBlurRadius * 2,
+ mPaint
+ );
+
+ mPaint.setColor(Color.RED);
+ canvas.drawCircle((right - left) / 2f, (bottom - top) / 2f, 50f, mPaint);
+
+ mRenderNode.endRecording();
+ }
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+ canvas.drawRenderNode(mRenderNode);
+ }
+ }
+}
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ColorFiltersMutateActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/ColorFiltersMutateActivity.java
index 51bae3af3e9c..c06f8fd44c03 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/ColorFiltersMutateActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/ColorFiltersMutateActivity.java
@@ -22,6 +22,7 @@ import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
+import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
@@ -30,12 +31,10 @@ import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter;
import android.graphics.RuntimeShader;
+import android.graphics.Shader;
import android.os.Bundle;
import android.view.View;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-
@SuppressWarnings({"UnusedDeclaration"})
public class ColorFiltersMutateActivity extends Activity {
@Override
@@ -52,20 +51,21 @@ public class ColorFiltersMutateActivity extends Activity {
private final Paint mLightingPaint;
private final Paint mBlendPaint;
private final Paint mShaderPaint;
+ private final RuntimeShader mRuntimeShader;
private float mSaturation = 0.0f;
private int mLightAdd = 0;
private int mLightMul = 0;
private int mPorterDuffColor = 0;
+ private float mShaderParam1 = 0.0f;
static final String sSkSL =
- "uniform float param1;\n"
- + "void main(float x, float y, inout half4 color) {\n"
- + "color = half4(color.r, half(param1), color.b, 1.0);\n"
+ "uniform shader bitmapShader;\n"
+ + "uniform float param1;\n"
+ + "half4 main(float2 xy) {\n"
+ + " return half4(sample(bitmapShader, xy).rgb, param1);\n"
+ "}\n";
- private byte[] mUniforms = new byte[4];
-
BitmapsView(Context c) {
super(c);
@@ -83,9 +83,13 @@ public class ColorFiltersMutateActivity extends Activity {
mBlendPaint = new Paint();
mBlendPaint.setColorFilter(new PorterDuffColorFilter(0, PorterDuff.Mode.SRC_OVER));
+ mRuntimeShader = new RuntimeShader(sSkSL, false);
+ mRuntimeShader.setUniform("param1", mShaderParam1);
+ mRuntimeShader.setInputShader("bitmapShader", new BitmapShader(mBitmap1,
+ Shader.TileMode.CLAMP,
+ Shader.TileMode.CLAMP));
mShaderPaint = new Paint();
- mShaderPaint.setShader(new RuntimeShader(sSkSL, mUniforms, true));
- setShaderParam1(0.0f);
+ mShaderPaint.setShader(mRuntimeShader);
ObjectAnimator sat = ObjectAnimator.ofFloat(this, "saturation", 1.0f);
sat.setDuration(1000);
@@ -172,20 +176,15 @@ public class ColorFiltersMutateActivity extends Activity {
}
public void setShaderParam1(float value) {
- RuntimeShader shader = (RuntimeShader) mShaderPaint.getShader();
- ByteBuffer buffer = ByteBuffer.wrap(mUniforms);
- buffer.order(ByteOrder.LITTLE_ENDIAN);
- buffer.putFloat(value);
- shader.updateUniforms(mUniforms);
+ mShaderParam1 = value;
+ mRuntimeShader.setUniform("param1", mShaderParam1);
invalidate();
}
// If either valueFrom or valueTo is null, then a getter function will also be derived
// and called by the animator class.
public float getShaderParam1() {
- ByteBuffer buffer = ByteBuffer.wrap(mUniforms);
- buffer.order(ByteOrder.LITTLE_ENDIAN);
- return buffer.getFloat();
+ return mShaderParam1;
}
@Override
diff --git a/tests/AutoVerify/app1/src/com/android/test/autoverify/MainActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/EdgeEffectStretchActivity.java
index 09ef47212622..c4b0072eaff8 100644
--- a/tests/AutoVerify/app1/src/com/android/test/autoverify/MainActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/EdgeEffectStretchActivity.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * 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.
@@ -13,3 +13,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
+package com.android.test.hwui;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+public class EdgeEffectStretchActivity extends Activity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.stretch_layout);
+ }
+}
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/PictureCaptureDemo.java b/tests/HwAccelerationTest/src/com/android/test/hwui/PictureCaptureDemo.java
index 029e302d0382..15568ac72227 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/PictureCaptureDemo.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/PictureCaptureDemo.java
@@ -34,13 +34,14 @@ import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.LinearLayout.LayoutParams;
import android.widget.ProgressBar;
+import android.widget.TextView;
-import java.io.PipedInputStream;
-import java.io.PipedOutputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
import java.util.Random;
-import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
-import java.util.concurrent.Future;
public class PictureCaptureDemo extends Activity {
@Override
@@ -77,6 +78,12 @@ public class PictureCaptureDemo extends Activity {
iv2.setImageBitmap(Bitmap.createBitmap(picture, 100, 100, Bitmap.Config.HARDWARE));
inner.addView(iv2, new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
+ TextView hello = new TextView(this);
+ hello.setText("I'm on a layer!");
+ hello.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+ inner.addView(hello,
+ new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
+
layout.addView(inner,
new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
// For testing with a functor in the tree
@@ -84,11 +91,13 @@ public class PictureCaptureDemo extends Activity {
wv.setWebViewClient(new WebViewClient());
wv.setWebChromeClient(new WebChromeClient());
wv.loadUrl("https://google.com");
- layout.addView(wv, new LayoutParams(LayoutParams.MATCH_PARENT, 400));
+ LayoutParams wvParams = new LayoutParams(LayoutParams.MATCH_PARENT, 400);
+ wvParams.bottomMargin = 50;
+ layout.addView(wv, wvParams);
SurfaceView mySurfaceView = new SurfaceView(this);
layout.addView(mySurfaceView,
- new LayoutParams(LayoutParams.MATCH_PARENT, 600));
+ new LayoutParams(LayoutParams.MATCH_PARENT, 600, 1f));
setContentView(layout);
@@ -98,22 +107,29 @@ public class PictureCaptureDemo extends Activity {
@Override
public void surfaceCreated(SurfaceHolder holder) {
final Random rand = new Random();
+ OutputStream renderingStream = new ByteArrayOutputStream() {
+ @Override
+ public void flush() throws IOException {
+ Picture picture = Picture.createFromStream(
+ new ByteArrayInputStream(buf, 0, count));
+ Canvas canvas = holder.lockCanvas();
+ if (canvas != null && picture != null) {
+ canvas.drawPicture(picture);
+ holder.unlockCanvasAndPost(canvas);
+ }
+ reset();
+ }
+ };
+
mStopCapture = ViewDebug.startRenderingCommandsCapture(mySurfaceView,
- mCaptureThread, (picture) -> {
+ Executors.newSingleThreadExecutor(), () -> {
if (rand.nextInt(20) == 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
}
}
- Canvas canvas = holder.lockCanvas();
- if (canvas == null) {
- return false;
- }
- canvas.drawPicture(picture);
- holder.unlockCanvasAndPost(canvas);
- picture.close();
- return true;
+ return renderingStream;
});
}
@@ -134,20 +150,4 @@ public class PictureCaptureDemo extends Activity {
}
});
}
-
- ExecutorService mCaptureThread = Executors.newSingleThreadExecutor();
- ExecutorService mExecutor = Executors.newSingleThreadExecutor();
-
- Picture deepCopy(Picture src) {
- try {
- PipedInputStream inputStream = new PipedInputStream();
- PipedOutputStream outputStream = new PipedOutputStream(inputStream);
- Future<Picture> future = mExecutor.submit(() -> Picture.createFromStream(inputStream));
- src.writeToStream(outputStream);
- outputStream.close();
- return future.get();
- } catch (Exception ex) {
- throw new RuntimeException(ex);
- }
- }
}
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/PositionListenerActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/PositionListenerActivity.java
index 818d899413de..2ad034cd143e 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/PositionListenerActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/PositionListenerActivity.java
@@ -19,8 +19,13 @@ package com.android.test.hwui;
import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
+import android.graphics.PointF;
+import android.graphics.RecordingCanvas;
+import android.graphics.Rect;
+import android.graphics.RectF;
import android.graphics.RenderNode;
import android.os.Bundle;
+import android.view.MotionEvent;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.ScrollView;
@@ -38,7 +43,44 @@ public class PositionListenerActivity extends Activity {
ProgressBar spinner = new ProgressBar(this, null, android.R.attr.progressBarStyleLarge);
layout.addView(spinner);
- ScrollView scrollingThing = new ScrollView(this);
+ ScrollView scrollingThing = new ScrollView(this) {
+ int setting = 0;
+ PointF opts[] = new PointF[] {
+ new PointF(0, 0),
+ new PointF(0, -1f),
+ new PointF(1f, 0),
+ new PointF(0, 1f),
+ new PointF(-1f, 0),
+ new PointF(-1f, 1f),
+ };
+ {
+ setWillNotDraw(false);
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent ev) {
+ if (ev.getActionMasked() == MotionEvent.ACTION_UP) {
+ setting = (setting + 1) % opts.length;
+ invalidate();
+ }
+ return super.onTouchEvent(ev);
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+ RenderNode node = ((RecordingCanvas) canvas).mNode;
+ PointF dir = opts[setting];
+ float maxStretchAmount = 100f;
+ // Although we could do this in a single call, the real one won't be - so mimic that
+ if (dir.x != 0f) {
+ node.stretch(dir.x, 0f, maxStretchAmount, maxStretchAmount);
+ }
+ if (dir.y != 0f) {
+ node.stretch(0f, dir.y, maxStretchAmount, maxStretchAmount);
+ }
+ }
+ };
scrollingThing.addView(new MyPositionReporter(this));
layout.addView(scrollingThing);
@@ -49,6 +91,14 @@ public class PositionListenerActivity extends Activity {
RenderNode mNode;
int mCurrentCount = 0;
int mTranslateY = 0;
+ Rect mPosition = new Rect();
+ float mWidth = 0f;
+ float mHeight = 0f;
+ RectF mMappedBounds = new RectF();
+ float mStretchX = 0.0f;
+ float mStretchY = 0.0f;
+ float mStretchMaxX = 0.0f;
+ float mStretchMaxY = 0.0f;
MyPositionReporter(Context c) {
super(c);
@@ -78,18 +128,45 @@ public class PositionListenerActivity extends Activity {
canvas.drawRenderNode(mNode);
}
+ void updateText() {
+ String posText =
+ "%d: Position %s, stretch width %f, height %f, vec %f,%f, amountX %f amountY %f mappedBounds %s";
+ setText(String.format(posText,
+ mCurrentCount, mPosition.toShortString(), mWidth, mHeight,
+ mStretchX, mStretchY, mStretchMaxX, mStretchMaxY,
+ mMappedBounds.toShortString()));
+ }
+
@Override
public void positionChanged(long frameNumber, int left, int top, int right, int bottom) {
- post(() -> {
+ getHandler().postAtFrontOfQueue(() -> {
mCurrentCount++;
- setText(String.format("%d: Position [%d, %d, %d, %d]", mCurrentCount,
- left, top, right, bottom));
+ mPosition.set(left, top, right, bottom);
+ updateText();
+ });
+ }
+
+ @Override
+ public void applyStretch(long frameNumber, float width, float height,
+ float vecX, float vecY,
+ float maxStretchX, float maxStretchY, float childRelativeLeft,
+ float childRelativeTop, float childRelativeRight, float childRelativeBottom) {
+ getHandler().postAtFrontOfQueue(() -> {
+ mWidth = width;
+ mHeight = height;
+ mStretchX = vecX;
+ mStretchY = vecY;
+ mStretchMaxX = maxStretchX;
+ mStretchMaxY = maxStretchY;
+ mMappedBounds.set(childRelativeLeft, childRelativeTop, childRelativeRight,
+ childRelativeBottom);
+ updateText();
});
}
@Override
public void positionLost(long frameNumber) {
- post(() -> {
+ getHandler().postAtFrontOfQueue(() -> {
mCurrentCount++;
setText(mCurrentCount + " No position");
});
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/RenderEffectShaderActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/RenderEffectShaderActivity.java
new file mode 100644
index 000000000000..661d48a84768
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/RenderEffectShaderActivity.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2020 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.test.hwui;
+
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.LinearGradient;
+import android.graphics.Paint;
+import android.graphics.RenderEffect;
+import android.graphics.RenderNode;
+import android.graphics.Shader;
+import android.os.Bundle;
+import android.view.Gravity;
+import android.view.View;
+import android.widget.LinearLayout;
+
+@SuppressWarnings({"UnusedDeclaration"})
+public class RenderEffectShaderActivity extends Activity {
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ LinearLayout layout = new LinearLayout(this);
+ layout.setClipChildren(false);
+ layout.setGravity(Gravity.CENTER);
+ layout.setOrientation(LinearLayout.VERTICAL);
+
+
+ LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(500, 500);
+ params.bottomMargin = 100;
+
+ layout.addView(new ShaderRenderEffectView(this), params);
+
+ setContentView(layout);
+ }
+
+ public static class ShaderRenderEffectView extends View {
+
+ private final Paint mPaint;
+ private final RenderNode mRenderNode;
+
+ public ShaderRenderEffectView(Context c) {
+ super(c);
+
+ mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ mRenderNode = new RenderNode("blurNode");
+
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ if (changed) {
+ LinearGradient gradient = new LinearGradient(
+ 0f, 0f,
+ 0f, bottom - top,
+ new int[]{Color.CYAN, Color.MAGENTA},
+ null,
+ Shader.TileMode.CLAMP
+ );
+ mRenderNode.setRenderEffect(
+ RenderEffect.createShaderEffect(gradient)
+ );
+
+ int width = right - left;
+ int height = bottom - top;
+ mRenderNode.setPosition(0, 0, width, height);
+ Canvas canvas = mRenderNode.beginRecording(width, height);
+ mPaint.setColor(Color.BLUE);
+
+ canvas.drawRect(
+ 0,
+ 0,
+ width,
+ height,
+ mPaint
+ );
+
+ mPaint.setColor(Color.RED);
+ canvas.drawCircle((right - left) / 2f, (bottom - top) / 2f, 50f, mPaint);
+
+ mRenderNode.endRecording();
+ }
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+ canvas.drawRenderNode(mRenderNode);
+ }
+ }
+}
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/RippleActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/RippleActivity.java
new file mode 100644
index 000000000000..d925541c76d6
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/RippleActivity.java
@@ -0,0 +1,186 @@
+/*
+ * 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.test.hwui;
+
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.CanvasProperty;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.RecordingCanvas;
+import android.graphics.RuntimeShader;
+import android.os.Bundle;
+import android.os.Trace;
+import android.view.RenderNodeAnimator;
+import android.view.View;
+import android.widget.LinearLayout;
+import android.widget.LinearLayout.LayoutParams;
+
+import java.util.ArrayList;
+
+public class RippleActivity extends Activity {
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ final LinearLayout layout = new LinearLayout(this);
+ layout.setOrientation(LinearLayout.VERTICAL);
+ layout.addView(new RippleView(this),
+ new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
+
+ setContentView(layout);
+ }
+
+ static class RippleView extends View {
+ static final int DURATION = 1000;
+ static final int MAX_RADIUS = 250;
+ private final int mColor = Color.RED;
+
+ private boolean mToggle = false;
+ ArrayList<RenderNodeAnimator> mRunningAnimations = new ArrayList<RenderNodeAnimator>();
+
+ CanvasProperty<Float> mX;
+ CanvasProperty<Float> mY;
+ CanvasProperty<Float> mRadius;
+ CanvasProperty<Float> mProgress;
+ CanvasProperty<Float> mNoisePhase;
+ CanvasProperty<Paint> mPaint;
+ RuntimeShader mRuntimeShader;
+
+ static final String sSkSL = ""
+ + "uniform float2 in_origin;"
+ + "uniform float in_progress;\n"
+ + "uniform float in_maxRadius;\n"
+ + "uniform shader in_paintColor;\n"
+ + "float dist2(float2 p0, float2 pf) { return sqrt((pf.x - p0.x) * (pf.x - p0.x) + "
+ + "(pf.y - p0.y) * (pf.y - p0.y)); }\n"
+ + "float mod2(float a, float b) { return a - (b * floor(a / b)); }\n"
+ + "float rand(float2 src) { return fract(sin(dot(src.xy, float2(12.9898, 78.233)))"
+ + " * 43758.5453123); }\n"
+ + "float4 main(float2 p)\n"
+ + "{\n"
+ + " float fraction = in_progress;\n"
+ + " float2 fragCoord = p;//sk_FragCoord.xy;\n"
+ + " float maxDist = in_maxRadius;\n"
+ + " float fragDist = dist2(in_origin, fragCoord.xy);\n"
+ + " float circleRadius = maxDist * fraction;\n"
+ + " float colorVal = (fragDist - circleRadius) / maxDist;\n"
+ + " float d = fragDist < circleRadius \n"
+ + " ? 1. - abs(colorVal * 2. * smoothstep(0., 1., fraction)) \n"
+ + " : 1. - abs(colorVal * 3.);\n"
+ + " d = smoothstep(0., 1., d);\n"
+ + " float divider = 2.;\n"
+ + " float x = floor(fragCoord.x / divider);\n"
+ + " float y = floor(fragCoord.y / divider);\n"
+ + " float density = .95;\n"
+ + " d = rand(float2(x, y)) > density ? d : d * .2;\n"
+ + " d = d * rand(float2(fraction, x * y));\n"
+ + " float alpha = 1. - pow(fraction, 3.);\n"
+ + " return float4(sample(in_paintColor, p).rgb, d * alpha);\n"
+ + "}";
+
+ RippleView(Context c) {
+ super(c);
+ setClickable(true);
+
+ mX = CanvasProperty.createFloat(200.0f);
+ mY = CanvasProperty.createFloat(200.0f);
+ mRadius = CanvasProperty.createFloat(150.0f);
+ mProgress = CanvasProperty.createFloat(0.0f);
+ mNoisePhase = CanvasProperty.createFloat(0.0f);
+
+ Paint p = new Paint();
+ p.setAntiAlias(true);
+ p.setColor(mColor);
+ mPaint = CanvasProperty.createPaint(p);
+
+ mRuntimeShader = new RuntimeShader(sSkSL, false);
+ mRuntimeShader.setUniform("in_maxRadius", MAX_RADIUS);
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+
+ if (canvas.isHardwareAccelerated()) {
+ RecordingCanvas recordingCanvas = (RecordingCanvas) canvas;
+ recordingCanvas.drawRipple(mX, mY, mRadius, mPaint, mProgress, mNoisePhase,
+ mColor, mRuntimeShader);
+ }
+ }
+
+ @Override
+ public boolean performClick() {
+ for (int i = 0; i < mRunningAnimations.size(); i++) {
+ mRunningAnimations.get(i).cancel();
+ }
+ mRunningAnimations.clear();
+
+ mToggle = !mToggle;
+
+ mRunningAnimations.add(new RenderNodeAnimator(
+ mX, mToggle ? 400.0f : 200.0f));
+
+ mRunningAnimations.add(new RenderNodeAnimator(
+ mY, mToggle ? 600.0f : 200.0f));
+
+ mRunningAnimations.add(new RenderNodeAnimator(
+ mRadius, mToggle ? MAX_RADIUS : 150.0f));
+
+ mRunningAnimations.add(new RenderNodeAnimator(
+ mProgress, mToggle ? 1.0f : 0.0f));
+
+ mRunningAnimations.add(new RenderNodeAnimator(
+ mNoisePhase, DURATION));
+
+ mRunningAnimations.add(new RenderNodeAnimator(
+ mPaint, RenderNodeAnimator.PAINT_ALPHA, 64.0f));
+
+ // Will be "chained" to run after the above
+ mRunningAnimations.add(new RenderNodeAnimator(
+ mPaint, RenderNodeAnimator.PAINT_ALPHA, 255.0f));
+
+ for (int i = 0; i < mRunningAnimations.size(); i++) {
+ RenderNodeAnimator anim = mRunningAnimations.get(i);
+ anim.setDuration(DURATION);
+ anim.setTarget(this);
+ if (i == (mRunningAnimations.size() - 1)) {
+ // "chain" test
+ anim.setStartValue(64.0f);
+ anim.setStartDelay(anim.getDuration());
+ }
+ anim.start();
+ }
+
+ if (mToggle) {
+ post(new Runnable() {
+ @Override
+ public void run() {
+ Trace.traceBegin(Trace.TRACE_TAG_VIEW, "pretendBusy");
+ try {
+ Thread.sleep(DURATION);
+ } catch (InterruptedException e) {
+ }
+ Trace.traceEnd(Trace.TRACE_TAG_VIEW);
+ }
+ });
+ }
+ return true;
+ }
+ }
+}
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ScrollingStretchSurfaceViewActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/ScrollingStretchSurfaceViewActivity.java
new file mode 100644
index 000000000000..040bff5d74d8
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/ScrollingStretchSurfaceViewActivity.java
@@ -0,0 +1,113 @@
+/*
+ * 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.test.hwui;
+
+import android.app.Activity;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.ColorFilter;
+import android.graphics.Paint;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.view.SurfaceHolder;
+import android.view.SurfaceHolder.Callback;
+import android.view.SurfaceView;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+
+public class ScrollingStretchSurfaceViewActivity extends Activity implements Callback {
+
+ SurfaceView mVerticalSurfaceView;
+ SurfaceView mHorizontalSurfaceView;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.scrolling_stretch_surfaceview);
+
+ mVerticalSurfaceView = new SurfaceView(this);
+ mVerticalSurfaceView.getHolder().addCallback(this);
+
+ mHorizontalSurfaceView = new SurfaceView(this);
+ mHorizontalSurfaceView.getHolder().addCallback(this);
+
+ FrameLayout verticalContainer = findViewById(R.id.vertical_surfaceview_container);
+ verticalContainer.addView(mVerticalSurfaceView,
+ new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT,
+ FrameLayout.LayoutParams.MATCH_PARENT));
+
+ FrameLayout horizontalContainer = findViewById(R.id.horizontal_surfaceview_container);
+ horizontalContainer.addView(mHorizontalSurfaceView,
+ new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT,
+ FrameLayout.LayoutParams.MATCH_PARENT));
+
+ ImageView verticalImageView = findViewById(R.id.vertical_imageview);
+ verticalImageView.setImageDrawable(new LineDrawable());
+
+ ImageView horizontalImageView = findViewById(R.id.horizontal_imageview);
+ horizontalImageView.setImageDrawable(new LineDrawable());
+ }
+
+ @Override
+ public void surfaceCreated(SurfaceHolder holder) {
+ }
+
+ @Override
+ public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
+ Canvas canvas = holder.lockCanvas();
+
+ drawLine(canvas, width, height);
+ holder.unlockCanvasAndPost(canvas);
+ }
+
+ private static void drawLine(Canvas canvas, int width, int height) {
+ canvas.drawColor(Color.GRAY);
+
+ Paint paint = new Paint();
+ paint.setAntiAlias(true);
+ paint.setColor(Color.GREEN);
+ paint.setStyle(Paint.Style.STROKE);
+ paint.setStrokeWidth(10f);
+ canvas.drawLine(0, 0, width, height, paint);
+ }
+
+ private static class LineDrawable extends Drawable {
+ @Override
+ public void draw(Canvas canvas) {
+ drawLine(canvas, getBounds().width(), getBounds().height());
+ }
+
+ @Override
+ public void setAlpha(int alpha) {
+ // NO-OP
+ }
+
+ @Override
+ public void setColorFilter(ColorFilter colorFilter) {
+ // NO-OP
+ }
+
+ @Override
+ public int getOpacity() {
+ return 0;
+ }
+ }
+
+ @Override
+ public void surfaceDestroyed(SurfaceHolder holder) {
+ }
+}
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/StretchShaderActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/StretchShaderActivity.java
new file mode 100644
index 000000000000..3307c36d9d1a
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/StretchShaderActivity.java
@@ -0,0 +1,537 @@
+/*
+ * 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.test.hwui;
+
+import android.annotation.Nullable;
+import android.app.Activity;
+import android.graphics.Bitmap;
+import android.graphics.BitmapShader;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.ColorFilter;
+import android.graphics.RecordingCanvas;
+import android.graphics.Rect;
+import android.graphics.RenderEffect;
+import android.graphics.RuntimeShader;
+import android.graphics.Shader;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.SeekBar;
+import android.widget.TextView;
+
+public class StretchShaderActivity extends Activity {
+
+ private static final float MAX_STRETCH_INTENSITY = 1.5f;
+ private static final float STRETCH_AFFECTED_DISTANCE = 1.0f;
+
+ private float mScrollX = 0f;
+ private float mScrollY = 0f;
+
+ private float mMaxStretchIntensity = MAX_STRETCH_INTENSITY;
+ private float mStretchAffectedDistance = STRETCH_AFFECTED_DISTANCE;
+
+ private float mOverscrollX = 25f;
+ private float mOverscrollY = 25f;
+
+ private RuntimeShader mRuntimeShader;
+ private ImageView mImageView;
+ private ImageView mTestImageView;
+
+ private Bitmap mBitmap;
+
+ private StretchDrawable mStretchDrawable = new StretchDrawable();
+
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ LinearLayout linearLayout = new LinearLayout(this);
+ linearLayout.setOrientation(LinearLayout.VERTICAL);
+
+ mBitmap = ((BitmapDrawable) getDrawable(R.drawable.sunset1)).getBitmap();
+ mRuntimeShader = new RuntimeShader(SKSL, false);
+
+ BitmapShader bitmapShader = new BitmapShader(mBitmap, Shader.TileMode.CLAMP,
+ Shader.TileMode.CLAMP);
+ mRuntimeShader.setInputShader("uContentTexture", bitmapShader);
+
+ mImageView = new ImageView(this);
+
+ mImageView.setRenderEffect(RenderEffect.createShaderEffect(mRuntimeShader));
+ mImageView.setImageDrawable(new ColorDrawable(Color.CYAN));
+
+ TextView overscrollXText = new TextView(this);
+ overscrollXText.setText("Overscroll X");
+
+ SeekBar overscrollXBar = new SeekBar(this);
+ overscrollXBar.setProgress(0);
+ overscrollXBar.setMin(-50);
+ overscrollXBar.setMax(50);
+ overscrollXBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
+ @Override
+ public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+ mOverscrollX = progress;
+ overscrollXText.setText("Overscroll X: " + mOverscrollX);
+ updateShader();
+ }
+
+ @Override
+ public void onStartTrackingTouch(SeekBar seekBar) {
+
+ }
+
+ @Override
+ public void onStopTrackingTouch(SeekBar seekBar) {
+
+ }
+ });
+
+ TextView overscrollYText = new TextView(this);
+ overscrollYText.setText("Overscroll Y");
+
+ SeekBar overscrollYBar = new SeekBar(this);
+ overscrollYBar.setProgress(0);
+ overscrollYBar.setMin(-50);
+ overscrollYBar.setMax(50);
+ overscrollYBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
+ @Override
+ public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+ mOverscrollY = progress;
+ overscrollYText.setText("Overscroll Y: " + mOverscrollY);
+ updateShader();
+ }
+
+ @Override
+ public void onStartTrackingTouch(SeekBar seekBar) {
+
+ }
+
+ @Override
+ public void onStopTrackingTouch(SeekBar seekBar) {
+
+ }
+ });
+
+ TextView scrollXText = new TextView(this);
+ scrollXText.setText("Scroll X");
+ SeekBar scrollXSeekBar = new SeekBar(this);
+ scrollXSeekBar.setMin(0);
+ scrollXSeekBar.setMax(100);
+ scrollXSeekBar.setProgress(0);
+ scrollXSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
+ @Override
+ public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+ mScrollX = (progress / 100f);
+ scrollXText.setText("Scroll X: " + mScrollY);
+ updateShader();
+ }
+
+ @Override
+ public void onStartTrackingTouch(SeekBar seekBar) {
+
+ }
+
+ @Override
+ public void onStopTrackingTouch(SeekBar seekBar) {
+
+ }
+ });
+
+ TextView scrollYText = new TextView(this);
+ scrollYText.setText("Scroll Y");
+ SeekBar scrollYSeekBar = new SeekBar(this);
+ scrollYSeekBar.setMin(0);
+ scrollYSeekBar.setMax(100);
+ scrollYSeekBar.setProgress(0);
+ scrollYSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
+ @Override
+ public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+ mScrollY = (progress / 100f);
+ scrollYText.setText("Scroll Y: " + mScrollY);
+ updateShader();
+ }
+
+ @Override
+ public void onStartTrackingTouch(SeekBar seekBar) {
+
+ }
+
+ @Override
+ public void onStopTrackingTouch(SeekBar seekBar) {
+
+ }
+ });
+
+ TextView stretchIntensityText = new TextView(this);
+ int stretchProgress = (int) (mMaxStretchIntensity * 100);
+ stretchIntensityText.setText("StretchIntensity: " + mMaxStretchIntensity);
+ SeekBar stretchIntensitySeekbar = new SeekBar(this);
+ stretchIntensitySeekbar.setProgress(stretchProgress);
+ stretchIntensitySeekbar.setMin(1);
+ stretchIntensitySeekbar.setMax((int) (MAX_STRETCH_INTENSITY * 100));
+ stretchIntensitySeekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
+ @Override
+ public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+ mMaxStretchIntensity = progress / 100f;
+ stretchIntensityText.setText("StretchIntensity: " + mMaxStretchIntensity);
+ updateShader();
+ }
+
+ @Override
+ public void onStartTrackingTouch(SeekBar seekBar) {
+
+ }
+
+ @Override
+ public void onStopTrackingTouch(SeekBar seekBar) {
+
+ }
+ });
+
+ TextView stretchDistanceText = new TextView(this);
+ stretchDistanceText.setText("StretchDistance");
+ SeekBar stretchDistanceSeekbar = new SeekBar(this);
+ stretchDistanceSeekbar.setMin(0);
+ stretchDistanceSeekbar.setProgress((int) (mStretchAffectedDistance * 100));
+ stretchDistanceSeekbar.setMax(100);
+ stretchDistanceSeekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
+ @Override
+ public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+ mStretchAffectedDistance = progress / 100f;
+ stretchDistanceText.setText("StretchDistance: " + mStretchAffectedDistance);
+ updateShader();
+ }
+
+ @Override
+ public void onStartTrackingTouch(SeekBar seekBar) {
+
+ }
+
+ @Override
+ public void onStopTrackingTouch(SeekBar seekBar) {
+
+ }
+ });
+
+
+ linearLayout.addView(mImageView,
+ new LinearLayout.LayoutParams(
+ mBitmap.getWidth(),
+ mBitmap.getHeight())
+ );
+
+ linearLayout.addView(overscrollXText,
+ new LinearLayout.LayoutParams(
+ LinearLayout.LayoutParams.WRAP_CONTENT,
+ LinearLayout.LayoutParams.WRAP_CONTENT
+ ));
+ linearLayout.addView(overscrollXBar,
+ new LinearLayout.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT
+ )
+ );
+
+ linearLayout.addView(overscrollYText,
+ new LinearLayout.LayoutParams(
+ LinearLayout.LayoutParams.WRAP_CONTENT,
+ LinearLayout.LayoutParams.WRAP_CONTENT
+ ));
+ linearLayout.addView(overscrollYBar,
+ new LinearLayout.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT
+ )
+ );
+
+ linearLayout.addView(scrollXText,
+ new LinearLayout.LayoutParams(
+ LinearLayout.LayoutParams.WRAP_CONTENT,
+ LinearLayout.LayoutParams.WRAP_CONTENT
+ ));
+
+ linearLayout.addView(scrollXSeekBar,
+ new LinearLayout.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT
+ ));
+
+ linearLayout.addView(scrollYText,
+ new LinearLayout.LayoutParams(
+ LinearLayout.LayoutParams.WRAP_CONTENT,
+ LinearLayout.LayoutParams.WRAP_CONTENT
+ ));
+
+ linearLayout.addView(scrollYSeekBar,
+ new LinearLayout.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT
+ ));
+
+ linearLayout.addView(stretchIntensityText,
+ new LinearLayout.LayoutParams(
+ LinearLayout.LayoutParams.WRAP_CONTENT,
+ LinearLayout.LayoutParams.WRAP_CONTENT
+ )
+ );
+
+ linearLayout.addView(stretchIntensitySeekbar,
+ new LinearLayout.LayoutParams(
+ LinearLayout.LayoutParams.MATCH_PARENT,
+ LinearLayout.LayoutParams.WRAP_CONTENT
+ )
+ );
+
+ linearLayout.addView(stretchDistanceText,
+ new LinearLayout.LayoutParams(
+ LinearLayout.LayoutParams.WRAP_CONTENT,
+ LinearLayout.LayoutParams.WRAP_CONTENT
+ ));
+
+ linearLayout.addView(stretchDistanceSeekbar,
+ new LinearLayout.LayoutParams(
+ LinearLayout.LayoutParams.MATCH_PARENT,
+ LinearLayout.LayoutParams.WRAP_CONTENT
+ ));
+
+ ImageView test = new ImageView(this);
+ mStretchDrawable.setBitmap(mBitmap);
+ test.setImageDrawable(mStretchDrawable);
+
+ mTestImageView = test;
+ linearLayout.addView(test,
+ new LinearLayout.LayoutParams(mBitmap.getWidth(), mBitmap.getHeight()));
+
+ setContentView(linearLayout);
+
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ mImageView.getViewTreeObserver().addOnPreDrawListener(
+ new ViewTreeObserver.OnPreDrawListener() {
+ @Override
+ public boolean onPreDraw() {
+ updateShader();
+ mImageView.getViewTreeObserver().removeOnPreDrawListener(this);
+ return false;
+ }
+ });
+ }
+
+ private void updateShader() {
+ final float width = mImageView.getWidth();
+ final float height = mImageView.getHeight();
+ final float distanceNotStretched = mStretchAffectedDistance;
+ final float normOverScrollDistX = mOverscrollX / width;
+ final float normOverScrollDistY = mOverscrollY / height;
+ final float distanceStretchedX =
+ mStretchAffectedDistance
+ / (1 + Math.abs(normOverScrollDistX) * mMaxStretchIntensity);
+ final float distanceStretchedY =
+ mStretchAffectedDistance
+ / (1 + Math.abs(normOverScrollDistY) * mMaxStretchIntensity);
+ final float diffX = distanceStretchedX - distanceNotStretched;
+ final float diffY = distanceStretchedY - distanceNotStretched;
+ float uScrollX = mScrollX;
+ float uScrollY = mScrollY;
+
+ mRuntimeShader.setUniform("uMaxStretchIntensity", mMaxStretchIntensity);
+ mRuntimeShader.setUniform("uStretchAffectedDist", mStretchAffectedDistance);
+ mRuntimeShader.setUniform("uDistanceStretchedX", distanceStretchedX);
+ mRuntimeShader.setUniform("uDistanceStretchedY", distanceStretchedY);
+ mRuntimeShader.setUniform("uDistDiffX", diffX);
+ mRuntimeShader.setUniform("uDistDiffY", diffY);
+ mRuntimeShader.setUniform("uOverscrollX", normOverScrollDistX);
+ mRuntimeShader.setUniform("uOverscrollY", normOverScrollDistY);
+ mRuntimeShader.setUniform("uScrollX", uScrollX);
+ mRuntimeShader.setUniform("uScrollY", uScrollY);
+ mRuntimeShader.setUniform("viewportWidth", width);
+ mRuntimeShader.setUniform("viewportHeight", height);
+
+ mImageView.setRenderEffect(RenderEffect.createShaderEffect(mRuntimeShader));
+
+ mStretchDrawable.setStretchDistance(mStretchAffectedDistance);
+ mStretchDrawable.setOverscrollX(normOverScrollDistX);
+ mStretchDrawable.setOverscrollY(normOverScrollDistY);
+ }
+
+ private static class StretchDrawable extends Drawable {
+
+ private float mStretchDistance = 0;
+ private float mOverScrollX = 0f;
+ private float mOverScrollY = 0f;
+ private Bitmap mBitmap = null;
+
+ public void setStretchDistance(float stretchDistance) {
+ mStretchDistance = stretchDistance;
+ invalidateSelf();
+ }
+
+ public void setOverscrollX(float overscrollX) {
+ mOverScrollX = overscrollX;
+ invalidateSelf();
+ }
+
+ public void setOverscrollY(float overscrollY) {
+ mOverScrollY = overscrollY;
+ invalidateSelf();
+ }
+
+ public void setBitmap(Bitmap bitmap) {
+ mBitmap = bitmap;
+ invalidateSelf();
+ }
+
+ @Override
+ public void draw(Canvas canvas) {
+ if (mStretchDistance > 0 && canvas instanceof RecordingCanvas) {
+ Rect bounds = getBounds();
+ ((RecordingCanvas) canvas).mNode.stretch(
+ mOverScrollX,
+ mOverScrollY,
+ mStretchDistance,
+ mStretchDistance
+ );
+ }
+ if (mBitmap != null) {
+ canvas.drawBitmap(mBitmap, 0f, 0f, null);
+ }
+ }
+
+ @Override
+ public void setAlpha(int alpha) {
+
+ }
+
+ @Override
+ public void setColorFilter(ColorFilter colorFilter) {
+
+ }
+
+ @Override
+ public int getOpacity() {
+ return 0;
+ }
+ }
+
+ private static final String SKSL = "uniform shader uContentTexture;\n"
+ + "uniform float uMaxStretchIntensity; // multiplier to apply to scale effect\n"
+ + "uniform float uStretchAffectedDist; // Maximum percentage to stretch beyond bounds"
+ + " of target\n"
+ + "\n"
+ + "// Distance stretched as a function of the normalized overscroll times scale "
+ + "intensity\n"
+ + "uniform float uDistanceStretchedX;\n"
+ + "uniform float uDistanceStretchedY;\n"
+ + "uniform float uDistDiffX;\n"
+ + "uniform float uDistDiffY; // Difference between the peak stretch amount and "
+ + "overscroll amount normalized\n"
+ + "uniform float uScrollX; // Horizontal offset represented as a ratio of pixels "
+ + "divided by the target width\n"
+ + "uniform float uScrollY; // Vertical offset represented as a ratio of pixels "
+ + "divided by the target height\n"
+ + "uniform float uOverscrollX; // Normalized overscroll amount in the horizontal "
+ + "direction\n"
+ + "uniform float uOverscrollY; // Normalized overscroll amount in the vertical "
+ + "direction\n"
+ + "\n"
+ + "uniform float viewportWidth; // target height in pixels\n"
+ + "uniform float viewportHeight; // target width in pixels\n"
+ + "\n"
+ + "vec4 main(vec2 coord) {\n"
+ + "\n"
+ + " // Normalize SKSL pixel coordinate into a unit vector\n"
+ + " vec2 uv = vec2(coord.x / viewportWidth, coord.y / viewportHeight);\n"
+ + " float inU = uv.x;\n"
+ + " float inV = uv.y;\n"
+ + " float outU;\n"
+ + " float outV;\n"
+ + " float stretchIntensity;\n"
+ + "\n"
+ + " // Add the normalized scroll position within scrolling list\n"
+ + " inU += uScrollX;\n"
+ + " inV += uScrollY;\n"
+ + "\n"
+ + " outU = inU;\n"
+ + " outV = inV;\n"
+ + " if (uOverscrollX > 0) {\n"
+ + " if (inU <= uStretchAffectedDist) {\n"
+ + " inU = uStretchAffectedDist - inU;\n"
+ + " float posBasedVariation = smoothstep(0., uStretchAffectedDist, inU);\n"
+ + " stretchIntensity = uMaxStretchIntensity * uOverscrollX * "
+ + "posBasedVariation;\n"
+ + " outU = uDistanceStretchedX - (inU / (1. + stretchIntensity));\n"
+ + " } else {\n"
+ + " outU = uDistDiffX + inU;\n"
+ + " }\n"
+ + " }\n"
+ + "\n"
+ + " if (uOverscrollX < 0) {\n"
+ + " float stretchAffectedDist = 1. - uStretchAffectedDist;\n"
+ + " if (inU >= stretchAffectedDist) {\n"
+ + " inU = inU - stretchAffectedDist;\n"
+ + " float posBasedVariation = (smoothstep(0., uStretchAffectedDist, "
+ + "inU));\n"
+ + " stretchIntensity = uMaxStretchIntensity * (-uOverscrollX) * "
+ + "posBasedVariation;\n"
+ + " outU = 1 - (uDistanceStretchedX - (inU / (1. + stretchIntensity)))"
+ + ";\n"
+ + " } else if (inU < stretchAffectedDist) {\n"
+ + " outU = -uDistDiffX + inU;\n"
+ + " }\n"
+ + " }\n"
+ + "\n"
+ + " if (uOverscrollY > 0) {\n"
+ + " if (inV <= uStretchAffectedDist) {\n"
+ + " inV = uStretchAffectedDist - inV;\n"
+ + " float posBasedVariation = smoothstep(0., uStretchAffectedDist, inV);\n"
+ + " stretchIntensity = uMaxStretchIntensity * uOverscrollY * "
+ + "posBasedVariation;\n"
+ + " outV = uDistanceStretchedY - (inV / (1. + stretchIntensity));\n"
+ + " } else if (inV >= uStretchAffectedDist) {\n"
+ + " outV = uDistDiffY + inV;\n"
+ + " }\n"
+ + " }\n"
+ + "\n"
+ + " if (uOverscrollY < 0) {\n"
+ + " float stretchAffectedDist = 1. - uStretchAffectedDist;\n"
+ + " if (inV >= stretchAffectedDist) {\n"
+ + " inV = inV - stretchAffectedDist;\n"
+ + " float posBasedVariation = (smoothstep(0., uStretchAffectedDist, inV));\n"
+ + " stretchIntensity = uMaxStretchIntensity * (-uOverscrollY) * "
+ + "posBasedVariation;\n"
+ + " outV = 1 - (uDistanceStretchedY - (inV / (1. + stretchIntensity)));\n"
+ + " } else if (inV < stretchAffectedDist) {\n"
+ + " outV = -uDistDiffY + inV;\n"
+ + " }\n"
+ + " }\n"
+ + "\n"
+ + " uv.x = outU;\n"
+ + " uv.y = outV;\n"
+ + " coord.x = uv.x * viewportWidth;\n"
+ + " coord.y = uv.y * viewportHeight;\n"
+ + " return sample(uContentTexture, coord);\n"
+ + "}";
+}
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/StretchySurfaceViewActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/StretchySurfaceViewActivity.java
new file mode 100644
index 000000000000..acb872cd23b8
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/StretchySurfaceViewActivity.java
@@ -0,0 +1,158 @@
+/*
+ * 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.test.hwui;
+
+import android.animation.ObjectAnimator;
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.RecordingCanvas;
+import android.graphics.RenderNode;
+import android.os.Bundle;
+import android.view.Gravity;
+import android.view.SurfaceHolder;
+import android.view.SurfaceHolder.Callback;
+import android.view.SurfaceView;
+import android.view.animation.LinearInterpolator;
+import android.widget.FrameLayout;
+
+public class StretchySurfaceViewActivity extends Activity implements Callback {
+ SurfaceView mSurfaceView;
+ ObjectAnimator mAnimator;
+
+ class MySurfaceView extends SurfaceView {
+ boolean mSlow;
+ boolean mScaled;
+ int mToggle = 0;
+
+ public MySurfaceView(Context context) {
+ super(context);
+ setOnClickListener(v -> {
+ mToggle = (mToggle + 1) % 4;
+ mSlow = (mToggle & 0x2) != 0;
+ mScaled = (mToggle & 0x1) != 0;
+
+ mSurfaceView.setScaleX(mScaled ? 1.6f : 1f);
+ mSurfaceView.setScaleY(mScaled ? 0.8f : 1f);
+
+ setTitle("Slow=" + mSlow + ", scaled=" + mScaled);
+ invalidate();
+ });
+ setWillNotDraw(false);
+ }
+
+ @Override
+ public void draw(Canvas canvas) {
+ super.draw(canvas);
+ if (mSlow) {
+ try {
+ Thread.sleep(16);
+ } catch (InterruptedException e) {}
+ }
+ }
+
+ public void setMyTranslationY(float ty) {
+ setTranslationY(ty);
+ if (mSlow) {
+ invalidate();
+ }
+ }
+
+ public float getMyTranslationY() {
+ return getTranslationY();
+ }
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ FrameLayout content = new FrameLayout(this) {
+ {
+ setWillNotDraw(false);
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ Paint paint = new Paint();
+ paint.setAntiAlias(true);
+ paint.setColor(Color.RED);
+ paint.setStyle(Paint.Style.STROKE);
+ paint.setStrokeWidth(10f);
+ canvas.drawLine(0f, 0f, getWidth(), getHeight(), paint);
+ super.onDraw(canvas);
+
+ RenderNode node = ((RecordingCanvas) canvas).mNode;
+ node.stretch(0f,
+ 1f, 400f, 400f);
+ }
+ };
+
+ mSurfaceView = new MySurfaceView(this);
+ mSurfaceView.getHolder().addCallback(this);
+
+ final float density = getResources().getDisplayMetrics().density;
+ int size = (int) (200 * density);
+
+ content.addView(mSurfaceView, new FrameLayout.LayoutParams(
+ size, size, Gravity.CENTER_HORIZONTAL | Gravity.TOP));
+ mAnimator = ObjectAnimator.ofFloat(mSurfaceView, "myTranslationY",
+ 0, size);
+ mAnimator.setRepeatMode(ObjectAnimator.REVERSE);
+ mAnimator.setRepeatCount(ObjectAnimator.INFINITE);
+ mAnimator.setDuration(1000);
+ mAnimator.setInterpolator(new LinearInterpolator());
+ setContentView(content);
+ }
+
+ @Override
+ public void surfaceCreated(SurfaceHolder holder) {
+ }
+
+ @Override
+ public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
+ Canvas canvas = holder.lockCanvas();
+ canvas.drawColor(Color.WHITE);
+
+ Paint paint = new Paint();
+ paint.setAntiAlias(true);
+ paint.setColor(Color.GREEN);
+ paint.setStyle(Paint.Style.STROKE);
+ paint.setStrokeWidth(10f);
+ canvas.drawLine(0, 0, width, height, paint);
+
+ holder.unlockCanvasAndPost(canvas);
+ }
+
+ @Override
+ public void surfaceDestroyed(SurfaceHolder holder) {
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ mAnimator.start();
+ }
+
+ @Override
+ protected void onPause() {
+ mAnimator.pause();
+ super.onPause();
+ }
+}
diff --git a/tests/ActivityViewTest/Android.bp b/tests/Input/Android.bp
index 95178a0fb9a5..eacf5b287a2e 100644
--- a/tests/ActivityViewTest/Android.bp
+++ b/tests/Input/Android.bp
@@ -8,8 +8,18 @@ package {
}
android_test {
- name: "ActivityViewTest",
- srcs: ["src/**/*.java"],
+ name: "InputTests",
+ srcs: [
+ "src/**/*.java",
+ "src/**/*.kt",
+ ],
platform_apis: true,
certificate: "platform",
+ static_libs: [
+ "androidx.test.ext.junit",
+ "androidx.test.rules",
+ "truth-prebuilt",
+ "ub-uiautomator",
+ ],
+ test_suites: ["device-tests"],
}
diff --git a/tests/Input/AndroidManifest.xml b/tests/Input/AndroidManifest.xml
new file mode 100644
index 000000000000..20f564e80b3d
--- /dev/null
+++ b/tests/Input/AndroidManifest.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.test.input">
+ <uses-permission android:name="android.permission.MONITOR_INPUT"/>
+ <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS"/>
+ <uses-permission android:name="android.permission.INJECT_EVENTS"/>
+
+ <application android:label="InputTest">
+
+ <activity android:name=".UnresponsiveGestureMonitorActivity"
+ android:label="Unresponsive gesture monitor"
+ android:process=":externalProcess">
+ </activity>
+
+ </application>
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.test.input"
+ android:label="Input Tests"/>
+</manifest>
diff --git a/tests/Input/AndroidTest.xml b/tests/Input/AndroidTest.xml
new file mode 100644
index 000000000000..c62db1ea5ca9
--- /dev/null
+++ b/tests/Input/AndroidTest.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright 2020 Google Inc. All Rights Reserved.
+ -->
+<configuration description="Runs Input Tests">
+ <option name="test-tag" value="InputTests" />
+ <target_preparer class="com.android.tradefed.targetprep.DeviceSetup">
+ <!-- keeps the screen on during tests -->
+ <option name="screen-always-on" value="on" />
+ <!-- prevents the phone from restarting -->
+ <option name="force-skip-system-props" value="true" />
+ </target_preparer>
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true"/>
+ <option name="test-file-name" value="InputTests.apk"/>
+
+ </target_preparer>
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest">
+ <option name="package" value="com.android.test.input"/>
+ <option name="exclude-annotation" value="androidx.test.filters.FlakyTest" />
+ <option name="shell-timeout" value="660s" />
+ <option name="test-timeout" value="600s" />
+ <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
+ </test>
+</configuration>
diff --git a/tests/Input/TEST_MAPPING b/tests/Input/TEST_MAPPING
new file mode 100644
index 000000000000..15b2bfa9fdc1
--- /dev/null
+++ b/tests/Input/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "presubmit": [
+ {
+ "name": "InputTests"
+ }
+ ]
+}
diff --git a/tests/Input/src/com/android/test/input/AnrTest.kt b/tests/Input/src/com/android/test/input/AnrTest.kt
new file mode 100644
index 000000000000..4da3eca25ea0
--- /dev/null
+++ b/tests/Input/src/com/android/test/input/AnrTest.kt
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2020 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.test.input
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.filters.MediumTest
+
+import android.graphics.Rect
+import android.os.SystemClock
+import android.provider.Settings
+import android.provider.Settings.Global.HIDE_ERROR_DIALOGS
+import android.support.test.uiautomator.By
+import android.support.test.uiautomator.UiDevice
+import android.support.test.uiautomator.UiObject2
+import android.support.test.uiautomator.Until
+import android.view.InputDevice
+import android.view.MotionEvent
+
+import org.junit.After
+import org.junit.Assert.fail
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/**
+ * This test makes sure that an unresponsive gesture monitor gets an ANR.
+ *
+ * The gesture monitor must be registered from a different process than the instrumented process.
+ * Otherwise, when the test runs, you will get:
+ * Test failed to run to completion.
+ * Reason: 'Instrumentation run failed due to 'keyDispatchingTimedOut''.
+ * Check device logcat for details
+ * RUNNER ERROR: Instrumentation run failed due to 'keyDispatchingTimedOut'
+ */
+@MediumTest
+@RunWith(AndroidJUnit4::class)
+class AnrTest {
+ companion object {
+ private const val TAG = "AnrTest"
+ }
+
+ val mInstrumentation = InstrumentationRegistry.getInstrumentation()
+ var mHideErrorDialogs = 0
+
+ @Before
+ fun setUp() {
+ val contentResolver = mInstrumentation.targetContext.contentResolver
+ mHideErrorDialogs = Settings.Global.getInt(contentResolver, HIDE_ERROR_DIALOGS, 0)
+ Settings.Global.putInt(contentResolver, HIDE_ERROR_DIALOGS, 0)
+ }
+
+ @After
+ fun tearDown() {
+ val contentResolver = mInstrumentation.targetContext.contentResolver
+ Settings.Global.putInt(contentResolver, HIDE_ERROR_DIALOGS, mHideErrorDialogs)
+ }
+
+ @Test
+ fun testGestureMonitorAnr() {
+ startUnresponsiveActivity()
+ val uiDevice: UiDevice = UiDevice.getInstance(mInstrumentation)
+ val obj: UiObject2? = uiDevice.wait(Until.findObject(
+ By.text("Unresponsive gesture monitor")), 10000)
+
+ if (obj == null) {
+ fail("Could not find unresponsive activity")
+ return
+ }
+
+ val rect: Rect = obj.visibleBounds
+ val downTime = SystemClock.uptimeMillis()
+ val downEvent = MotionEvent.obtain(downTime, downTime,
+ MotionEvent.ACTION_DOWN, rect.left.toFloat(), rect.top.toFloat(), 0 /* metaState */)
+ downEvent.source = InputDevice.SOURCE_TOUCHSCREEN
+
+ mInstrumentation.uiAutomation.injectInputEvent(downEvent, false /* sync*/)
+
+ // Todo: replace using timeout from android.hardware.input.IInputManager
+ SystemClock.sleep(5000) // default ANR timeout for gesture monitors
+
+ clickCloseAppOnAnrDialog()
+ }
+
+ private fun clickCloseAppOnAnrDialog() {
+ // Find anr dialog and kill app
+ val uiDevice: UiDevice = UiDevice.getInstance(mInstrumentation)
+ val closeAppButton: UiObject2? =
+ uiDevice.wait(Until.findObject(By.res("android:id/aerr_close")), 20000)
+ if (closeAppButton == null) {
+ fail("Could not find anr dialog")
+ return
+ }
+ closeAppButton.click()
+ }
+
+ private fun startUnresponsiveActivity() {
+ val flags = " -W -n "
+ val startCmd = "am start $flags com.android.test.input/.UnresponsiveGestureMonitorActivity"
+ mInstrumentation.uiAutomation.executeShellCommand(startCmd)
+ }
+} \ No newline at end of file
diff --git a/tests/Input/src/com/android/test/input/InputDeviceTest.java b/tests/Input/src/com/android/test/input/InputDeviceTest.java
new file mode 100644
index 000000000000..63500774816a
--- /dev/null
+++ b/tests/Input/src/com/android/test/input/InputDeviceTest.java
@@ -0,0 +1,98 @@
+/*
+ * 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 android.view;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.os.Parcel;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class InputDeviceTest {
+ private static final float DELTA = 0.01f;
+ private static final int DEVICE_ID = 1000;
+
+ private void assertMotionRangeEquals(InputDevice.MotionRange range,
+ InputDevice.MotionRange outRange) {
+ assertEquals(range.getAxis(), outRange.getAxis());
+ assertEquals(range.getSource(), outRange.getSource());
+ assertEquals(range.getMin(), outRange.getMin(), DELTA);
+ assertEquals(range.getMax(), outRange.getMax(), DELTA);
+ assertEquals(range.getFlat(), outRange.getFlat(), DELTA);
+ assertEquals(range.getFuzz(), outRange.getFuzz(), DELTA);
+ assertEquals(range.getResolution(), outRange.getResolution(), DELTA);
+ }
+
+ private void assertDeviceEquals(InputDevice device, InputDevice outDevice) {
+ assertEquals(device.getId(), outDevice.getId());
+ assertEquals(device.getGeneration(), outDevice.getGeneration());
+ assertEquals(device.getControllerNumber(), outDevice.getControllerNumber());
+ assertEquals(device.getName(), outDevice.getName());
+ assertEquals(device.getVendorId(), outDevice.getVendorId());
+ assertEquals(device.getProductId(), outDevice.getProductId());
+ assertEquals(device.getDescriptor(), outDevice.getDescriptor());
+ assertEquals(device.isExternal(), outDevice.isExternal());
+ assertEquals(device.getSources(), outDevice.getSources());
+ assertEquals(device.getKeyboardType(), outDevice.getKeyboardType());
+ assertEquals(device.getMotionRanges().size(), outDevice.getMotionRanges().size());
+
+ KeyCharacterMap keyCharacterMap = device.getKeyCharacterMap();
+ KeyCharacterMap outKeyCharacterMap = outDevice.getKeyCharacterMap();
+ assertTrue("keyCharacterMap not equal", keyCharacterMap.equals(outKeyCharacterMap));
+
+ for (int j = 0; j < device.getMotionRanges().size(); j++) {
+ assertMotionRangeEquals(device.getMotionRanges().get(j),
+ outDevice.getMotionRanges().get(j));
+ }
+ }
+
+ private void assertInputDeviceParcelUnparcel(KeyCharacterMap keyCharacterMap) {
+ final InputDevice device =
+ new InputDevice(DEVICE_ID, 0 /* generation */, 0 /* controllerNumber */, "name",
+ 0 /* vendorId */, 0 /* productId */, "descriptor", true /* isExternal */,
+ 0 /* sources */, 0 /* keyboardType */, keyCharacterMap,
+ false /* hasVibrator */, false /* hasMicrophone */, false /* hasButtonUnderpad */,
+ true /* hasSensor */, false /* hasBattery */);
+
+ Parcel parcel = Parcel.obtain();
+ device.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+
+ InputDevice outDevice = InputDevice.CREATOR.createFromParcel(parcel);
+ assertDeviceEquals(device, outDevice);
+ }
+
+ @Test
+ public void testParcelUnparcelInputDevice_VirtualCharacterMap() {
+ final KeyCharacterMap keyCharacterMap =
+ KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD);
+ assertInputDeviceParcelUnparcel(keyCharacterMap);
+ }
+
+ @Test
+ public void testParcelUnparcelInputDevice_EmptyCharacterMap() {
+ final KeyCharacterMap keyCharacterMap = KeyCharacterMap.obtainEmptyMap(DEVICE_ID);
+ assertInputDeviceParcelUnparcel(keyCharacterMap);
+ }
+}
diff --git a/tests/Input/src/com/android/test/input/InputEventAssignerTest.kt b/tests/Input/src/com/android/test/input/InputEventAssignerTest.kt
new file mode 100644
index 000000000000..c1a86b3a2dac
--- /dev/null
+++ b/tests/Input/src/com/android/test/input/InputEventAssignerTest.kt
@@ -0,0 +1,130 @@
+/*
+ * 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.test.input
+
+import android.view.InputDevice.SOURCE_MOUSE
+import android.view.InputDevice.SOURCE_TOUCHSCREEN
+import android.view.InputEventAssigner
+import android.view.KeyEvent
+import android.view.MotionEvent
+import org.junit.Assert.assertEquals
+import org.junit.Test
+
+/**
+ * Create a MotionEvent with the provided action, eventTime, and source
+ */
+fun createMotionEvent(action: Int, eventTime: Long, source: Int): MotionEvent {
+ val downTime: Long = 10
+ val x = 1f
+ val y = 2f
+ val pressure = 3f
+ val size = 1f
+ val metaState = 0
+ val xPrecision = 0f
+ val yPrecision = 0f
+ val deviceId = 1
+ val edgeFlags = 0
+ val displayId = 0
+ return MotionEvent.obtain(downTime, eventTime, action, x, y, pressure, size, metaState,
+ xPrecision, yPrecision, deviceId, edgeFlags, source, displayId)
+}
+
+private fun createKeyEvent(action: Int, eventTime: Long): KeyEvent {
+ val code = KeyEvent.KEYCODE_A
+ val repeat = 0
+ return KeyEvent(eventTime, eventTime, action, code, repeat)
+}
+
+class InputEventAssignerTest {
+ companion object {
+ private const val TAG = "InputEventAssignerTest"
+ }
+
+ /**
+ * A single MOVE event should be assigned to the next available frame.
+ */
+ @Test
+ fun testTouchGesture() {
+ val assigner = InputEventAssigner()
+ val event = createMotionEvent(MotionEvent.ACTION_MOVE, 10, SOURCE_TOUCHSCREEN)
+ val eventId = assigner.processEvent(event)
+ assertEquals(event.id, eventId)
+ }
+
+ /**
+ * DOWN event should be used until a vsync comes in. After vsync, the latest event should be
+ * produced.
+ */
+ @Test
+ fun testTouchDownWithMove() {
+ val assigner = InputEventAssigner()
+ val down = createMotionEvent(MotionEvent.ACTION_DOWN, 10, SOURCE_TOUCHSCREEN)
+ val move1 = createMotionEvent(MotionEvent.ACTION_MOVE, 12, SOURCE_TOUCHSCREEN)
+ val move2 = createMotionEvent(MotionEvent.ACTION_MOVE, 13, SOURCE_TOUCHSCREEN)
+ val move3 = createMotionEvent(MotionEvent.ACTION_MOVE, 14, SOURCE_TOUCHSCREEN)
+ val move4 = createMotionEvent(MotionEvent.ACTION_MOVE, 15, SOURCE_TOUCHSCREEN)
+ var eventId = assigner.processEvent(down)
+ assertEquals(down.id, eventId)
+ eventId = assigner.processEvent(move1)
+ assertEquals(down.id, eventId)
+ eventId = assigner.processEvent(move2)
+ // Even though we already had 2 move events, there was no choreographer callback yet.
+ // Therefore, we should still get the id of the down event
+ assertEquals(down.id, eventId)
+
+ // Now send CALLBACK_INPUT to the assigner. It should provide the latest motion event
+ assigner.notifyFrameProcessed()
+ eventId = assigner.processEvent(move3)
+ assertEquals(move3.id, eventId)
+ eventId = assigner.processEvent(move4)
+ assertEquals(move4.id, eventId)
+ }
+
+ /**
+ * Similar to the above test, but with SOURCE_MOUSE. Since we don't have down latency
+ * concept for non-touchscreens, the latest input event will be used.
+ */
+ @Test
+ fun testMouseDownWithMove() {
+ val assigner = InputEventAssigner()
+ val down = createMotionEvent(MotionEvent.ACTION_DOWN, 10, SOURCE_MOUSE)
+ val move1 = createMotionEvent(MotionEvent.ACTION_MOVE, 12, SOURCE_MOUSE)
+ var eventId = assigner.processEvent(down)
+ assertEquals(down.id, eventId)
+ eventId = assigner.processEvent(move1)
+ assertEquals(move1.id, eventId)
+ }
+
+ /**
+ * KeyEvents are processed immediately, so the latest event should be returned.
+ */
+ @Test
+ fun testKeyEvent() {
+ val assigner = InputEventAssigner()
+ val down = createKeyEvent(KeyEvent.ACTION_DOWN, 20)
+ var eventId = assigner.processEvent(down)
+ assertEquals(down.id, eventId)
+ val up = createKeyEvent(KeyEvent.ACTION_UP, 21)
+ eventId = assigner.processEvent(up)
+ // DOWN is only sticky for Motions, not for keys
+ assertEquals(up.id, eventId)
+ assigner.notifyFrameProcessed()
+ val down2 = createKeyEvent(KeyEvent.ACTION_DOWN, 22)
+ eventId = assigner.processEvent(down2)
+ assertEquals(down2.id, eventId)
+ }
+}
diff --git a/tests/Input/src/com/android/test/input/InputEventSenderAndReceiverTest.kt b/tests/Input/src/com/android/test/input/InputEventSenderAndReceiverTest.kt
new file mode 100644
index 000000000000..014efc2b954c
--- /dev/null
+++ b/tests/Input/src/com/android/test/input/InputEventSenderAndReceiverTest.kt
@@ -0,0 +1,165 @@
+/*
+ * 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.test.input
+
+import android.os.HandlerThread
+import android.os.InputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS
+import android.os.Looper
+import android.view.InputChannel
+import android.view.InputEvent
+import android.view.InputEventReceiver
+import android.view.InputEventSender
+import android.view.KeyEvent
+import android.view.MotionEvent
+import java.util.concurrent.LinkedBlockingQueue
+import java.util.concurrent.TimeUnit
+import org.junit.Assert.assertEquals
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+
+private fun assertKeyEvent(expected: KeyEvent, received: KeyEvent) {
+ assertEquals(expected.action, received.action)
+ assertEquals(expected.deviceId, received.deviceId)
+ assertEquals(expected.downTime, received.downTime)
+ assertEquals(expected.eventTime, received.eventTime)
+ assertEquals(expected.keyCode, received.keyCode)
+ assertEquals(expected.scanCode, received.scanCode)
+ assertEquals(expected.repeatCount, received.repeatCount)
+ assertEquals(expected.metaState, received.metaState)
+ assertEquals(expected.flags, received.flags)
+ assertEquals(expected.source, received.source)
+ assertEquals(expected.displayId, received.displayId)
+}
+
+private fun <T> getEvent(queue: LinkedBlockingQueue<T>): T {
+ try {
+ return queue.poll(DEFAULT_DISPATCHING_TIMEOUT_MILLIS.toLong(), TimeUnit.MILLISECONDS)
+ } catch (e: InterruptedException) {
+ throw RuntimeException("Unexpectedly interrupted while waiting for event")
+ }
+}
+
+class TestInputEventReceiver(channel: InputChannel, looper: Looper) :
+ InputEventReceiver(channel, looper) {
+ private val mInputEvents = LinkedBlockingQueue<InputEvent>()
+
+ override fun onInputEvent(event: InputEvent) {
+ when (event) {
+ is KeyEvent -> mInputEvents.put(KeyEvent.obtain(event))
+ is MotionEvent -> mInputEvents.put(MotionEvent.obtain(event))
+ else -> throw Exception("Received $event is neither a key nor a motion")
+ }
+ finishInputEvent(event, true /*handled*/)
+ }
+
+ fun getInputEvent(): InputEvent {
+ return getEvent(mInputEvents)
+ }
+}
+
+class TestInputEventSender(channel: InputChannel, looper: Looper) :
+ InputEventSender(channel, looper) {
+ data class FinishedSignal(val seq: Int, val handled: Boolean)
+ data class Timeline(val inputEventId: Int, val gpuCompletedTime: Long, val presentTime: Long)
+
+ private val mFinishedSignals = LinkedBlockingQueue<FinishedSignal>()
+ private val mTimelines = LinkedBlockingQueue<Timeline>()
+
+ override fun onInputEventFinished(seq: Int, handled: Boolean) {
+ mFinishedSignals.put(FinishedSignal(seq, handled))
+ }
+
+ override fun onTimelineReported(inputEventId: Int, gpuCompletedTime: Long, presentTime: Long) {
+ mTimelines.put(Timeline(inputEventId, gpuCompletedTime, presentTime))
+ }
+
+ fun getFinishedSignal(): FinishedSignal {
+ return getEvent(mFinishedSignals)
+ }
+
+ fun getTimeline(): Timeline {
+ return getEvent(mTimelines)
+ }
+}
+
+class InputEventSenderAndReceiverTest {
+ companion object {
+ private const val TAG = "InputEventSenderAndReceiverTest"
+ }
+ private val mHandlerThread = HandlerThread("Process input events")
+ private lateinit var mReceiver: TestInputEventReceiver
+ private lateinit var mSender: TestInputEventSender
+
+ @Before
+ fun setUp() {
+ val channels = InputChannel.openInputChannelPair("TestChannel")
+ mHandlerThread.start()
+
+ val looper = mHandlerThread.getLooper()
+ mSender = TestInputEventSender(channels[0], looper)
+ mReceiver = TestInputEventReceiver(channels[1], looper)
+ }
+
+ @After
+ fun tearDown() {
+ mHandlerThread.quitSafely()
+ }
+
+ @Test
+ fun testSendAndReceiveKey() {
+ val key = KeyEvent(1 /*downTime*/, 1 /*eventTime*/, KeyEvent.ACTION_DOWN,
+ KeyEvent.KEYCODE_A, 0 /*repeat*/)
+ val seq = 10
+ mSender.sendInputEvent(seq, key)
+ val receivedKey = mReceiver.getInputEvent() as KeyEvent
+ val finishedSignal = mSender.getFinishedSignal()
+
+ // Check receiver
+ assertKeyEvent(key, receivedKey)
+
+ // Check sender
+ assertEquals(TestInputEventSender.FinishedSignal(seq, handled = true), finishedSignal)
+ }
+
+ // The timeline case is slightly unusual because it goes from InputConsumer to InputPublisher.
+ @Test
+ fun testSendAndReceiveTimeline() {
+ val sent = TestInputEventSender.Timeline(
+ inputEventId = 1, gpuCompletedTime = 2, presentTime = 3)
+ mReceiver.reportTimeline(sent.inputEventId, sent.gpuCompletedTime, sent.presentTime)
+ val received = mSender.getTimeline()
+ assertEquals(sent, received)
+ }
+
+ // If an invalid timeline is sent, the channel should get closed. This helps surface any
+ // app-originating bugs early, and forces the work-around to happen in the early stages of the
+ // event processing.
+ @Test
+ fun testSendAndReceiveInvalidTimeline() {
+ val sent = TestInputEventSender.Timeline(
+ inputEventId = 1, gpuCompletedTime = 3, presentTime = 2)
+ mReceiver.reportTimeline(sent.inputEventId, sent.gpuCompletedTime, sent.presentTime)
+ val received = mSender.getTimeline()
+ assertEquals(null, received)
+ // Sender will no longer receive callbacks for this fd, even if receiver sends a valid
+ // timeline later
+ mReceiver.reportTimeline(2 /*inputEventId*/, 3 /*gpuCompletedTime*/, 4 /*presentTime*/)
+ val receivedSecondTimeline = mSender.getTimeline()
+ assertEquals(null, receivedSecondTimeline)
+ }
+}
diff --git a/tests/Input/src/com/android/test/input/UnresponsiveGestureMonitorActivity.kt b/tests/Input/src/com/android/test/input/UnresponsiveGestureMonitorActivity.kt
new file mode 100644
index 000000000000..d83a4570fedc
--- /dev/null
+++ b/tests/Input/src/com/android/test/input/UnresponsiveGestureMonitorActivity.kt
@@ -0,0 +1,52 @@
+/**
+ * Copyright (c) 2020 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.test.input
+
+import android.app.Activity
+import android.hardware.input.InputManager
+import android.os.Bundle
+import android.os.Looper
+import android.util.Log
+import android.view.InputChannel
+import android.view.InputEvent
+import android.view.InputEventReceiver
+import android.view.InputMonitor
+
+class UnresponsiveReceiver(channel: InputChannel, looper: Looper) :
+ InputEventReceiver(channel, looper) {
+ companion object {
+ const val TAG = "UnresponsiveReceiver"
+ }
+ override fun onInputEvent(event: InputEvent) {
+ Log.i(TAG, "Received $event")
+ // Not calling 'finishInputEvent' in order to trigger the ANR
+ }
+}
+
+class UnresponsiveGestureMonitorActivity : Activity() {
+ companion object {
+ const val MONITOR_NAME = "unresponsive gesture monitor"
+ }
+ private lateinit var mInputEventReceiver: InputEventReceiver
+ private lateinit var mInputMonitor: InputMonitor
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ mInputMonitor = InputManager.getInstance().monitorGestureInput(MONITOR_NAME, displayId)
+ mInputEventReceiver = UnresponsiveReceiver(
+ mInputMonitor.getInputChannel(), Looper.myLooper())
+ }
+}
diff --git a/tests/Input/src/com/android/test/input/ViewFrameInfoTest.kt b/tests/Input/src/com/android/test/input/ViewFrameInfoTest.kt
new file mode 100644
index 000000000000..6ef1ecdae59b
--- /dev/null
+++ b/tests/Input/src/com/android/test/input/ViewFrameInfoTest.kt
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2020 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.test.input
+
+import android.graphics.FrameInfo
+import android.os.IInputConstants.INVALID_INPUT_EVENT_ID
+import android.os.SystemClock
+import android.view.ViewFrameInfo
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+
+class ViewFrameInfoTest {
+ companion object {
+ private const val TAG = "ViewFrameInfoTest"
+ }
+ private val mViewFrameInfo = ViewFrameInfo()
+ private var mTimeStarted: Long = 0
+
+ @Before
+ fun setUp() {
+ mViewFrameInfo.reset()
+ mViewFrameInfo.setInputEvent(139)
+ mViewFrameInfo.flags = mViewFrameInfo.flags or FrameInfo.FLAG_WINDOW_VISIBILITY_CHANGED
+ mTimeStarted = SystemClock.uptimeNanos()
+ mViewFrameInfo.markDrawStart()
+ }
+
+ @Test
+ fun testPopulateFields() {
+ assertThat(mViewFrameInfo.drawStart).isGreaterThan(mTimeStarted)
+ assertThat(mViewFrameInfo.flags).isEqualTo(FrameInfo.FLAG_WINDOW_VISIBILITY_CHANGED)
+ }
+
+ @Test
+ fun testReset() {
+ mViewFrameInfo.reset()
+ // Ensure that the original object is reset correctly
+ assertThat(mViewFrameInfo.drawStart).isEqualTo(0)
+ assertThat(mViewFrameInfo.flags).isEqualTo(0)
+ }
+
+ @Test
+ fun testUpdateFrameInfoFromViewFrameInfo() {
+ val frameInfo = FrameInfo()
+ // By default, all values should be zero
+ assertThat(frameInfo.frameInfo[FrameInfo.INPUT_EVENT_ID]).isEqualTo(INVALID_INPUT_EVENT_ID)
+ assertThat(frameInfo.frameInfo[FrameInfo.FLAGS]).isEqualTo(0)
+ assertThat(frameInfo.frameInfo[FrameInfo.DRAW_START]).isEqualTo(0)
+
+ // The values inside FrameInfo should match those from ViewFrameInfo after we update them
+ mViewFrameInfo.populateFrameInfo(frameInfo)
+ assertThat(frameInfo.frameInfo[FrameInfo.INPUT_EVENT_ID]).isEqualTo(139)
+ assertThat(frameInfo.frameInfo[FrameInfo.FLAGS]).isEqualTo(
+ FrameInfo.FLAG_WINDOW_VISIBILITY_CHANGED)
+ assertThat(frameInfo.frameInfo[FrameInfo.DRAW_START]).isGreaterThan(mTimeStarted)
+ }
+} \ No newline at end of file
diff --git a/tests/Internal/Android.bp b/tests/Internal/Android.bp
index 8546ec204fff..ef45864dd93b 100644
--- a/tests/Internal/Android.bp
+++ b/tests/Internal/Android.bp
@@ -20,6 +20,7 @@ android_test {
"androidx.test.rules",
"mockito-target-minus-junit4",
"truth-prebuilt",
+ "platform-test-annotations",
],
java_resource_dirs: ["res"],
certificate: "platform",
diff --git a/tests/Internal/AndroidManifest.xml b/tests/Internal/AndroidManifest.xml
index c85c3b12504a..dbba24531769 100644
--- a/tests/Internal/AndroidManifest.xml
+++ b/tests/Internal/AndroidManifest.xml
@@ -16,29 +16,30 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.internal.tests">
- <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
- <uses-permission android:name="android.permission.BIND_WALLPAPER" />
+ package="com.android.internal.tests">
+ <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
+ <uses-permission android:name="android.permission.BIND_WALLPAPER"/>
<application>
- <uses-library android:name="android.test.runner" />
+ <uses-library android:name="android.test.runner"/>
<service android:name="stub.DummyWallpaperService"
- android:enabled="true"
- android:directBootAware="true"
- android:label="Dummy wallpaper"
- android:permission="android.permission.BIND_WALLPAPER">
+ android:enabled="true"
+ android:directBootAware="true"
+ android:label="Dummy wallpaper"
+ android:permission="android.permission.BIND_WALLPAPER"
+ android:exported="true">
<intent-filter>
- <action android:name="android.service.wallpaper.WallpaperService" />
+ <action android:name="android.service.wallpaper.WallpaperService"/>
</intent-filter>
<!-- Link to XML that defines the wallpaper info. -->
<meta-data android:name="android.service.wallpaper"
- android:resource="@xml/livewallpaper" />
+ android:resource="@xml/livewallpaper"/>
</service>
</application>
<instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
- android:targetPackage="com.android.internal.tests"
- android:label="Internal Tests" />
+ android:targetPackage="com.android.internal.tests"
+ android:label="Internal Tests"/>
</manifest>
diff --git a/tests/Internal/src/android/app/WallpaperColorsTest.java b/tests/Internal/src/android/app/WallpaperColorsTest.java
index e9bac717daa1..9ffb236d3f59 100644
--- a/tests/Internal/src/android/app/WallpaperColorsTest.java
+++ b/tests/Internal/src/android/app/WallpaperColorsTest.java
@@ -20,6 +20,7 @@ import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
+import android.os.Parcel;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -47,7 +48,7 @@ public class WallpaperColorsTest {
}
/**
- * Sanity check to guarantee that white supports dark text and black doesn't
+ * Check that white supports dark text and black doesn't
*/
@Test
public void colorHintsTest() {
@@ -106,4 +107,26 @@ public class WallpaperColorsTest {
// This would crash:
canvas.drawBitmap(image, 0, 0, new Paint());
}
+
+ /**
+ * Parcelled WallpaperColors object should equal the original.
+ */
+ @Test
+ public void testParcelUnparcel() {
+ Bitmap image = Bitmap.createBitmap(300, 300, Bitmap.Config.ARGB_8888);
+ WallpaperColors colors = WallpaperColors.fromBitmap(image);
+ Parcel parcel = Parcel.obtain();
+ colors.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ WallpaperColors reconstructed = new WallpaperColors(parcel);
+ parcel.recycle();
+ Assert.assertEquals("WallpaperColors recreated from Parcel should equal original",
+ colors, reconstructed);
+ Assert.assertEquals("getAllColors() on WallpaperColors recreated from Parcel should"
+ + "return the same as the original",
+ colors.getAllColors(), reconstructed.getAllColors());
+ Assert.assertEquals("getMainColors() on WallpaperColors recreated from Parcel should"
+ + "return the same as the original",
+ colors.getMainColors(), reconstructed.getMainColors());
+ }
}
diff --git a/tests/Internal/src/com/android/internal/protolog/ProtoLogImplTest.java b/tests/Internal/src/com/android/internal/protolog/ProtoLogImplTest.java
new file mode 100644
index 000000000000..3db011683a86
--- /dev/null
+++ b/tests/Internal/src/com/android/internal/protolog/ProtoLogImplTest.java
@@ -0,0 +1,462 @@
+/*
+ * Copyright (C) 2019 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 androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import static com.android.internal.protolog.ProtoLogImpl.PROTOLOG_VERSION;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.os.SystemClock;
+import android.platform.test.annotations.Presubmit;
+import android.util.proto.ProtoInputStream;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.internal.protolog.common.IProtoLogGroup;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintWriter;
+import java.util.LinkedList;
+
+/**
+ * Test class for {@link ProtoLogImpl}.
+ */
+@SuppressWarnings("ConstantConditions")
+@SmallTest
+@Presubmit
+@RunWith(JUnit4.class)
+public class ProtoLogImplTest {
+
+ private static final byte[] MAGIC_HEADER = new byte[]{
+ 0x9, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x4c, 0x4f, 0x47
+ };
+
+ private ProtoLogImpl mProtoLog;
+ private File mFile;
+
+ @Mock
+ private ProtoLogViewerConfigReader mReader;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ final Context testContext = getInstrumentation().getContext();
+ mFile = testContext.getFileStreamPath("tracing_test.dat");
+ //noinspection ResultOfMethodCallIgnored
+ mFile.delete();
+ mProtoLog = new ProtoLogImpl(mFile, 1024 * 1024, mReader);
+ }
+
+ @After
+ public void tearDown() {
+ if (mFile != null) {
+ //noinspection ResultOfMethodCallIgnored
+ mFile.delete();
+ }
+ ProtoLogImpl.setSingleInstance(null);
+ }
+
+ @Test
+ public void isEnabled_returnsFalseByDefault() {
+ assertFalse(mProtoLog.isProtoEnabled());
+ }
+
+ @Test
+ public void isEnabled_returnsTrueAfterStart() {
+ mProtoLog.startProtoLog(mock(PrintWriter.class));
+ assertTrue(mProtoLog.isProtoEnabled());
+ }
+
+ @Test
+ public void isEnabled_returnsFalseAfterStop() {
+ mProtoLog.startProtoLog(mock(PrintWriter.class));
+ mProtoLog.stopProtoLog(mock(PrintWriter.class), true);
+ assertFalse(mProtoLog.isProtoEnabled());
+ }
+
+ @Test
+ public void logFile_startsWithMagicHeader() throws Exception {
+ mProtoLog.startProtoLog(mock(PrintWriter.class));
+ mProtoLog.stopProtoLog(mock(PrintWriter.class), true);
+
+ assertTrue("Log file should exist", mFile.exists());
+
+ byte[] header = new byte[MAGIC_HEADER.length];
+ try (InputStream is = new FileInputStream(mFile)) {
+ assertEquals(MAGIC_HEADER.length, is.read(header));
+ assertArrayEquals(MAGIC_HEADER, header);
+ }
+ }
+
+ @Test
+ public void getSingleInstance() {
+ ProtoLogImpl mockedProtoLog = mock(ProtoLogImpl.class);
+ ProtoLogImpl.setSingleInstance(mockedProtoLog);
+ assertSame(mockedProtoLog, ProtoLogImpl.getSingleInstance());
+ }
+
+ @Test
+ public void d_logCalled() {
+ ProtoLogImpl mockedProtoLog = mock(ProtoLogImpl.class);
+ ProtoLogImpl.setSingleInstance(mockedProtoLog);
+ ProtoLogImpl.d(TestProtoLogGroup.TEST_GROUP, 1234, 4321, "test %d");
+ verify(mockedProtoLog).log(eq(ProtoLogImpl.LogLevel.DEBUG), eq(
+ TestProtoLogGroup.TEST_GROUP),
+ eq(1234), eq(4321), eq("test %d"), eq(new Object[]{}));
+ }
+
+ @Test
+ public void v_logCalled() {
+ ProtoLogImpl mockedProtoLog = mock(ProtoLogImpl.class);
+ ProtoLogImpl.setSingleInstance(mockedProtoLog);
+ ProtoLogImpl.v(TestProtoLogGroup.TEST_GROUP, 1234, 4321, "test %d");
+ verify(mockedProtoLog).log(eq(ProtoLogImpl.LogLevel.VERBOSE), eq(
+ TestProtoLogGroup.TEST_GROUP),
+ eq(1234), eq(4321), eq("test %d"), eq(new Object[]{}));
+ }
+
+ @Test
+ public void i_logCalled() {
+ ProtoLogImpl mockedProtoLog = mock(ProtoLogImpl.class);
+ ProtoLogImpl.setSingleInstance(mockedProtoLog);
+ ProtoLogImpl.i(TestProtoLogGroup.TEST_GROUP, 1234, 4321, "test %d");
+ verify(mockedProtoLog).log(eq(ProtoLogImpl.LogLevel.INFO), eq(
+ TestProtoLogGroup.TEST_GROUP),
+ eq(1234), eq(4321), eq("test %d"), eq(new Object[]{}));
+ }
+
+ @Test
+ public void w_logCalled() {
+ ProtoLogImpl mockedProtoLog = mock(ProtoLogImpl.class);
+ ProtoLogImpl.setSingleInstance(mockedProtoLog);
+ ProtoLogImpl.w(TestProtoLogGroup.TEST_GROUP, 1234,
+ 4321, "test %d");
+ verify(mockedProtoLog).log(eq(ProtoLogImpl.LogLevel.WARN), eq(
+ TestProtoLogGroup.TEST_GROUP),
+ eq(1234), eq(4321), eq("test %d"), eq(new Object[]{}));
+ }
+
+ @Test
+ public void e_logCalled() {
+ ProtoLogImpl mockedProtoLog = mock(ProtoLogImpl.class);
+ ProtoLogImpl.setSingleInstance(mockedProtoLog);
+ ProtoLogImpl.e(TestProtoLogGroup.TEST_GROUP, 1234, 4321, "test %d");
+ verify(mockedProtoLog).log(eq(ProtoLogImpl.LogLevel.ERROR), eq(
+ TestProtoLogGroup.TEST_GROUP),
+ eq(1234), eq(4321), eq("test %d"), eq(new Object[]{}));
+ }
+
+ @Test
+ public void wtf_logCalled() {
+ ProtoLogImpl mockedProtoLog = mock(ProtoLogImpl.class);
+ ProtoLogImpl.setSingleInstance(mockedProtoLog);
+ ProtoLogImpl.wtf(TestProtoLogGroup.TEST_GROUP,
+ 1234, 4321, "test %d");
+ verify(mockedProtoLog).log(eq(ProtoLogImpl.LogLevel.WTF), eq(
+ TestProtoLogGroup.TEST_GROUP),
+ eq(1234), eq(4321), eq("test %d"), eq(new Object[]{}));
+ }
+
+ @Test
+ public void log_logcatEnabledExternalMessage() {
+ when(mReader.getViewerString(anyInt())).thenReturn("test %b %d %% %o %x %e %g %s %f");
+ ProtoLogImpl implSpy = Mockito.spy(mProtoLog);
+ TestProtoLogGroup.TEST_GROUP.setLogToLogcat(true);
+ TestProtoLogGroup.TEST_GROUP.setLogToProto(false);
+
+ implSpy.log(
+ ProtoLogImpl.LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, 1234, 4321, null,
+ new Object[]{true, 10000, 20000, 30000, 0.0001, 0.00002, "test", 0.000003});
+
+ verify(implSpy).passToLogcat(eq(TestProtoLogGroup.TEST_GROUP.getTag()), eq(
+ ProtoLogImpl.LogLevel.INFO),
+ eq("test true 10000 % 47040 7530 1.000000e-04 2.00000e-05 test 0.000003"));
+ verify(mReader).getViewerString(eq(1234));
+ }
+
+ @Test
+ public void log_logcatEnabledInvalidMessage() {
+ when(mReader.getViewerString(anyInt())).thenReturn("test %b %d %% %o %x %e %g %s %f");
+ ProtoLogImpl implSpy = Mockito.spy(mProtoLog);
+ TestProtoLogGroup.TEST_GROUP.setLogToLogcat(true);
+ TestProtoLogGroup.TEST_GROUP.setLogToProto(false);
+
+ implSpy.log(
+ ProtoLogImpl.LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, 1234, 4321, null,
+ new Object[]{true, 10000, 0.0001, 0.00002, "test"});
+
+ verify(implSpy).passToLogcat(eq(TestProtoLogGroup.TEST_GROUP.getTag()), eq(
+ ProtoLogImpl.LogLevel.INFO),
+ eq("UNKNOWN MESSAGE (1234) true 10000 1.0E-4 2.0E-5 test"));
+ verify(mReader).getViewerString(eq(1234));
+ }
+
+ @Test
+ public void log_logcatEnabledInlineMessage() {
+ when(mReader.getViewerString(anyInt())).thenReturn("test %d");
+ ProtoLogImpl implSpy = Mockito.spy(mProtoLog);
+ TestProtoLogGroup.TEST_GROUP.setLogToLogcat(true);
+ TestProtoLogGroup.TEST_GROUP.setLogToProto(false);
+
+ implSpy.log(
+ ProtoLogImpl.LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, 1234, 4321, "test %d",
+ new Object[]{5});
+
+ verify(implSpy).passToLogcat(eq(TestProtoLogGroup.TEST_GROUP.getTag()), eq(
+ ProtoLogImpl.LogLevel.INFO), eq("test 5"));
+ verify(mReader, never()).getViewerString(anyInt());
+ }
+
+ @Test
+ public void log_logcatEnabledNoMessage() {
+ when(mReader.getViewerString(anyInt())).thenReturn(null);
+ ProtoLogImpl implSpy = Mockito.spy(mProtoLog);
+ TestProtoLogGroup.TEST_GROUP.setLogToLogcat(true);
+ TestProtoLogGroup.TEST_GROUP.setLogToProto(false);
+
+ implSpy.log(
+ ProtoLogImpl.LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, 1234, 4321, null,
+ new Object[]{5});
+
+ verify(implSpy).passToLogcat(eq(TestProtoLogGroup.TEST_GROUP.getTag()), eq(
+ ProtoLogImpl.LogLevel.INFO), eq("UNKNOWN MESSAGE (1234) 5"));
+ verify(mReader).getViewerString(eq(1234));
+ }
+
+ @Test
+ public void log_logcatDisabled() {
+ when(mReader.getViewerString(anyInt())).thenReturn("test %d");
+ ProtoLogImpl implSpy = Mockito.spy(mProtoLog);
+ TestProtoLogGroup.TEST_GROUP.setLogToLogcat(false);
+ TestProtoLogGroup.TEST_GROUP.setLogToProto(false);
+
+ implSpy.log(
+ ProtoLogImpl.LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, 1234, 4321, "test %d",
+ new Object[]{5});
+
+ verify(implSpy, never()).passToLogcat(any(), any(), any());
+ verify(mReader, never()).getViewerString(anyInt());
+ }
+
+ private static class ProtoLogData {
+ Integer mMessageHash = null;
+ Long mElapsedTime = null;
+ LinkedList<String> mStrParams = new LinkedList<>();
+ LinkedList<Long> mSint64Params = new LinkedList<>();
+ LinkedList<Double> mDoubleParams = new LinkedList<>();
+ LinkedList<Boolean> mBooleanParams = new LinkedList<>();
+ }
+
+ private ProtoLogData readProtoLogSingle(ProtoInputStream ip) throws IOException {
+ while (ip.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+ if (ip.getFieldNumber() == (int) ProtoLogFileProto.VERSION) {
+ assertEquals(PROTOLOG_VERSION, ip.readString(ProtoLogFileProto.VERSION));
+ continue;
+ }
+ if (ip.getFieldNumber() != (int) ProtoLogFileProto.LOG) {
+ continue;
+ }
+ long token = ip.start(ProtoLogFileProto.LOG);
+ ProtoLogData data = new ProtoLogData();
+ while (ip.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+ switch (ip.getFieldNumber()) {
+ case (int) ProtoLogMessage.MESSAGE_HASH: {
+ data.mMessageHash = ip.readInt(ProtoLogMessage.MESSAGE_HASH);
+ break;
+ }
+ case (int) ProtoLogMessage.ELAPSED_REALTIME_NANOS: {
+ data.mElapsedTime = ip.readLong(ProtoLogMessage.ELAPSED_REALTIME_NANOS);
+ break;
+ }
+ case (int) ProtoLogMessage.STR_PARAMS: {
+ data.mStrParams.add(ip.readString(ProtoLogMessage.STR_PARAMS));
+ break;
+ }
+ case (int) ProtoLogMessage.SINT64_PARAMS: {
+ data.mSint64Params.add(ip.readLong(ProtoLogMessage.SINT64_PARAMS));
+ break;
+ }
+ case (int) ProtoLogMessage.DOUBLE_PARAMS: {
+ data.mDoubleParams.add(ip.readDouble(ProtoLogMessage.DOUBLE_PARAMS));
+ break;
+ }
+ case (int) ProtoLogMessage.BOOLEAN_PARAMS: {
+ data.mBooleanParams.add(ip.readBoolean(ProtoLogMessage.BOOLEAN_PARAMS));
+ break;
+ }
+ }
+ }
+ ip.end(token);
+ return data;
+ }
+ return null;
+ }
+
+ @Test
+ public void log_protoEnabled() throws Exception {
+ TestProtoLogGroup.TEST_GROUP.setLogToLogcat(false);
+ TestProtoLogGroup.TEST_GROUP.setLogToProto(true);
+ mProtoLog.startProtoLog(mock(PrintWriter.class));
+ long before = SystemClock.elapsedRealtimeNanos();
+ mProtoLog.log(
+ ProtoLogImpl.LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, 1234,
+ 0b1110101001010100, null,
+ new Object[]{"test", 1, 2, 3, 0.4, 0.5, 0.6, true});
+ long after = SystemClock.elapsedRealtimeNanos();
+ mProtoLog.stopProtoLog(mock(PrintWriter.class), true);
+ try (InputStream is = new FileInputStream(mFile)) {
+ ProtoInputStream ip = new ProtoInputStream(is);
+ ProtoLogData data = readProtoLogSingle(ip);
+ assertNotNull(data);
+ assertEquals(1234, data.mMessageHash.longValue());
+ assertTrue(before <= data.mElapsedTime && data.mElapsedTime <= after);
+ assertArrayEquals(new String[]{"test"}, data.mStrParams.toArray());
+ assertArrayEquals(new Long[]{1L, 2L, 3L}, data.mSint64Params.toArray());
+ assertArrayEquals(new Double[]{0.4, 0.5, 0.6}, data.mDoubleParams.toArray());
+ assertArrayEquals(new Boolean[]{true}, data.mBooleanParams.toArray());
+ }
+ }
+
+ @Test
+ public void log_invalidParamsMask() throws Exception {
+ TestProtoLogGroup.TEST_GROUP.setLogToLogcat(false);
+ TestProtoLogGroup.TEST_GROUP.setLogToProto(true);
+ mProtoLog.startProtoLog(mock(PrintWriter.class));
+ long before = SystemClock.elapsedRealtimeNanos();
+ mProtoLog.log(
+ ProtoLogImpl.LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, 1234,
+ 0b01100100, null,
+ new Object[]{"test", 1, 0.1, true});
+ long after = SystemClock.elapsedRealtimeNanos();
+ mProtoLog.stopProtoLog(mock(PrintWriter.class), true);
+ try (InputStream is = new FileInputStream(mFile)) {
+ ProtoInputStream ip = new ProtoInputStream(is);
+ ProtoLogData data = readProtoLogSingle(ip);
+ assertNotNull(data);
+ assertEquals(1234, data.mMessageHash.longValue());
+ assertTrue(before <= data.mElapsedTime && data.mElapsedTime <= after);
+ assertArrayEquals(new String[]{"test", "(INVALID PARAMS_MASK) true"},
+ data.mStrParams.toArray());
+ assertArrayEquals(new Long[]{1L}, data.mSint64Params.toArray());
+ assertArrayEquals(new Double[]{0.1}, data.mDoubleParams.toArray());
+ assertArrayEquals(new Boolean[]{}, data.mBooleanParams.toArray());
+ }
+ }
+
+ @Test
+ public void log_protoDisabled() throws Exception {
+ TestProtoLogGroup.TEST_GROUP.setLogToLogcat(false);
+ TestProtoLogGroup.TEST_GROUP.setLogToProto(false);
+ mProtoLog.startProtoLog(mock(PrintWriter.class));
+ mProtoLog.log(ProtoLogImpl.LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, 1234,
+ 0b11, null, new Object[]{true});
+ mProtoLog.stopProtoLog(mock(PrintWriter.class), true);
+ try (InputStream is = new FileInputStream(mFile)) {
+ ProtoInputStream ip = new ProtoInputStream(is);
+ ProtoLogData data = readProtoLogSingle(ip);
+ assertNull(data);
+ }
+ }
+
+ private enum TestProtoLogGroup implements IProtoLogGroup {
+ TEST_GROUP(true, true, false, "WindowManagetProtoLogTest");
+
+ private final boolean mEnabled;
+ private volatile boolean mLogToProto;
+ private volatile boolean mLogToLogcat;
+ private final String mTag;
+
+ /**
+ * @param enabled set to false to exclude all log statements for this group from
+ * compilation,
+ * they will not be available in runtime.
+ * @param logToProto enable binary logging for the group
+ * @param logToLogcat enable text logging for the group
+ * @param tag name of the source of the logged message
+ */
+ TestProtoLogGroup(boolean enabled, boolean logToProto, boolean logToLogcat, String tag) {
+ this.mEnabled = enabled;
+ this.mLogToProto = logToProto;
+ this.mLogToLogcat = logToLogcat;
+ this.mTag = tag;
+ }
+
+ @Override
+ public boolean isEnabled() {
+ return mEnabled;
+ }
+
+ @Override
+ public boolean isLogToProto() {
+ return mLogToProto;
+ }
+
+ @Override
+ public boolean isLogToLogcat() {
+ return mLogToLogcat;
+ }
+
+ @Override
+ public boolean isLogToAny() {
+ return mLogToLogcat || mLogToProto;
+ }
+
+ @Override
+ public String getTag() {
+ return mTag;
+ }
+
+ @Override
+ public void setLogToProto(boolean logToProto) {
+ this.mLogToProto = logToProto;
+ }
+
+ @Override
+ public void setLogToLogcat(boolean logToLogcat) {
+ this.mLogToLogcat = logToLogcat;
+ }
+
+ }
+}
diff --git a/tests/Internal/src/com/android/internal/protolog/ProtoLogViewerConfigReaderTest.java b/tests/Internal/src/com/android/internal/protolog/ProtoLogViewerConfigReaderTest.java
new file mode 100644
index 000000000000..ae5021638745
--- /dev/null
+++ b/tests/Internal/src/com/android/internal/protolog/ProtoLogViewerConfigReaderTest.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2019 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.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.util.zip.GZIPOutputStream;
+
+@SmallTest
+@Presubmit
+@RunWith(JUnit4.class)
+public class ProtoLogViewerConfigReaderTest {
+ private static final String TEST_VIEWER_CONFIG = "{\n"
+ + " \"version\": \"1.0.0\",\n"
+ + " \"messages\": {\n"
+ + " \"70933285\": {\n"
+ + " \"message\": \"Test completed successfully: %b\",\n"
+ + " \"level\": \"ERROR\",\n"
+ + " \"group\": \"GENERIC_WM\"\n"
+ + " },\n"
+ + " \"1792430067\": {\n"
+ + " \"message\": \"Attempted to add window to a display that does not exist: %d."
+ + " Aborting.\",\n"
+ + " \"level\": \"WARN\",\n"
+ + " \"group\": \"GENERIC_WM\"\n"
+ + " },\n"
+ + " \"1352021864\": {\n"
+ + " \"message\": \"Test 2\",\n"
+ + " \"level\": \"WARN\",\n"
+ + " \"group\": \"GENERIC_WM\"\n"
+ + " },\n"
+ + " \"409412266\": {\n"
+ + " \"message\": \"Window %s is already added\",\n"
+ + " \"level\": \"WARN\",\n"
+ + " \"group\": \"GENERIC_WM\"\n"
+ + " }\n"
+ + " },\n"
+ + " \"groups\": {\n"
+ + " \"GENERIC_WM\": {\n"
+ + " \"tag\": \"WindowManager\"\n"
+ + " }\n"
+ + " }\n"
+ + "}\n";
+
+
+ private ProtoLogViewerConfigReader
+ mConfig = new ProtoLogViewerConfigReader();
+ private File mTestViewerConfig;
+
+ @Before
+ public void setUp() throws IOException {
+ mTestViewerConfig = File.createTempFile("testConfig", ".json.gz");
+ OutputStreamWriter writer = new OutputStreamWriter(
+ new GZIPOutputStream(new FileOutputStream(mTestViewerConfig)));
+ writer.write(TEST_VIEWER_CONFIG);
+ writer.close();
+ }
+
+ @After
+ public void tearDown() {
+ //noinspection ResultOfMethodCallIgnored
+ mTestViewerConfig.delete();
+ }
+
+ @Test
+ public void getViewerString_notLoaded() {
+ assertNull(mConfig.getViewerString(1));
+ }
+
+ @Test
+ public void loadViewerConfig() {
+ mConfig.loadViewerConfig(null, mTestViewerConfig.getAbsolutePath());
+ assertEquals("Test completed successfully: %b", mConfig.getViewerString(70933285));
+ assertEquals("Test 2", mConfig.getViewerString(1352021864));
+ assertEquals("Window %s is already added", mConfig.getViewerString(409412266));
+ assertNull(mConfig.getViewerString(1));
+ }
+
+ @Test
+ public void loadViewerConfig_invalidFile() {
+ mConfig.loadViewerConfig(null, "/tmp/unknown/file/does/not/exist");
+ // No exception is thrown.
+ assertNull(mConfig.getViewerString(1));
+ }
+}
diff --git a/tests/Internal/src/com/android/internal/protolog/common/LogDataTypeTest.java b/tests/Internal/src/com/android/internal/protolog/common/LogDataTypeTest.java
new file mode 100644
index 000000000000..e20ca3df57c7
--- /dev/null
+++ b/tests/Internal/src/com/android/internal/protolog/common/LogDataTypeTest.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2019 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.common;
+
+import static org.junit.Assert.assertEquals;
+
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+@SmallTest
+@Presubmit
+@RunWith(JUnit4.class)
+public class LogDataTypeTest {
+ @Test
+ public void parseFormatString() {
+ String str = "%b %d %o %x %f %e %g %s %%";
+ List<Integer> out = LogDataType.parseFormatString(str);
+ assertEquals(Arrays.asList(
+ LogDataType.BOOLEAN,
+ LogDataType.LONG,
+ LogDataType.LONG,
+ LogDataType.LONG,
+ LogDataType.DOUBLE,
+ LogDataType.DOUBLE,
+ LogDataType.DOUBLE,
+ LogDataType.STRING
+ ), out);
+ }
+
+ @Test(expected = InvalidFormatStringException.class)
+ public void parseFormatString_invalid() {
+ String str = "%q";
+ LogDataType.parseFormatString(str);
+ }
+
+ @Test
+ public void logDataTypesToBitMask() {
+ List<Integer> types = Arrays.asList(LogDataType.STRING, LogDataType.DOUBLE,
+ LogDataType.LONG, LogDataType.BOOLEAN);
+ int mask = LogDataType.logDataTypesToBitMask(types);
+ assertEquals(0b11011000, mask);
+ }
+
+ @Test(expected = BitmaskConversionException.class)
+ public void logDataTypesToBitMask_toManyParams() {
+ ArrayList<Integer> types = new ArrayList<>();
+ for (int i = 0; i <= 16; i++) {
+ types.add(LogDataType.STRING);
+ }
+ LogDataType.logDataTypesToBitMask(types);
+ }
+
+ @Test
+ public void bitmaskToLogDataTypes() {
+ int bitmask = 0b11011000;
+ List<Integer> types = Arrays.asList(LogDataType.STRING, LogDataType.DOUBLE,
+ LogDataType.LONG, LogDataType.BOOLEAN);
+ for (int i = 0; i < types.size(); i++) {
+ assertEquals(types.get(i).intValue(), LogDataType.bitmaskToLogDataType(bitmask, i));
+ }
+ }
+}
diff --git a/tests/JankBench/app/src/main/AndroidManifest.xml b/tests/JankBench/app/src/main/AndroidManifest.xml
index 58aa66fcd05d..fe431fda48cd 100644
--- a/tests/JankBench/app/src/main/AndroidManifest.xml
+++ b/tests/JankBench/app/src/main/AndroidManifest.xml
@@ -1,4 +1,5 @@
-<?xml version="1.0" encoding="utf-8"?><!--
+<?xml version="1.0" encoding="utf-8"?>
+<!--
~ Copyright (C) 2015 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
@@ -13,50 +14,48 @@
~ License.
~
-->
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.benchmark">
+ package="com.android.benchmark">
- <uses-sdk android:minSdkVersion="24" />
+ <uses-sdk android:minSdkVersion="24"/>
- <android:uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
- <android:uses-permission android:name="android.permission.READ_PHONE_STATE" />
- <android:uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+ <android:uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
+ <android:uses-permission android:name="android.permission.READ_PHONE_STATE"/>
+ <android:uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
- <application
- android:allowBackup="true"
- android:icon="@mipmap/ic_launcher"
- android:label="@string/app_name"
- android:supportsRtl="true"
- android:theme="@style/AppTheme">
- <activity
- android:name=".app.HomeActivity"
- android:label="@string/app_name"
- android:theme="@style/AppTheme.NoActionBar">
+ <application android:allowBackup="true"
+ android:icon="@mipmap/ic_launcher"
+ android:label="@string/app_name"
+ android:supportsRtl="true"
+ android:theme="@style/AppTheme">
+ <activity android:name=".app.HomeActivity"
+ android:label="@string/app_name"
+ android:theme="@style/AppTheme.NoActionBar"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
+ <action android:name="android.intent.action.MAIN"/>
- <category android:name="android.intent.category.LAUNCHER" />
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity
- android:name=".app.RunLocalBenchmarksActivity"
- android:exported="true">
+ <activity android:name=".app.RunLocalBenchmarksActivity"
+ android:exported="true">
<intent-filter>
- <action android:name="com.android.benchmark.ACTION_BENCHMARK" />
+ <action android:name="com.android.benchmark.ACTION_BENCHMARK"/>
</intent-filter>
- <meta-data
- android:name="com.android.benchmark.benchmark_group"
- android:resource="@xml/benchmark" />
+ <meta-data android:name="com.android.benchmark.benchmark_group"
+ android:resource="@xml/benchmark"/>
</activity>
- <activity android:name=".ui.ListViewScrollActivity" />
- <activity android:name=".ui.ImageListViewScrollActivity" />
- <activity android:name=".ui.ShadowGridActivity" />
- <activity android:name=".ui.TextScrollActivity" />
- <activity android:name=".ui.EditTextInputActivity" />
- <activity android:name=".synthetic.MemoryActivity" />
- <activity android:name=".ui.FullScreenOverdrawActivity"></activity>
- <activity android:name=".ui.BitmapUploadActivity"></activity>
+ <activity android:name=".ui.ListViewScrollActivity"/>
+ <activity android:name=".ui.ImageListViewScrollActivity"/>
+ <activity android:name=".ui.ShadowGridActivity"/>
+ <activity android:name=".ui.TextScrollActivity"/>
+ <activity android:name=".ui.EditTextInputActivity"/>
+ <activity android:name=".synthetic.MemoryActivity"/>
+ <activity android:name=".ui.FullScreenOverdrawActivity"/>
+ <activity android:name=".ui.BitmapUploadActivity"/>
</application>
-</manifest> \ No newline at end of file
+</manifest>
diff --git a/tests/JobSchedulerTestApp/AndroidManifest.xml b/tests/JobSchedulerTestApp/AndroidManifest.xml
index 96541972b9b8..aeeaba469a2a 100644
--- a/tests/JobSchedulerTestApp/AndroidManifest.xml
+++ b/tests/JobSchedulerTestApp/AndroidManifest.xml
@@ -1,32 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.demo.jobSchedulerApp" >
+ package="com.android.demo.jobSchedulerApp">
- <uses-sdk
- android:minSdkVersion="18"
- android:targetSdkVersion="18" />
+ <uses-sdk android:minSdkVersion="18"
+ android:targetSdkVersion="18"/>
- <uses-permission android:name="android.permission.INTERNET" />
- <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
+ <uses-permission android:name="android.permission.INTERNET"/>
+ <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
- <application
- android:icon="@drawable/ic_launcher"
- android:label="@string/app_name"
- android:theme="@style/AppTheme" >
- <activity
- android:name="com.android.demo.jobSchedulerApp.MainActivity"
- android:label="@string/app_name"
- android:windowSoftInputMode="stateHidden" >
+ <application android:icon="@drawable/ic_launcher"
+ android:label="@string/app_name"
+ android:theme="@style/AppTheme">
+ <activity android:name="com.android.demo.jobSchedulerApp.MainActivity"
+ android:label="@string/app_name"
+ android:windowSoftInputMode="stateHidden"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <service
- android:name=".service.TestJobService"
- android:permission="android.permission.BIND_JOB_SERVICE"
- android:exported="true"/>
+ <service android:name=".service.TestJobService"
+ android:permission="android.permission.BIND_JOB_SERVICE"
+ android:exported="true"/>
</application>
</manifest>
diff --git a/tests/LargeAssetTest/AndroidManifest.xml b/tests/LargeAssetTest/AndroidManifest.xml
index c86118e492e5..ac55dcb66be8 100644
--- a/tests/LargeAssetTest/AndroidManifest.xml
+++ b/tests/LargeAssetTest/AndroidManifest.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2010 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
@@ -12,15 +13,18 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.largeassettest">
+ package="com.android.largeassettest">
<application>
- <activity android:name="LargeAssetTest" android:label="Large Asset Test">
+ <activity android:name="LargeAssetTest"
+ android:label="Large Asset Test"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
diff --git a/tests/LegacyAssistant/AndroidManifest.xml b/tests/LegacyAssistant/AndroidManifest.xml
index 7ae510379980..942eafa06f35 100644
--- a/tests/LegacyAssistant/AndroidManifest.xml
+++ b/tests/LegacyAssistant/AndroidManifest.xml
@@ -15,22 +15,23 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.google.android.test.legacyassistant">
+ package="com.google.android.test.legacyassistant">
<application android:label="@string/activity_title">
<activity android:name=".AssistActivity"
- android:theme="@android:style/Theme.NoTitleBar">
+ android:theme="@android:style/Theme.NoTitleBar"
+ android:exported="true">
<!-- Handle assist intent -->
<intent-filter>
- <action android:name="android.intent.action.ASSIST" />
- <category android:name="android.intent.category.DEFAULT" />
+ <action android:name="android.intent.action.ASSIST"/>
+ <category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
<!-- Provide icon for search -->
<meta-data android:name="com.android.systemui.action_assist_icon"
- android:resource="@drawable/ic_action_assist" />
+ android:resource="@drawable/ic_action_assist"/>
</activity>
diff --git a/tests/LocationTracker/AndroidManifest.xml b/tests/LocationTracker/AndroidManifest.xml
index dc7ea99849e0..0940ee31db1f 100644
--- a/tests/LocationTracker/AndroidManifest.xml
+++ b/tests/LocationTracker/AndroidManifest.xml
@@ -1,30 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.locationtracker">
+ package="com.android.locationtracker">
<!-- Permissions for the Location Service -->
- <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
- <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
+ <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
+ <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<!-- Permission for wifi -->
- <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
+ <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<!-- give the location tracker ability to induce device insomnia -->
- <uses-permission android:name="android.permission.WAKE_LOCK" />
+ <uses-permission android:name="android.permission.WAKE_LOCK"/>
<!-- Permission for SD card -->
- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<application android:label="@string/app_label">
- <activity android:name="TrackerActivity" android:label="Location Tracker">
+ <activity android:name="TrackerActivity"
+ android:label="Location Tracker"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <service android:name=".TrackerService" />
- <activity android:label="@string/settings_menu" android:name="SettingsActivity" />
+ <service android:name=".TrackerService"/>
+ <activity android:label="@string/settings_menu"
+ android:name="SettingsActivity"/>
<provider android:name=".data.TrackerProvider"
- android:authorities="com.android.locationtracker" />
+ android:authorities="com.android.locationtracker"/>
</application>
</manifest>
diff --git a/tests/LockTaskTests/AndroidManifest.xml b/tests/LockTaskTests/AndroidManifest.xml
index e349c9248263..3ffdc4712b0e 100644
--- a/tests/LockTaskTests/AndroidManifest.xml
+++ b/tests/LockTaskTests/AndroidManifest.xml
@@ -1,56 +1,51 @@
<?xml version="1.0" encoding="utf-8"?>
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.google.android.example.locktasktests"
- android:versionCode="1"
- android:versionName="1.0" >
+ package="com.google.android.example.locktasktests"
+ android:versionCode="1"
+ android:versionName="1.0">
- <uses-sdk
- android:minSdkVersion="22"
- android:targetSdkVersion="22" />
+ <uses-sdk android:minSdkVersion="22"
+ android:targetSdkVersion="22"/>
<uses-permission android:name="android.permission.INTERNET"/>
- <application
- android:icon="@drawable/ic_launcher"
- android:label="@string/app_name"
- android:theme="@style/AppTheme"
- android:allowBackup="true" >
- <activity
- android:name="com.google.android.example.locktasktests.MainActivity"
- android:label="@string/app_name"
- android:screenOrientation="portrait"
- android:theme="@style/AppTheme" >
+ <application android:icon="@drawable/ic_launcher"
+ android:label="@string/app_name"
+ android:theme="@style/AppTheme"
+ android:allowBackup="true">
+ <activity android:name="com.google.android.example.locktasktests.MainActivity"
+ android:label="@string/app_name"
+ android:screenOrientation="portrait"
+ android:theme="@style/AppTheme"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity
- android:name="com.google.android.example.locktasktests.LockDefaultActivity"
- android:label="@string/title_activity_default"
- android:taskAffinity=""
- android:documentLaunchMode="always"
- android:lockTaskMode="normal" >
+ <activity android:name="com.google.android.example.locktasktests.LockDefaultActivity"
+ android:label="@string/title_activity_default"
+ android:taskAffinity=""
+ android:documentLaunchMode="always"
+ android:lockTaskMode="normal">
</activity>
- <activity
- android:name="com.google.android.example.locktasktests.LockTaskNeverActivity"
- android:label="@string/title_activity_never"
- android:taskAffinity=""
- android:documentLaunchMode="always"
- android:lockTaskMode="never" >
+ <activity android:name="com.google.android.example.locktasktests.LockTaskNeverActivity"
+ android:label="@string/title_activity_never"
+ android:taskAffinity=""
+ android:documentLaunchMode="always"
+ android:lockTaskMode="never">
</activity>
- <activity
- android:name="com.google.android.example.locktasktests.LockWhitelistedActivity"
- android:label="@string/title_activity_whitelist"
- android:taskAffinity=""
- android:documentLaunchMode="always"
- android:lockTaskMode="if_whitelisted" >
+ <activity android:name="com.google.android.example.locktasktests.LockWhitelistedActivity"
+ android:label="@string/title_activity_whitelist"
+ android:taskAffinity=""
+ android:documentLaunchMode="always"
+ android:lockTaskMode="if_whitelisted">
</activity>
- <activity
- android:name="com.google.android.example.locktasktests.LockAtLaunchActivity"
- android:label="@string/title_activity_always"
- android:taskAffinity=""
- android:documentLaunchMode="always"
- android:lockTaskMode="always" >
+ <activity android:name="com.google.android.example.locktasktests.LockAtLaunchActivity"
+ android:label="@string/title_activity_always"
+ android:taskAffinity=""
+ android:documentLaunchMode="always"
+ android:lockTaskMode="always">
</activity>
</application>
diff --git a/tests/LotsOfApps/AndroidManifest.xml b/tests/LotsOfApps/AndroidManifest.xml
index 585ddccf8450..3aed04391103 100644
--- a/tests/LotsOfApps/AndroidManifest.xml
+++ b/tests/LotsOfApps/AndroidManifest.xml
@@ -1,710 +1,912 @@
+<?xml version="1.0" encoding="utf-8"?>
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.lotsofapps">
- <uses-permission android:name="android.permission.DEVICE_POWER" />
- <uses-permission android:name="android.permission.WAKE_LOCK" />
- <uses-permission android:name="android.permission.STATUS_BAR" />
- <uses-permission android:name="android.permission.EXPAND_STATUS_BAR" />
- <uses-permission android:name="android.permission.VIBRATE" />
+ package="com.android.lotsofapps">
+ <uses-permission android:name="android.permission.DEVICE_POWER"/>
+ <uses-permission android:name="android.permission.WAKE_LOCK"/>
+ <uses-permission android:name="android.permission.STATUS_BAR"/>
+ <uses-permission android:name="android.permission.EXPAND_STATUS_BAR"/>
+ <uses-permission android:name="android.permission.VIBRATE"/>
<application>
- <activity android:name="com.android.lotsofapps.activity00" android:icon="@drawable/ic_launcher_add_folder">
+ <activity android:name="com.android.lotsofapps.activity00"
+ android:icon="@drawable/ic_launcher_add_folder"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity01" android:icon="@drawable/ic_launcher_alarmclock">
+ <activity android:name="com.android.lotsofapps.activity01"
+ android:icon="@drawable/ic_launcher_alarmclock"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity02" android:icon="@drawable/ic_launcher_application">
+ <activity android:name="com.android.lotsofapps.activity02"
+ android:icon="@drawable/ic_launcher_application"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity03" android:icon="@drawable/ic_launcher_browser">
+ <activity android:name="com.android.lotsofapps.activity03"
+ android:icon="@drawable/ic_launcher_browser"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity04" android:icon="@drawable/ic_launcher_camera">
+ <activity android:name="com.android.lotsofapps.activity04"
+ android:icon="@drawable/ic_launcher_camera"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity05" android:icon="@drawable/ic_launcher_camera_record">
+ <activity android:name="com.android.lotsofapps.activity05"
+ android:icon="@drawable/ic_launcher_camera_record"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity06" android:icon="@drawable/ic_launcher_contacts">
+ <activity android:name="com.android.lotsofapps.activity06"
+ android:icon="@drawable/ic_launcher_contacts"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity07" android:icon="@drawable/ic_launcher_drm_file">
+ <activity android:name="com.android.lotsofapps.activity07"
+ android:icon="@drawable/ic_launcher_drm_file"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity08" android:icon="@drawable/ic_launcher_folder">
+ <activity android:name="com.android.lotsofapps.activity08"
+ android:icon="@drawable/ic_launcher_folder"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity09" android:icon="@drawable/ic_launcher_folder_bluetooth">
+ <activity android:name="com.android.lotsofapps.activity09"
+ android:icon="@drawable/ic_launcher_folder_bluetooth"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity10" android:icon="@drawable/ic_launcher_folder_live">
+ <activity android:name="com.android.lotsofapps.activity10"
+ android:icon="@drawable/ic_launcher_folder_live"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity11" android:icon="@drawable/ic_launcher_folder_live_contacts">
+ <activity android:name="com.android.lotsofapps.activity11"
+ android:icon="@drawable/ic_launcher_folder_live_contacts"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity12" android:icon="@drawable/ic_launcher_folder_live_contacts_phone">
+ <activity android:name="com.android.lotsofapps.activity12"
+ android:icon="@drawable/ic_launcher_folder_live_contacts_phone"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity13" android:icon="@drawable/ic_launcher_folder_live_contacts_starred">
+ <activity android:name="com.android.lotsofapps.activity13"
+ android:icon="@drawable/ic_launcher_folder_live_contacts_starred"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity14" android:icon="@drawable/ic_launcher_folder_open">
+ <activity android:name="com.android.lotsofapps.activity14"
+ android:icon="@drawable/ic_launcher_folder_open"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity15" android:icon="@drawable/ic_launcher_gallery">
+ <activity android:name="com.android.lotsofapps.activity15"
+ android:icon="@drawable/ic_launcher_gallery"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity16" android:icon="@drawable/ic_launcher_home">
+ <activity android:name="com.android.lotsofapps.activity16"
+ android:icon="@drawable/ic_launcher_home"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity17" android:icon="@drawable/ic_launcher_im">
+ <activity android:name="com.android.lotsofapps.activity17"
+ android:icon="@drawable/ic_launcher_im"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity18" android:icon="@drawable/ic_launcher_musicplayer_2">
+ <activity android:name="com.android.lotsofapps.activity18"
+ android:icon="@drawable/ic_launcher_musicplayer_2"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity19" android:icon="@drawable/ic_launcher_phone">
+ <activity android:name="com.android.lotsofapps.activity19"
+ android:icon="@drawable/ic_launcher_phone"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity20" android:icon="@drawable/ic_launcher_record_audio">
+ <activity android:name="com.android.lotsofapps.activity20"
+ android:icon="@drawable/ic_launcher_record_audio"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity21" android:icon="@drawable/ic_launcher_settings">
+ <activity android:name="com.android.lotsofapps.activity21"
+ android:icon="@drawable/ic_launcher_settings"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity22" android:icon="@drawable/ic_launcher_shortcut">
+ <activity android:name="com.android.lotsofapps.activity22"
+ android:icon="@drawable/ic_launcher_shortcut"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity23" android:icon="@drawable/ic_launcher_shortcut_browser_bookmark">
+ <activity android:name="com.android.lotsofapps.activity23"
+ android:icon="@drawable/ic_launcher_shortcut_browser_bookmark"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity24" android:icon="@drawable/ic_launcher_contacts">
+ <activity android:name="com.android.lotsofapps.activity24"
+ android:icon="@drawable/ic_launcher_contacts"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity25" android:icon="@drawable/ic_launcher_shortcut_directdial">
+ <activity android:name="com.android.lotsofapps.activity25"
+ android:icon="@drawable/ic_launcher_shortcut_directdial"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity26" android:icon="@drawable/ic_launcher_shortcut_directmessage">
+ <activity android:name="com.android.lotsofapps.activity26"
+ android:icon="@drawable/ic_launcher_shortcut_directmessage"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity27" android:icon="@drawable/ic_launcher_browser">
+ <activity android:name="com.android.lotsofapps.activity27"
+ android:icon="@drawable/ic_launcher_browser"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity28" android:icon="@drawable/ic_launcher_sim_toolkit">
+ <activity android:name="com.android.lotsofapps.activity28"
+ android:icon="@drawable/ic_launcher_sim_toolkit"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity29" android:icon="@drawable/ic_launcher_slideshow_add_sms">
+ <activity android:name="com.android.lotsofapps.activity29"
+ android:icon="@drawable/ic_launcher_slideshow_add_sms"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity20" android:icon="@drawable/ic_launcher_slideshow_default_sms">
+ <activity android:name="com.android.lotsofapps.activity20"
+ android:icon="@drawable/ic_launcher_slideshow_default_sms"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity31" android:icon="@drawable/ic_launcher_smsmms">
+ <activity android:name="com.android.lotsofapps.activity31"
+ android:icon="@drawable/ic_launcher_smsmms"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity32" android:icon="@drawable/ic_launcher_soundrecorder">
+ <activity android:name="com.android.lotsofapps.activity32"
+ android:icon="@drawable/ic_launcher_soundrecorder"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity33" android:icon="@drawable/ic_launcher_video_camera">
+ <activity android:name="com.android.lotsofapps.activity33"
+ android:icon="@drawable/ic_launcher_video_camera"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity34" android:icon="@drawable/ic_launcher_video_player">
+ <activity android:name="com.android.lotsofapps.activity34"
+ android:icon="@drawable/ic_launcher_video_player"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity35" android:icon="@drawable/ic_launcher_wallpaper">
+ <activity android:name="com.android.lotsofapps.activity35"
+ android:icon="@drawable/ic_launcher_wallpaper"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity36" android:icon="@drawable/ic_launcher_im">
+ <activity android:name="com.android.lotsofapps.activity36"
+ android:icon="@drawable/ic_launcher_im"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity37" android:icon="@drawable/ic_launcher_musicplayer_2">
+ <activity android:name="com.android.lotsofapps.activity37"
+ android:icon="@drawable/ic_launcher_musicplayer_2"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity38" android:icon="@drawable/ic_launcher_phone">
+ <activity android:name="com.android.lotsofapps.activity38"
+ android:icon="@drawable/ic_launcher_phone"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity39" android:icon="@drawable/ic_launcher_record_audio">
+ <activity android:name="com.android.lotsofapps.activity39"
+ android:icon="@drawable/ic_launcher_record_audio"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity40" android:icon="@drawable/ic_launcher_settings">
+ <activity android:name="com.android.lotsofapps.activity40"
+ android:icon="@drawable/ic_launcher_settings"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity41" android:icon="@drawable/ic_launcher_shortcut">
+ <activity android:name="com.android.lotsofapps.activity41"
+ android:icon="@drawable/ic_launcher_shortcut"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity42" android:icon="@drawable/ic_launcher_sim_toolkit">
+ <activity android:name="com.android.lotsofapps.activity42"
+ android:icon="@drawable/ic_launcher_sim_toolkit"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity43" android:icon="@drawable/ic_launcher_smsmms">
+ <activity android:name="com.android.lotsofapps.activity43"
+ android:icon="@drawable/ic_launcher_smsmms"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity44" android:icon="@drawable/ic_launcher_soundrecorder">
+ <activity android:name="com.android.lotsofapps.activity44"
+ android:icon="@drawable/ic_launcher_soundrecorder"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity45" android:icon="@drawable/ic_launcher_video_camera">
+ <activity android:name="com.android.lotsofapps.activity45"
+ android:icon="@drawable/ic_launcher_video_camera"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity46" android:icon="@drawable/ic_launcher_wallpaper">
+ <activity android:name="com.android.lotsofapps.activity46"
+ android:icon="@drawable/ic_launcher_wallpaper"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity47" android:icon="@drawable/ic_launcher_drm_file">
+ <activity android:name="com.android.lotsofapps.activity47"
+ android:icon="@drawable/ic_launcher_drm_file"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity48" android:icon="@drawable/ic_launcher_contacts">
+ <activity android:name="com.android.lotsofapps.activity48"
+ android:icon="@drawable/ic_launcher_contacts"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity49" android:icon="@drawable/ic_launcher_drm_file">
+ <activity android:name="com.android.lotsofapps.activity49"
+ android:icon="@drawable/ic_launcher_drm_file"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity50" android:icon="@drawable/ic_launcher_add_folder">
+ <activity android:name="com.android.lotsofapps.activity50"
+ android:icon="@drawable/ic_launcher_add_folder"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity51" android:icon="@drawable/ic_launcher_alarmclock">
+ <activity android:name="com.android.lotsofapps.activity51"
+ android:icon="@drawable/ic_launcher_alarmclock"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity52" android:icon="@drawable/ic_launcher_application">
+ <activity android:name="com.android.lotsofapps.activity52"
+ android:icon="@drawable/ic_launcher_application"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity53" android:icon="@drawable/ic_launcher_browser">
+ <activity android:name="com.android.lotsofapps.activity53"
+ android:icon="@drawable/ic_launcher_browser"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity54" android:icon="@drawable/ic_launcher_camera">
+ <activity android:name="com.android.lotsofapps.activity54"
+ android:icon="@drawable/ic_launcher_camera"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity55" android:icon="@drawable/ic_launcher_camera_record">
+ <activity android:name="com.android.lotsofapps.activity55"
+ android:icon="@drawable/ic_launcher_camera_record"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity56" android:icon="@drawable/ic_launcher_contacts">
+ <activity android:name="com.android.lotsofapps.activity56"
+ android:icon="@drawable/ic_launcher_contacts"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity57" android:icon="@drawable/ic_launcher_drm_file">
+ <activity android:name="com.android.lotsofapps.activity57"
+ android:icon="@drawable/ic_launcher_drm_file"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity58" android:icon="@drawable/ic_launcher_folder">
+ <activity android:name="com.android.lotsofapps.activity58"
+ android:icon="@drawable/ic_launcher_folder"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity59" android:icon="@drawable/ic_launcher_folder_bluetooth">
+ <activity android:name="com.android.lotsofapps.activity59"
+ android:icon="@drawable/ic_launcher_folder_bluetooth"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity60" android:icon="@drawable/ic_launcher_folder_live">
+ <activity android:name="com.android.lotsofapps.activity60"
+ android:icon="@drawable/ic_launcher_folder_live"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity61" android:icon="@drawable/ic_launcher_folder_live_contacts">
+ <activity android:name="com.android.lotsofapps.activity61"
+ android:icon="@drawable/ic_launcher_folder_live_contacts"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity62" android:icon="@drawable/ic_launcher_folder_live_contacts_phone">
+ <activity android:name="com.android.lotsofapps.activity62"
+ android:icon="@drawable/ic_launcher_folder_live_contacts_phone"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity63" android:icon="@drawable/ic_launcher_folder_live_contacts_starred">
+ <activity android:name="com.android.lotsofapps.activity63"
+ android:icon="@drawable/ic_launcher_folder_live_contacts_starred"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity64" android:icon="@drawable/ic_launcher_folder_open">
+ <activity android:name="com.android.lotsofapps.activity64"
+ android:icon="@drawable/ic_launcher_folder_open"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity65" android:icon="@drawable/ic_launcher_gallery">
+ <activity android:name="com.android.lotsofapps.activity65"
+ android:icon="@drawable/ic_launcher_gallery"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity66" android:icon="@drawable/ic_launcher_home">
+ <activity android:name="com.android.lotsofapps.activity66"
+ android:icon="@drawable/ic_launcher_home"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity67" android:icon="@drawable/ic_launcher_im">
+ <activity android:name="com.android.lotsofapps.activity67"
+ android:icon="@drawable/ic_launcher_im"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity68" android:icon="@drawable/ic_launcher_musicplayer_2">
+ <activity android:name="com.android.lotsofapps.activity68"
+ android:icon="@drawable/ic_launcher_musicplayer_2"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity69" android:icon="@drawable/ic_launcher_phone">
+ <activity android:name="com.android.lotsofapps.activity69"
+ android:icon="@drawable/ic_launcher_phone"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity70" android:icon="@drawable/ic_launcher_record_audio">
+ <activity android:name="com.android.lotsofapps.activity70"
+ android:icon="@drawable/ic_launcher_record_audio"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity71" android:icon="@drawable/ic_launcher_settings">
+ <activity android:name="com.android.lotsofapps.activity71"
+ android:icon="@drawable/ic_launcher_settings"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity72" android:icon="@drawable/ic_launcher_shortcut">
+ <activity android:name="com.android.lotsofapps.activity72"
+ android:icon="@drawable/ic_launcher_shortcut"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity73" android:icon="@drawable/ic_launcher_shortcut_browser_bookmark">
+ <activity android:name="com.android.lotsofapps.activity73"
+ android:icon="@drawable/ic_launcher_shortcut_browser_bookmark"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity74" android:icon="@drawable/ic_launcher_contacts">
+ <activity android:name="com.android.lotsofapps.activity74"
+ android:icon="@drawable/ic_launcher_contacts"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity75" android:icon="@drawable/ic_launcher_shortcut_directdial">
+ <activity android:name="com.android.lotsofapps.activity75"
+ android:icon="@drawable/ic_launcher_shortcut_directdial"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity76" android:icon="@drawable/ic_launcher_shortcut_directmessage">
+ <activity android:name="com.android.lotsofapps.activity76"
+ android:icon="@drawable/ic_launcher_shortcut_directmessage"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity77" android:icon="@drawable/ic_launcher_browser">
+ <activity android:name="com.android.lotsofapps.activity77"
+ android:icon="@drawable/ic_launcher_browser"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity78" android:icon="@drawable/ic_launcher_sim_toolkit">
+ <activity android:name="com.android.lotsofapps.activity78"
+ android:icon="@drawable/ic_launcher_sim_toolkit"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity79" android:icon="@drawable/ic_launcher_slideshow_add_sms">
+ <activity android:name="com.android.lotsofapps.activity79"
+ android:icon="@drawable/ic_launcher_slideshow_add_sms"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity80" android:icon="@drawable/ic_launcher_slideshow_default_sms">
+ <activity android:name="com.android.lotsofapps.activity80"
+ android:icon="@drawable/ic_launcher_slideshow_default_sms"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity81" android:icon="@drawable/ic_launcher_smsmms">
+ <activity android:name="com.android.lotsofapps.activity81"
+ android:icon="@drawable/ic_launcher_smsmms"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity82" android:icon="@drawable/ic_launcher_soundrecorder">
+ <activity android:name="com.android.lotsofapps.activity82"
+ android:icon="@drawable/ic_launcher_soundrecorder"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity83" android:icon="@drawable/ic_launcher_video_camera">
+ <activity android:name="com.android.lotsofapps.activity83"
+ android:icon="@drawable/ic_launcher_video_camera"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity84" android:icon="@drawable/ic_launcher_video_player">
+ <activity android:name="com.android.lotsofapps.activity84"
+ android:icon="@drawable/ic_launcher_video_player"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity85" android:icon="@drawable/ic_launcher_wallpaper">
+ <activity android:name="com.android.lotsofapps.activity85"
+ android:icon="@drawable/ic_launcher_wallpaper"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity86" android:icon="@drawable/ic_launcher_im">
+ <activity android:name="com.android.lotsofapps.activity86"
+ android:icon="@drawable/ic_launcher_im"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity87" android:icon="@drawable/ic_launcher_musicplayer_2">
+ <activity android:name="com.android.lotsofapps.activity87"
+ android:icon="@drawable/ic_launcher_musicplayer_2"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity88" android:icon="@drawable/ic_launcher_phone">
+ <activity android:name="com.android.lotsofapps.activity88"
+ android:icon="@drawable/ic_launcher_phone"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity89" android:icon="@drawable/ic_launcher_record_audio">
+ <activity android:name="com.android.lotsofapps.activity89"
+ android:icon="@drawable/ic_launcher_record_audio"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity90" android:icon="@drawable/ic_launcher_settings">
+ <activity android:name="com.android.lotsofapps.activity90"
+ android:icon="@drawable/ic_launcher_settings"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity91" android:icon="@drawable/ic_launcher_shortcut">
+ <activity android:name="com.android.lotsofapps.activity91"
+ android:icon="@drawable/ic_launcher_shortcut"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity92" android:icon="@drawable/ic_launcher_sim_toolkit">
+ <activity android:name="com.android.lotsofapps.activity92"
+ android:icon="@drawable/ic_launcher_sim_toolkit"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity93" android:icon="@drawable/ic_launcher_smsmms">
+ <activity android:name="com.android.lotsofapps.activity93"
+ android:icon="@drawable/ic_launcher_smsmms"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity94" android:icon="@drawable/ic_launcher_soundrecorder">
+ <activity android:name="com.android.lotsofapps.activity94"
+ android:icon="@drawable/ic_launcher_soundrecorder"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity95" android:icon="@drawable/ic_launcher_video_camera">
+ <activity android:name="com.android.lotsofapps.activity95"
+ android:icon="@drawable/ic_launcher_video_camera"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity96" android:icon="@drawable/ic_launcher_wallpaper">
+ <activity android:name="com.android.lotsofapps.activity96"
+ android:icon="@drawable/ic_launcher_wallpaper"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity97" android:icon="@drawable/ic_launcher_drm_file">
+ <activity android:name="com.android.lotsofapps.activity97"
+ android:icon="@drawable/ic_launcher_drm_file"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity98" android:icon="@drawable/ic_launcher_contacts">
+ <activity android:name="com.android.lotsofapps.activity98"
+ android:icon="@drawable/ic_launcher_contacts"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity99" android:icon="@drawable/ic_launcher_drm_file">
+ <activity android:name="com.android.lotsofapps.activity99"
+ android:icon="@drawable/ic_launcher_drm_file"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
diff --git a/tests/LowStorageTest/AndroidManifest.xml b/tests/LowStorageTest/AndroidManifest.xml
index 9d4a63ac330f..5b496562ab27 100644
--- a/tests/LowStorageTest/AndroidManifest.xml
+++ b/tests/LowStorageTest/AndroidManifest.xml
@@ -1,13 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.lowstoragetest">
+ package="com.android.lowstoragetest">
<application android:label="LowStorageTest">
<activity android:name="LowStorageTest"
- android:theme="@android:style/Theme.Black.NoTitleBar">
+ android:theme="@android:style/Theme.Black.NoTitleBar"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
-</manifest> \ No newline at end of file
+</manifest>
diff --git a/tests/ManagedProfileLifecycleStressTest/app/DummyDPC/AndroidManifest.xml b/tests/ManagedProfileLifecycleStressTest/app/DummyDPC/AndroidManifest.xml
index 860940d4e025..aefb07661f7e 100644
--- a/tests/ManagedProfileLifecycleStressTest/app/DummyDPC/AndroidManifest.xml
+++ b/tests/ManagedProfileLifecycleStressTest/app/DummyDPC/AndroidManifest.xml
@@ -15,17 +15,16 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.dummydpc">
+ package="com.android.dummydpc">
- <application
- android:testOnly="true">
- <receiver
- android:name="com.android.dummydpc.DummyDeviceAdminReceiver"
- android:permission="android.permission.BIND_DEVICE_ADMIN">
+ <application android:testOnly="true">
+ <receiver android:name="com.android.dummydpc.DummyDeviceAdminReceiver"
+ android:permission="android.permission.BIND_DEVICE_ADMIN"
+ android:exported="true">
<meta-data android:name="android.app.device_admin"
- android:resource="@xml/device_admin" />
+ android:resource="@xml/device_admin"/>
<intent-filter>
- <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
+ <action android:name="android.app.action.DEVICE_ADMIN_ENABLED"/>
</intent-filter>
</receiver>
</application>
diff --git a/tests/ManagedProfileLifecycleStressTest/src/com/android/test/stress/ManagedProfileLifecycleStressTest.java b/tests/ManagedProfileLifecycleStressTest/src/com/android/test/stress/ManagedProfileLifecycleStressTest.java
index 026677e09bed..99dde859028a 100644
--- a/tests/ManagedProfileLifecycleStressTest/src/com/android/test/stress/ManagedProfileLifecycleStressTest.java
+++ b/tests/ManagedProfileLifecycleStressTest/src/com/android/test/stress/ManagedProfileLifecycleStressTest.java
@@ -20,6 +20,7 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import com.android.tradefed.device.CollectingOutputReceiver;
import com.android.tradefed.log.LogUtil.CLog;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
@@ -62,13 +63,62 @@ public class ManagedProfileLifecycleStressTest extends BaseHostJUnit4Test {
CLog.w("Iteration N" + iteration);
final int userId = createManagedProfile();
startUser(userId);
- installPackageAsUser(DUMMY_DPC_APK, true /* grantPermissions */, userId, "-t");
+ installPackageAsUser(
+ DUMMY_DPC_APK, /* grantPermissions= */true, userId, /* options= */"-t");
setProfileOwner(DUMMY_DPC_COMPONENT, userId);
removeUser(userId);
}
CLog.w("Completed " + iteration + " iterations.");
}
+ /**
+ * Create, start, and kill managed profiles in a loop with waitForBroadcastIdle after each user
+ * operation.
+ */
+ @Test
+ public void testCreateStartDeleteStable() throws Exception {
+ // Disable package verifier for ADB installs.
+ getDevice().executeShellCommand("settings put global verifier_verify_adb_installs 0");
+ int iteration = 0;
+ final long deadline = System.nanoTime() + TimeUnit.MINUTES.toNanos(TIME_LIMIT_MINUTES);
+ while (System.nanoTime() < deadline) {
+ iteration++;
+ CLog.w("Iteration N" + iteration);
+ final int userId = createManagedProfile();
+ waitForBroadcastIdle();
+
+ startUser(userId);
+ waitForBroadcastIdle();
+
+ installPackageAsUser(
+ DUMMY_DPC_APK, /* grantPermissions= */true, userId, /* options= */"-t");
+
+ setProfileOwner(DUMMY_DPC_COMPONENT, userId);
+
+ removeUser(userId);
+ waitForBroadcastIdle();
+ }
+ CLog.w("Completed " + iteration + " iterations.");
+ }
+
+ private void waitForBroadcastIdle() throws Exception {
+ final CollectingOutputReceiver receiver = new CollectingOutputReceiver();
+ // We allow 8min for the command to complete and 4min for the command to start to
+ // output something.
+ getDevice().executeShellCommand(
+ "am wait-for-broadcast-idle",
+ receiver,
+ /* maxTimeoutForCommand= */8,
+ /* maxTimeoutToOutputShellResponse= */4,
+ TimeUnit.MINUTES,
+ /* retryAttempts= */0);
+ final String output = receiver.getOutput();
+ if (!output.contains("All broadcast queues are idle!")) {
+ CLog.e("Output from 'am wait-for-broadcast-idle': %s", output);
+ fail("'am wait-for-broadcase-idle' did not complete.");
+ }
+ }
+
private int createManagedProfile() throws Exception {
final String output = getDevice().executeShellCommand(
"pm create-user --profileOf 0 --managed TestProfile");
diff --git a/tests/MirrorSurfaceTest/AndroidManifest.xml b/tests/MirrorSurfaceTest/AndroidManifest.xml
index 123cd0f26ff3..6385cc8a9d22 100644
--- a/tests/MirrorSurfaceTest/AndroidManifest.xml
+++ b/tests/MirrorSurfaceTest/AndroidManifest.xml
@@ -16,14 +16,15 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.google.android.test.mirrorsurface">
+ package="com.google.android.test.mirrorsurface">
<uses-permission android:name="android.permission.ACCESS_SURFACE_FLINGER"/>
- <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
+ <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
<application android:label="MirrorSurfaceTest">
<activity android:name=".MirrorSurfaceActivity"
- android:label="Mirror Surface"
- android:configChanges="orientation|screenSize">
+ android:label="Mirror Surface"
+ android:configChanges="orientation|screenSize"
+ android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
diff --git a/tests/NullHomeTest/Android.bp b/tests/NullHomeTest/Android.bp
index a5720db25a91..d8799a87e8c9 100644
--- a/tests/NullHomeTest/Android.bp
+++ b/tests/NullHomeTest/Android.bp
@@ -26,6 +26,6 @@ android_test {
srcs: ["src/**/*.java"],
certificate: "platform",
platform_apis: true,
- static_libs: ["android-support-test"],
+ static_libs: ["androidx.test.rules"],
test_suites: ["device-tests"],
}
diff --git a/tests/NullHomeTest/AndroidManifest.xml b/tests/NullHomeTest/AndroidManifest.xml
index dc6402e03b5a..6f77781c7a29 100644
--- a/tests/NullHomeTest/AndroidManifest.xml
+++ b/tests/NullHomeTest/AndroidManifest.xml
@@ -21,7 +21,7 @@
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="21" />
<instrumentation
- android:name="android.support.test.runner.AndroidJUnitRunner"
+ android:name="androidx.test.runner.AndroidJUnitRunner"
android:targetPackage="com.android.test.nullhome"
android:label="Check if no null Home exists/is enabled" />
diff --git a/tests/NullHomeTest/src/com/android/test/nullhome/NullHomeTest.java b/tests/NullHomeTest/src/com/android/test/nullhome/NullHomeTest.java
index 1d77cdc51187..3ec3ef2f8fea 100644
--- a/tests/NullHomeTest/src/com/android/test/nullhome/NullHomeTest.java
+++ b/tests/NullHomeTest/src/com/android/test/nullhome/NullHomeTest.java
@@ -18,9 +18,10 @@ package com.android.test.nullhome;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
-import android.support.test.InstrumentationRegistry;
import android.util.Log;
+import androidx.test.InstrumentationRegistry;
+
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
diff --git a/tests/OneMedia/AndroidManifest.xml b/tests/OneMedia/AndroidManifest.xml
index 8697f1b085bf..7fc352405212 100644
--- a/tests/OneMedia/AndroidManifest.xml
+++ b/tests/OneMedia/AndroidManifest.xml
@@ -1,33 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.onemedia"
- android:versionCode="1"
- android:versionName="1.0" >
+ package="com.android.onemedia"
+ android:versionCode="1"
+ android:versionName="1.0">
<uses-sdk android:minSdkVersion="19"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
- <uses-permission android:name="android.permission.INTERNET" />
- <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.INTERNET"/>
+ <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
- <application
- android:allowBackup="true"
- android:icon="@drawable/ic_launcher"
- android:label="@string/app_name"
- android:theme="@style/AppTheme" >
+ <application android:allowBackup="true"
+ android:icon="@drawable/ic_launcher"
+ android:label="@string/app_name"
+ android:theme="@style/AppTheme">
- <uses-library android:name="org.apache.http.legacy" android:required="false" />
- <activity
- android:name="com.android.onemedia.OnePlayerActivity"
- android:label="@string/app_name" >
+ <uses-library android:name="org.apache.http.legacy"
+ android:required="false"/>
+ <activity android:name="com.android.onemedia.OnePlayerActivity"
+ android:label="@string/app_name"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <service
- android:name="com.android.onemedia.OnePlayerService"
- android:exported="true"
- android:process="com.android.onemedia.service" />
+ <service android:name="com.android.onemedia.OnePlayerService"
+ android:exported="true"
+ android:process="com.android.onemedia.service"/>
</application>
</manifest>
diff --git a/tests/OneMedia/src/com/android/onemedia/NotificationHelper.java b/tests/OneMedia/src/com/android/onemedia/NotificationHelper.java
index ceb0937b9165..6483c924cd67 100644
--- a/tests/OneMedia/src/com/android/onemedia/NotificationHelper.java
+++ b/tests/OneMedia/src/com/android/onemedia/NotificationHelper.java
@@ -52,22 +52,22 @@ public class NotificationHelper extends BroadcastReceiver {
mIntents.put(R.drawable.ic_pause, PendingIntent.getBroadcast(mService, 100, new Intent(
com.android.onemedia.playback.RequestUtils.ACTION_PAUSE).setPackage(pkg),
- PendingIntent.FLAG_CANCEL_CURRENT));
+ PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_MUTABLE_UNAUDITED));
mIntents.put(R.drawable.ic_play_arrow, PendingIntent.getBroadcast(mService, 100,
new Intent(com.android.onemedia.playback.RequestUtils.ACTION_PLAY).setPackage(pkg),
- PendingIntent.FLAG_CANCEL_CURRENT));
+ PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_MUTABLE_UNAUDITED));
mIntents.put(R.drawable.ic_skip_previous, PendingIntent.getBroadcast(mService, 100,
new Intent(com.android.onemedia.playback.RequestUtils.ACTION_PREV).setPackage(pkg),
- PendingIntent.FLAG_CANCEL_CURRENT));
+ PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_MUTABLE_UNAUDITED));
mIntents.put(R.drawable.ic_skip_next, PendingIntent.getBroadcast(mService, 100,
new Intent(com.android.onemedia.playback.RequestUtils.ACTION_NEXT).setPackage(pkg),
- PendingIntent.FLAG_CANCEL_CURRENT));
+ PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_MUTABLE_UNAUDITED));
mIntents.put(R.drawable.ic_fast_rewind, PendingIntent.getBroadcast(mService, 100,
new Intent(com.android.onemedia.playback.RequestUtils.ACTION_REW).setPackage(pkg),
- PendingIntent.FLAG_CANCEL_CURRENT));
+ PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_MUTABLE_UNAUDITED));
mIntents.put(R.drawable.ic_fast_forward, PendingIntent.getBroadcast(mService, 100,
new Intent(com.android.onemedia.playback.RequestUtils.ACTION_FFWD).setPackage(pkg),
- PendingIntent.FLAG_CANCEL_CURRENT));
+ PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_MUTABLE_UNAUDITED));
}
/**
diff --git a/tests/PackageWatchdog/TEST_MAPPING b/tests/PackageWatchdog/TEST_MAPPING
new file mode 100644
index 000000000000..6494a273eced
--- /dev/null
+++ b/tests/PackageWatchdog/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "presubmit": [
+ {
+ "name": "PackageWatchdogTest"
+ }
+ ]
+}
diff --git a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
index ae93a81f274e..96bbf82cfba7 100644
--- a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
+++ b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
@@ -22,7 +22,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
import static com.google.common.truth.Truth.assertThat;
-import static org.junit.Assert.fail;
+import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
@@ -43,10 +43,15 @@ import android.os.SystemProperties;
import android.os.test.TestLooper;
import android.provider.DeviceConfig;
import android.util.AtomicFile;
+import android.util.LongArrayQueue;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
+import android.util.Xml;
import androidx.test.InstrumentationRegistry;
import com.android.dx.mockito.inline.extended.ExtendedMockito;
+import com.android.internal.util.XmlUtils;
import com.android.server.PackageWatchdog.HealthCheckState;
import com.android.server.PackageWatchdog.MonitoredPackage;
import com.android.server.PackageWatchdog.PackageHealthObserver;
@@ -64,6 +69,7 @@ import org.mockito.quality.Strictness;
import org.mockito.stubbing.Answer;
import java.io.File;
+import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -72,11 +78,15 @@ import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
+import java.util.function.Supplier;
/**
* Test PackageWatchdog.
*/
public class PackageWatchdogTest {
+ private static final long RETRY_MAX_COUNT = 30;
+ private static final long RETRY_TIMEOUT_MILLIS = 500;
+
private static final String APP_A = "com.package.a";
private static final String APP_B = "com.package.b";
private static final String APP_C = "com.package.c";
@@ -91,6 +101,8 @@ public class PackageWatchdogTest {
private final TestClock mTestClock = new TestClock();
private TestLooper mTestLooper;
private Context mSpyContext;
+ // Keep track of all created watchdogs to apply device config changes
+ private List<PackageWatchdog> mAllocatedWatchdogs;
@Mock
private ConnectivityModuleConnector mConnectivityModuleConnector;
@Mock
@@ -100,12 +112,23 @@ public class PackageWatchdogTest {
private MockitoSession mSession;
private HashMap<String, String> mSystemSettingsMap;
+ private boolean retry(Supplier<Boolean> supplier) throws Exception {
+ for (int i = 0; i < RETRY_MAX_COUNT; ++i) {
+ if (supplier.get()) {
+ return true;
+ }
+ Thread.sleep(RETRY_TIMEOUT_MILLIS);
+ }
+ return false;
+ }
+
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
new File(InstrumentationRegistry.getContext().getFilesDir(),
"package-watchdog.xml").delete();
- adoptShellPermissions(Manifest.permission.READ_DEVICE_CONFIG);
+ adoptShellPermissions(Manifest.permission.READ_DEVICE_CONFIG,
+ Manifest.permission.WRITE_DEVICE_CONFIG);
mTestLooper = new TestLooper();
mSpyContext = spy(InstrumentationRegistry.getContext());
when(mSpyContext.getPackageManager()).thenReturn(mMockPackageManager);
@@ -150,12 +173,27 @@ public class PackageWatchdogTest {
return storedValue == null ? defaultValue : Long.parseLong(storedValue);
}
).when(() -> SystemProperties.getLong(anyString(), anyLong()));
+
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ROLLBACK,
+ PackageWatchdog.PROPERTY_WATCHDOG_EXPLICIT_HEALTH_CHECK_ENABLED,
+ Boolean.toString(true), false);
+
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ROLLBACK,
+ PackageWatchdog.PROPERTY_WATCHDOG_TRIGGER_FAILURE_COUNT,
+ Integer.toString(PackageWatchdog.DEFAULT_TRIGGER_FAILURE_COUNT), false);
+
+ mAllocatedWatchdogs = new ArrayList<>();
}
@After
public void tearDown() throws Exception {
dropShellPermissions();
mSession.finishMocking();
+ // Clean up listeners since too many listeners will delay notifications significantly
+ for (PackageWatchdog watchdog : mAllocatedWatchdogs) {
+ watchdog.removePropertyChangedListener();
+ }
+ mAllocatedWatchdogs.clear();
}
@Test
@@ -376,7 +414,7 @@ public class PackageWatchdogTest {
TestObserver observer = new TestObserver(OBSERVER_NAME_1) {
@Override
public int onHealthCheckFailed(VersionedPackage versionedPackage,
- int failureReason) {
+ int failureReason, int mitigationCount) {
if (versionedPackage.getVersionCode() == VERSION_CODE) {
// Only rollback for specific versionCode
return PackageHealthObserverImpact.USER_IMPACT_MEDIUM;
@@ -604,10 +642,6 @@ public class PackageWatchdogTest {
*/
@Test
public void testExplicitHealthCheckStateChanges() throws Exception {
- adoptShellPermissions(
- Manifest.permission.WRITE_DEVICE_CONFIG,
- Manifest.permission.READ_DEVICE_CONFIG);
-
TestController controller = new TestController();
PackageWatchdog watchdog = createWatchdog(controller, true /* withPackagesReady */);
TestObserver observer = new TestObserver(OBSERVER_NAME_1,
@@ -739,7 +773,8 @@ public class PackageWatchdogTest {
false /* hasPassedHealthCheck */);
MonitoredPackage m2 = wd.newMonitoredPackage(APP_B, LONG_DURATION, false);
MonitoredPackage m3 = wd.newMonitoredPackage(APP_C, LONG_DURATION, false);
- MonitoredPackage m4 = wd.newMonitoredPackage(APP_D, LONG_DURATION, SHORT_DURATION, true);
+ MonitoredPackage m4 = wd.newMonitoredPackage(APP_D, LONG_DURATION, SHORT_DURATION, true,
+ new LongArrayQueue());
// Verify transition: inactive -> active -> passed
// Verify initially inactive
@@ -799,9 +834,6 @@ public class PackageWatchdogTest {
/** Test default values are used when device property is invalid. */
@Test
public void testInvalidConfig_watchdogTriggerFailureCount() {
- adoptShellPermissions(
- Manifest.permission.WRITE_DEVICE_CONFIG,
- Manifest.permission.READ_DEVICE_CONFIG);
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ROLLBACK,
PackageWatchdog.PROPERTY_WATCHDOG_TRIGGER_FAILURE_COUNT,
Integer.toString(-1), /*makeDefault*/false);
@@ -827,9 +859,6 @@ public class PackageWatchdogTest {
/** Test default values are used when device property is invalid. */
@Test
public void testInvalidConfig_watchdogTriggerDurationMillis() {
- adoptShellPermissions(
- Manifest.permission.WRITE_DEVICE_CONFIG,
- Manifest.permission.READ_DEVICE_CONFIG);
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ROLLBACK,
PackageWatchdog.PROPERTY_WATCHDOG_TRIGGER_FAILURE_COUNT,
Integer.toString(2), /*makeDefault*/false);
@@ -842,7 +871,6 @@ public class PackageWatchdogTest {
watchdog.startObservingHealth(observer, Arrays.asList(APP_A, APP_B), Long.MAX_VALUE);
watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)),
PackageWatchdog.FAILURE_REASON_UNKNOWN);
- mTestLooper.dispatchAll();
moveTimeForwardAndDispatch(PackageWatchdog.DEFAULT_TRIGGER_FAILURE_DURATION_MS + 1);
watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)),
PackageWatchdog.FAILURE_REASON_UNKNOWN);
@@ -854,7 +882,6 @@ public class PackageWatchdogTest {
watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_B, VERSION_CODE)),
PackageWatchdog.FAILURE_REASON_UNKNOWN);
- mTestLooper.dispatchAll();
moveTimeForwardAndDispatch(PackageWatchdog.DEFAULT_TRIGGER_FAILURE_DURATION_MS - 1);
watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_B, VERSION_CODE)),
PackageWatchdog.FAILURE_REASON_UNKNOWN);
@@ -909,9 +936,6 @@ public class PackageWatchdogTest {
/** Test we are notified when enough failures are triggered within any window. */
@Test
public void testFailureTriggerWindow() {
- adoptShellPermissions(
- Manifest.permission.WRITE_DEVICE_CONFIG,
- Manifest.permission.READ_DEVICE_CONFIG);
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ROLLBACK,
PackageWatchdog.PROPERTY_WATCHDOG_TRIGGER_FAILURE_COUNT,
Integer.toString(3), /*makeDefault*/false);
@@ -925,11 +949,9 @@ public class PackageWatchdogTest {
// Raise 2 failures at t=0 and t=900 respectively
watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)),
PackageWatchdog.FAILURE_REASON_UNKNOWN);
- mTestLooper.dispatchAll();
moveTimeForwardAndDispatch(900);
watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)),
PackageWatchdog.FAILURE_REASON_UNKNOWN);
- mTestLooper.dispatchAll();
// Raise 2 failures at t=1100
moveTimeForwardAndDispatch(200);
@@ -1064,6 +1086,31 @@ public class PackageWatchdogTest {
}
/**
+ * Ensure that the correct mitigation counts are sent to the boot loop observer.
+ */
+ @Test
+ public void testMultipleBootLoopMitigation() {
+ PackageWatchdog watchdog = createWatchdog();
+ TestObserver bootObserver = new TestObserver(OBSERVER_NAME_1);
+ watchdog.registerHealthObserver(bootObserver);
+ for (int i = 0; i < 4; i++) {
+ for (int j = 0; j < PackageWatchdog.DEFAULT_BOOT_LOOP_TRIGGER_COUNT; j++) {
+ watchdog.noteBoot();
+ }
+ }
+
+ moveTimeForwardAndDispatch(PackageWatchdog.DEFAULT_DEESCALATION_WINDOW_MS + 1);
+
+ for (int i = 0; i < 4; i++) {
+ for (int j = 0; j < PackageWatchdog.DEFAULT_BOOT_LOOP_TRIGGER_COUNT; j++) {
+ watchdog.noteBoot();
+ }
+ }
+
+ assertThat(bootObserver.mBootMitigationCounts).isEqualTo(List.of(1, 2, 3, 4, 1, 2, 3, 4));
+ }
+
+ /**
* Ensure that passing a null list of failed packages does not cause any mitigation logic to
* execute.
*/
@@ -1146,6 +1193,172 @@ public class PackageWatchdogTest {
assertThat(observer.mMitigatedPackages).isEqualTo(List.of(APP_A));
}
+ /**
+ * Ensure that the sliding window logic results in the correct mitigation count being sent to
+ * an observer.
+ */
+ @Test
+ public void testMitigationSlidingWindow() {
+ PackageWatchdog watchdog = createWatchdog();
+ TestObserver observer = new TestObserver(OBSERVER_NAME_1);
+ watchdog.startObservingHealth(observer, List.of(APP_A),
+ PackageWatchdog.DEFAULT_OBSERVING_DURATION_MS * 2);
+
+
+ raiseFatalFailureAndDispatch(watchdog, Arrays.asList(new VersionedPackage(APP_A,
+ VERSION_CODE)), PackageWatchdog.FAILURE_REASON_UNKNOWN);
+
+ moveTimeForwardAndDispatch(TimeUnit.MINUTES.toMillis(10));
+
+ raiseFatalFailureAndDispatch(watchdog, Arrays.asList(new VersionedPackage(APP_A,
+ VERSION_CODE)), PackageWatchdog.FAILURE_REASON_UNKNOWN);
+ raiseFatalFailureAndDispatch(watchdog, Arrays.asList(new VersionedPackage(APP_A,
+ VERSION_CODE)), PackageWatchdog.FAILURE_REASON_UNKNOWN);
+
+ moveTimeForwardAndDispatch(PackageWatchdog.DEFAULT_DEESCALATION_WINDOW_MS);
+
+ // The first failure will be outside the threshold.
+ raiseFatalFailureAndDispatch(watchdog, Arrays.asList(new VersionedPackage(APP_A,
+ VERSION_CODE)), PackageWatchdog.FAILURE_REASON_UNKNOWN);
+
+ moveTimeForwardAndDispatch(TimeUnit.MINUTES.toMillis(20));
+
+ // The next 2 failures will also be outside the threshold.
+ raiseFatalFailureAndDispatch(watchdog, Arrays.asList(new VersionedPackage(APP_A,
+ VERSION_CODE)), PackageWatchdog.FAILURE_REASON_UNKNOWN);
+ raiseFatalFailureAndDispatch(watchdog, Arrays.asList(new VersionedPackage(APP_A,
+ VERSION_CODE)), PackageWatchdog.FAILURE_REASON_UNKNOWN);
+
+ assertThat(observer.mMitigationCounts).isEqualTo(List.of(1, 2, 3, 3, 2, 3));
+ }
+
+ @Test
+ public void testNormalizingMitigationCalls() {
+ PackageWatchdog watchdog = createWatchdog();
+
+ LongArrayQueue mitigationCalls = new LongArrayQueue();
+ mitigationCalls.addLast(1000);
+ mitigationCalls.addLast(2000);
+ mitigationCalls.addLast(3000);
+
+ MonitoredPackage pkg = watchdog.newMonitoredPackage(
+ "test", 123, 456, true, mitigationCalls);
+
+ // Make current system uptime 10000ms.
+ moveTimeForwardAndDispatch(9999);
+
+ LongArrayQueue expectedCalls = pkg.normalizeMitigationCalls();
+
+ assertThat(expectedCalls.size()).isEqualTo(mitigationCalls.size());
+
+ for (int i = 0; i < mitigationCalls.size(); i++) {
+ assertThat(expectedCalls.get(i)).isEqualTo(mitigationCalls.get(i) - 10000);
+ }
+ }
+
+ /**
+ * Ensure that a {@link MonitoredPackage} may be correctly written and read in order to persist
+ * across reboots.
+ */
+ @Test
+ public void testWritingAndReadingMonitoredPackage() throws Exception {
+ PackageWatchdog watchdog = createWatchdog();
+
+ LongArrayQueue mitigationCalls = new LongArrayQueue();
+ mitigationCalls.addLast(1000);
+ mitigationCalls.addLast(2000);
+ mitigationCalls.addLast(3000);
+ MonitoredPackage writePkg = watchdog.newMonitoredPackage(
+ "test.package", 1000, 2000, true, mitigationCalls);
+
+ // Move time forward so that the current uptime is 4000ms. Therefore, the written mitigation
+ // calls will each be reduced by 4000.
+ moveTimeForwardAndDispatch(3999);
+ LongArrayQueue expectedCalls = new LongArrayQueue();
+ expectedCalls.addLast(-3000);
+ expectedCalls.addLast(-2000);
+ expectedCalls.addLast(-1000);
+ MonitoredPackage expectedPkg = watchdog.newMonitoredPackage(
+ "test.package", 1000, 2000, true, expectedCalls);
+
+ // Write the package
+ File tmpFile = File.createTempFile("package-watchdog-test", ".xml");
+ AtomicFile testFile = new AtomicFile(tmpFile);
+ FileOutputStream stream = testFile.startWrite();
+ TypedXmlSerializer outputSerializer = Xml.resolveSerializer(stream);
+ outputSerializer.startDocument(null, true);
+ writePkg.writeLocked(outputSerializer);
+ outputSerializer.endDocument();
+ testFile.finishWrite(stream);
+
+ // Read the package
+ TypedXmlPullParser parser = Xml.resolvePullParser(testFile.openRead());
+ XmlUtils.beginDocument(parser, "package");
+ MonitoredPackage readPkg = watchdog.parseMonitoredPackage(parser);
+
+ assertTrue(readPkg.isEqualTo(expectedPkg));
+ }
+
+ /**
+ * Tests device config changes are propagated correctly.
+ */
+ @Test
+ public void testDeviceConfigChange_explicitHealthCheckEnabled() throws Exception {
+ TestController controller = new TestController();
+ PackageWatchdog watchdog = createWatchdog(controller, true /* withPackagesReady */);
+ assertThat(controller.mIsEnabled).isTrue();
+
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ROLLBACK,
+ PackageWatchdog.PROPERTY_WATCHDOG_EXPLICIT_HEALTH_CHECK_ENABLED,
+ Boolean.toString(false), /*makeDefault*/false);
+ retry(() -> !controller.mIsEnabled);
+ assertThat(controller.mIsEnabled).isFalse();
+ }
+
+ /**
+ * Tests device config changes are propagated correctly.
+ */
+ @Test
+ public void testDeviceConfigChange_triggerFailureCount() throws Exception {
+ PackageWatchdog watchdog = createWatchdog();
+
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ROLLBACK,
+ PackageWatchdog.PROPERTY_WATCHDOG_TRIGGER_FAILURE_COUNT,
+ Integer.toString(777), false);
+ retry(() -> watchdog.getTriggerFailureCount() == 777);
+ assertThat(watchdog.getTriggerFailureCount()).isEqualTo(777);
+
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ROLLBACK,
+ PackageWatchdog.PROPERTY_WATCHDOG_TRIGGER_FAILURE_COUNT,
+ Integer.toString(0), false);
+ retry(() -> watchdog.getTriggerFailureCount()
+ == PackageWatchdog.DEFAULT_TRIGGER_FAILURE_COUNT);
+ assertThat(watchdog.getTriggerFailureCount()).isEqualTo(
+ PackageWatchdog.DEFAULT_TRIGGER_FAILURE_COUNT);
+ }
+
+ /**
+ * Tests device config changes are propagated correctly.
+ */
+ @Test
+ public void testDeviceConfigChange_triggerFailureDurationMs() throws Exception {
+ PackageWatchdog watchdog = createWatchdog();
+
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ROLLBACK,
+ PackageWatchdog.PROPERTY_WATCHDOG_TRIGGER_DURATION_MILLIS,
+ Integer.toString(888), false);
+ retry(() -> watchdog.getTriggerFailureDurationMs() == 888);
+ assertThat(watchdog.getTriggerFailureDurationMs()).isEqualTo(888);
+
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ROLLBACK,
+ PackageWatchdog.PROPERTY_WATCHDOG_TRIGGER_DURATION_MILLIS,
+ Integer.toString(0), false);
+ retry(() -> watchdog.getTriggerFailureDurationMs()
+ == PackageWatchdog.DEFAULT_TRIGGER_FAILURE_DURATION_MS);
+ assertThat(watchdog.getTriggerFailureDurationMs()).isEqualTo(
+ PackageWatchdog.DEFAULT_TRIGGER_FAILURE_DURATION_MS);
+ }
+
private void adoptShellPermissions(String... permissions) {
InstrumentationRegistry
.getInstrumentation()
@@ -1164,15 +1377,15 @@ public class PackageWatchdogTest {
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ROLLBACK,
PackageWatchdog.PROPERTY_WATCHDOG_EXPLICIT_HEALTH_CHECK_ENABLED,
Boolean.toString(enabled), /*makeDefault*/false);
- //give time for DeviceConfig to broadcast the property value change
- try {
- Thread.sleep(SHORT_DURATION);
- } catch (InterruptedException e) {
- fail("Thread.sleep unexpectedly failed!");
+ // Call updateConfigs() so device config changes take effect immediately
+ for (PackageWatchdog watchdog : mAllocatedWatchdogs) {
+ watchdog.updateConfigs();
}
}
private void moveTimeForwardAndDispatch(long milliSeconds) {
+ // Exhaust all due runnables now which shouldn't be executed after time-leap
+ mTestLooper.dispatchAll();
mTestClock.moveTimeForward(milliSeconds);
mTestLooper.moveTimeForward(milliSeconds);
mTestLooper.dispatchAll();
@@ -1215,6 +1428,7 @@ public class PackageWatchdogTest {
verify(mConnectivityModuleConnector).registerHealthListener(
mConnectivityModuleCallbackCaptor.capture());
}
+ mAllocatedWatchdogs.add(watchdog);
return watchdog;
}
@@ -1227,6 +1441,8 @@ public class PackageWatchdogTest {
private boolean mMitigatedBootLoop = false;
final List<String> mHealthCheckFailedPackages = new ArrayList<>();
final List<String> mMitigatedPackages = new ArrayList<>();
+ final List<Integer> mMitigationCounts = new ArrayList<>();
+ final List<Integer> mBootMitigationCounts = new ArrayList<>();
TestObserver(String name) {
mName = name;
@@ -1238,13 +1454,16 @@ public class PackageWatchdogTest {
mImpact = impact;
}
- public int onHealthCheckFailed(VersionedPackage versionedPackage, int failureReason) {
+ public int onHealthCheckFailed(VersionedPackage versionedPackage, int failureReason,
+ int mitigationCount) {
mHealthCheckFailedPackages.add(versionedPackage.getPackageName());
return mImpact;
}
- public boolean execute(VersionedPackage versionedPackage, int failureReason) {
+ public boolean execute(VersionedPackage versionedPackage, int failureReason,
+ int mitigationCount) {
mMitigatedPackages.add(versionedPackage.getPackageName());
+ mMitigationCounts.add(mitigationCount);
mLastFailureReason = failureReason;
return true;
}
@@ -1261,12 +1480,13 @@ public class PackageWatchdogTest {
return mMayObservePackages;
}
- public int onBootLoop() {
+ public int onBootLoop(int level) {
return mImpact;
}
- public boolean executeBootLoopMitigation() {
+ public boolean executeBootLoopMitigation(int level) {
mMitigatedBootLoop = true;
+ mBootMitigationCounts.add(level);
return true;
}
diff --git a/tests/PlatformCompatGating/src/com/android/tests/gating/PlatformCompatPermissionsTest.java b/tests/PlatformCompatGating/src/com/android/tests/gating/PlatformCompatPermissionsTest.java
index 9b9e5815a588..060133df0a40 100644
--- a/tests/PlatformCompatGating/src/com/android/tests/gating/PlatformCompatPermissionsTest.java
+++ b/tests/PlatformCompatGating/src/com/android/tests/gating/PlatformCompatPermissionsTest.java
@@ -16,6 +16,7 @@
package com.android.tests.gating;
+import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
import static android.Manifest.permission.LOG_COMPAT_CHANGE;
import static android.Manifest.permission.OVERRIDE_COMPAT_CHANGE_CONFIG;
import static android.Manifest.permission.READ_COMPAT_CHANGE_CONFIG;
@@ -261,13 +262,15 @@ public final class PlatformCompatPermissionsTest {
public void clearOverrides_noOverridesPermission_throwsSecurityException()
throws Throwable {
thrown.expect(SecurityException.class);
+ mUiAutomation.adoptShellPermissionIdentity(INTERACT_ACROSS_USERS_FULL);
mPlatformCompat.clearOverrides("foo.bar");
}
@Test
public void clearOverrides_overridesPermission_noThrow()
throws Throwable {
- mUiAutomation.adoptShellPermissionIdentity(OVERRIDE_COMPAT_CHANGE_CONFIG);
+ mUiAutomation.adoptShellPermissionIdentity(OVERRIDE_COMPAT_CHANGE_CONFIG,
+ INTERACT_ACROSS_USERS_FULL);
mPlatformCompat.clearOverrides("foo.bar");
}
@@ -276,13 +279,15 @@ public final class PlatformCompatPermissionsTest {
public void clearOverridesForTest_noOverridesPermission_throwsSecurityException()
throws Throwable {
thrown.expect(SecurityException.class);
+ mUiAutomation.adoptShellPermissionIdentity(INTERACT_ACROSS_USERS_FULL);
mPlatformCompat.clearOverridesForTest("foo.bar");
}
@Test
public void clearOverridesForTest_overridesPermission_noThrow()
throws Throwable {
- mUiAutomation.adoptShellPermissionIdentity(OVERRIDE_COMPAT_CHANGE_CONFIG);
+ mUiAutomation.adoptShellPermissionIdentity(OVERRIDE_COMPAT_CHANGE_CONFIG,
+ INTERACT_ACROSS_USERS_FULL);
mPlatformCompat.clearOverridesForTest("foo.bar");
}
@@ -291,13 +296,15 @@ public final class PlatformCompatPermissionsTest {
public void clearOverride_noOverridesPermission_throwsSecurityException()
throws Throwable {
thrown.expect(SecurityException.class);
+ mUiAutomation.adoptShellPermissionIdentity(INTERACT_ACROSS_USERS_FULL);
mPlatformCompat.clearOverride(1, "foo.bar");
}
@Test
public void clearOverride_overridesPermission_noThrow()
throws Throwable {
- mUiAutomation.adoptShellPermissionIdentity(OVERRIDE_COMPAT_CHANGE_CONFIG);
+ mUiAutomation.adoptShellPermissionIdentity(OVERRIDE_COMPAT_CHANGE_CONFIG,
+ INTERACT_ACROSS_USERS_FULL);
mPlatformCompat.clearOverride(1, "foo.bar");
}
diff --git a/tests/PlatformCompatGating/test-rules/src/android/compat/testing/PlatformCompatChangeRule.java b/tests/PlatformCompatGating/test-rules/src/android/compat/testing/PlatformCompatChangeRule.java
index d6846faa5c00..0c5205c848da 100644
--- a/tests/PlatformCompatGating/test-rules/src/android/compat/testing/PlatformCompatChangeRule.java
+++ b/tests/PlatformCompatGating/test-rules/src/android/compat/testing/PlatformCompatChangeRule.java
@@ -94,10 +94,7 @@ public class PlatformCompatChangeRule extends CoreCompatChangeRule {
if (platformCompat == null) {
throw new IllegalStateException("Could not get IPlatformCompat service!");
}
- uiAutomation.adoptShellPermissionIdentity(
- Manifest.permission.LOG_COMPAT_CHANGE,
- Manifest.permission.OVERRIDE_COMPAT_CHANGE_CONFIG,
- Manifest.permission.READ_COMPAT_CHANGE_CONFIG);
+ adoptShellPermissions(uiAutomation);
Compatibility.setOverrides(mConfig);
try {
platformCompat.setOverridesForTest(new CompatibilityChangeConfig(mConfig),
@@ -105,6 +102,7 @@ public class PlatformCompatChangeRule extends CoreCompatChangeRule {
try {
mTestStatement.evaluate();
} finally {
+ adoptShellPermissions(uiAutomation);
platformCompat.clearOverridesForTest(packageName);
}
} catch (RemoteException e) {
@@ -114,5 +112,14 @@ public class PlatformCompatChangeRule extends CoreCompatChangeRule {
Compatibility.clearOverrides();
}
}
+
+ private static void adoptShellPermissions(UiAutomation uiAutomation) {
+ uiAutomation.adoptShellPermissionIdentity(
+ Manifest.permission.LOG_COMPAT_CHANGE,
+ Manifest.permission.OVERRIDE_COMPAT_CHANGE_CONFIG,
+ Manifest.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD,
+ Manifest.permission.READ_COMPAT_CHANGE_CONFIG,
+ Manifest.permission.INTERACT_ACROSS_USERS_FULL);
+ }
}
}
diff --git a/tests/RenderThreadTest/AndroidManifest.xml b/tests/RenderThreadTest/AndroidManifest.xml
index a7f4f6e9c5c8..22a4e43c988c 100644
--- a/tests/RenderThreadTest/AndroidManifest.xml
+++ b/tests/RenderThreadTest/AndroidManifest.xml
@@ -1,25 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.example.renderthread"
- android:versionCode="1"
- android:versionName="1.0" >
+ package="com.example.renderthread"
+ android:versionCode="1"
+ android:versionName="1.0">
- <application
- android:allowBackup="true"
- android:icon="@drawable/ic_launcher"
- android:label="@string/app_name"
- android:theme="@style/AppTheme" >
- <activity
- android:name=".MainActivity"
- android:label="@string/app_name" >
+ <application android:allowBackup="true"
+ android:icon="@drawable/ic_launcher"
+ android:label="@string/app_name"
+ android:theme="@style/AppTheme">
+ <activity android:name=".MainActivity"
+ android:label="@string/app_name"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
+ <action android:name="android.intent.action.MAIN"/>
- <category android:name="android.intent.category.LAUNCHER" />
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:name=".SubActivity"
- android:theme="@style/AppTheme.Transparent" />
+ android:theme="@style/AppTheme.Transparent"/>
</application>
</manifest>
diff --git a/tests/RollbackTest/Android.bp b/tests/RollbackTest/Android.bp
index f7dda5798a83..6e1cef496f40 100644
--- a/tests/RollbackTest/Android.bp
+++ b/tests/RollbackTest/Android.bp
@@ -24,6 +24,7 @@ package {
android_test {
name: "RollbackTest",
manifest: "RollbackTest/AndroidManifest.xml",
+ platform_apis: true,
srcs: ["RollbackTest/src/**/*.java"],
static_libs: ["androidx.test.rules", "cts-rollback-lib", "cts-install-lib"],
test_suites: ["general-tests"],
diff --git a/tests/RollbackTest/MultiUserRollbackTest.xml b/tests/RollbackTest/MultiUserRollbackTest.xml
index 2f62af1856da..8fa0510d9e71 100644
--- a/tests/RollbackTest/MultiUserRollbackTest.xml
+++ b/tests/RollbackTest/MultiUserRollbackTest.xml
@@ -20,6 +20,8 @@
<option name="run-command" value="pm uninstall com.android.cts.install.lib.testapp.B" />
<option name="teardown-command" value="pm uninstall com.android.cts.install.lib.testapp.A" />
<option name="teardown-command" value="pm uninstall com.android.cts.install.lib.testapp.B" />
+ <option name="run-command" value="setprop persist.rollback.is_test 1" />
+ <option name="teardown-command" value="setprop persist.rollback.is_test 0" />
</target_preparer>
<test class="com.android.tradefed.testtype.HostTest" >
<option name="class" value="com.android.tests.rollback.host.MultiUserRollbackTest" />
diff --git a/tests/RollbackTest/MultiUserRollbackTest/src/com/android/tests/rollback/host/MultiUserRollbackTest.java b/tests/RollbackTest/MultiUserRollbackTest/src/com/android/tests/rollback/host/MultiUserRollbackTest.java
index f16084744853..35859fe1472e 100644
--- a/tests/RollbackTest/MultiUserRollbackTest/src/com/android/tests/rollback/host/MultiUserRollbackTest.java
+++ b/tests/RollbackTest/MultiUserRollbackTest/src/com/android/tests/rollback/host/MultiUserRollbackTest.java
@@ -48,6 +48,8 @@ public class MultiUserRollbackTest extends BaseHostJUnit4Test {
public void tearDown() throws Exception {
removeSecondaryUserIfNecessary();
runPhaseForUsers("cleanUp", mOriginalUserId);
+ uninstallPackage("com.android.cts.install.lib.testapp.A");
+ uninstallPackage("com.android.cts.install.lib.testapp.B");
}
@Before
@@ -88,6 +90,13 @@ public class MultiUserRollbackTest extends BaseHostJUnit4Test {
}
@Test
+ public void testBadUpdateRollback() throws Exception {
+ // Need to switch user in order to send broadcasts in device tests
+ assertTrue(getDevice().switchUser(mSecondaryUserId));
+ runPhaseForUsers("testBadUpdateRollback", mSecondaryUserId);
+ }
+
+ @Test
public void testMultipleUsers() throws Exception {
runPhaseForUsers("testMultipleUsersInstallV1", mOriginalUserId, mSecondaryUserId);
runPhaseForUsers("testMultipleUsersUpgradeToV2", mOriginalUserId);
@@ -111,6 +120,8 @@ public class MultiUserRollbackTest extends BaseHostJUnit4Test {
private void removeSecondaryUserIfNecessary() throws Exception {
if (mSecondaryUserId != -1) {
+ // Can't remove the 2nd user without switching out of it
+ assertTrue(getDevice().switchUser(mOriginalUserId));
getDevice().removeUser(mSecondaryUserId);
mSecondaryUserId = -1;
}
diff --git a/tests/RollbackTest/NetworkStagedRollbackTest.xml b/tests/RollbackTest/NetworkStagedRollbackTest.xml
index 2ab907a59298..13f603140aee 100644
--- a/tests/RollbackTest/NetworkStagedRollbackTest.xml
+++ b/tests/RollbackTest/NetworkStagedRollbackTest.xml
@@ -24,6 +24,8 @@
<option name="run-command" value="am broadcast -a 'com.google.android.gms.phenotype.FLAG_OVERRIDE' --es package &quot;com.google.android.gms.platformconfigurator&quot; --es user '\\*' --esa flags &quot;ModuleConfig__versioned_immediate_commit_packages&quot; --esa types &quot;bytes&quot; --esa values &quot;Cm5vdGFwYWNrYWdlOgA=&quot; com.google.android.gms" />
<option name="teardown-command" value="am broadcast -a 'com.google.android.gms.phenotype.FLAG_OVERRIDE' --es action delete --es package &quot;com.google.android.gms.platformconfigurator&quot; --es user '\*' --esa flag &quot;ModuleConfig__immediate_commit_packages&quot; com.google.android.gms" />
<option name="teardown-command" value="am broadcast -a 'com.google.android.gms.phenotype.FLAG_OVERRIDE' --es action delete --es package &quot;com.google.android.gms.platformconfigurator&quot; --es user '\*' --esa flag &quot;ModuleConfig__versioned_immediate_commit_packages&quot; com.google.android.gms" />
+ <option name="run-command" value="setprop persist.rollback.is_test 1" />
+ <option name="teardown-command" value="setprop persist.rollback.is_test 0" />
</target_preparer>
<test class="com.android.tradefed.testtype.HostTest" >
<option name="class" value="com.android.tests.rollback.host.NetworkStagedRollbackTest" />
diff --git a/tests/RollbackTest/NetworkStagedRollbackTest/src/com/android/tests/rollback/host/NetworkStagedRollbackTest.java b/tests/RollbackTest/NetworkStagedRollbackTest/src/com/android/tests/rollback/host/NetworkStagedRollbackTest.java
index fb4a2b209347..c769a6f8c018 100644
--- a/tests/RollbackTest/NetworkStagedRollbackTest/src/com/android/tests/rollback/host/NetworkStagedRollbackTest.java
+++ b/tests/RollbackTest/NetworkStagedRollbackTest/src/com/android/tests/rollback/host/NetworkStagedRollbackTest.java
@@ -16,8 +16,6 @@
package com.android.tests.rollback.host;
-import static com.android.tests.rollback.host.WatchdogEventLogger.watchdogEventOccurred;
-
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
@@ -26,11 +24,11 @@ import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
import org.junit.After;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
-import java.util.List;
import java.util.concurrent.TimeUnit;
/**
@@ -76,6 +74,7 @@ public class NetworkStagedRollbackTest extends BaseHostJUnit4Test {
/**
* Tests failed network health check triggers watchdog staged rollbacks.
*/
+ @Ignore("b/159569441")
@Test
public void testNetworkFailedRollback() throws Exception {
try {
@@ -96,12 +95,11 @@ public class NetworkStagedRollbackTest extends BaseHostJUnit4Test {
// Verify rollback was executed after health check deadline
runPhase("testNetworkFailedRollback_Phase3");
- List<String> watchdogEvents = mLogger.getWatchdogLoggingEvents();
- assertTrue(watchdogEventOccurred(watchdogEvents, ROLLBACK_INITIATE, null,
+ assertTrue(mLogger.watchdogEventOccurred(ROLLBACK_INITIATE, null,
REASON_EXPLICIT_HEALTH_CHECK, null));
- assertTrue(watchdogEventOccurred(watchdogEvents, ROLLBACK_BOOT_TRIGGERED, null,
+ assertTrue(mLogger.watchdogEventOccurred(ROLLBACK_BOOT_TRIGGERED, null,
null, null));
- assertTrue(watchdogEventOccurred(watchdogEvents, ROLLBACK_SUCCESS, null, null, null));
+ assertTrue(mLogger.watchdogEventOccurred(ROLLBACK_SUCCESS, null, null, null));
} finally {
// Reconnect internet again so we won't break tests which assume internet available
getDevice().executeShellCommand("svc wifi enable");
@@ -132,8 +130,7 @@ public class NetworkStagedRollbackTest extends BaseHostJUnit4Test {
// Verify rollback was not executed after health check deadline
runPhase("testNetworkPassedDoesNotRollback_Phase3");
- List<String> watchdogEvents = mLogger.getWatchdogLoggingEvents();
- assertEquals(watchdogEventOccurred(watchdogEvents, null, null,
+ assertEquals(mLogger.watchdogEventOccurred(null, null,
REASON_EXPLICIT_HEALTH_CHECK, null), false);
}
}
diff --git a/tests/RollbackTest/RollbackTest.xml b/tests/RollbackTest/RollbackTest.xml
index 7b85cc84f1f5..fbb6e46e1721 100644
--- a/tests/RollbackTest/RollbackTest.xml
+++ b/tests/RollbackTest/RollbackTest.xml
@@ -27,6 +27,8 @@
<option name="run-command" value="pm uninstall com.android.cts.install.lib.testapp.B" />
<option name="teardown-command" value="pm uninstall com.android.cts.install.lib.testapp.A" />
<option name="teardown-command" value="pm uninstall com.android.cts.install.lib.testapp.B" />
+ <option name="run-command" value="setprop persist.rollback.is_test 1" />
+ <option name="teardown-command" value="setprop persist.rollback.is_test 0" />
</target_preparer>
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="com.android.tests.rollback" />
diff --git a/tests/RollbackTest/RollbackTest/AndroidManifest.xml b/tests/RollbackTest/RollbackTest/AndroidManifest.xml
index 9274da268735..590105b3209f 100644
--- a/tests/RollbackTest/RollbackTest/AndroidManifest.xml
+++ b/tests/RollbackTest/RollbackTest/AndroidManifest.xml
@@ -19,8 +19,6 @@
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
<application>
- <receiver android:name="com.android.cts.install.lib.LocalIntentSender"
- android:exported="true" />
<uses-library android:name="android.test.runner" />
</application>
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/MultiUserRollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/MultiUserRollbackTest.java
index 5d133a4de13d..d37dd7b9ceab 100644
--- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/MultiUserRollbackTest.java
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/MultiUserRollbackTest.java
@@ -70,6 +70,11 @@ public class MultiUserRollbackTest {
new RollbackTest().testBasic();
}
+ @Test
+ public void testBadUpdateRollback() throws Exception {
+ new RollbackTest().testBadUpdateRollback();
+ }
+
/**
* Install version 1 of the test app. This method is run for both users.
*/
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
index dd08771b220d..7b2a07fd80f8 100644
--- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
@@ -175,7 +175,7 @@ public class RollbackTest {
assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
UserManager um = (UserManager) context.getSystemService(context.USER_SERVICE);
- List<Integer> userIds = um.getUsers(true)
+ List<Integer> userIds = um.getAliveUsers()
.stream().map(user -> user.id).collect(Collectors.toList());
assertThat(InstallUtils.isOnlyInstalledForUser(TestApp.A,
context.getUserId(), userIds)).isTrue();
@@ -1193,28 +1193,74 @@ public class RollbackTest {
Manifest.permission.DELETE_PACKAGES,
Manifest.permission.TEST_MANAGE_ROLLBACKS);
- Uninstall.packages(TestApp.A, TestApp.B);
- Install.multi(TestApp.A1, TestApp.B1).commit();
+ Uninstall.packages(TestApp.A, TestApp.B, TestApp.C);
+ Install.multi(TestApp.A1, TestApp.B1, TestApp.C1).commit();
// Write user data version = 1
InstallUtils.processUserData(TestApp.A);
InstallUtils.processUserData(TestApp.B);
+ InstallUtils.processUserData(TestApp.C);
Install a2 = Install.single(TestApp.A2)
.setEnableRollback(PackageManager.RollbackDataPolicy.WIPE);
Install b2 = Install.single(TestApp.B2)
.setEnableRollback(PackageManager.RollbackDataPolicy.RESTORE);
- Install.multi(a2, b2).setEnableRollback().commit();
+ // The rollback data policy of C2 is specified in the manifest
+ Install c2 = Install.single(TestApp.C2).setEnableRollback();
+ Install.multi(a2, b2, c2).setEnableRollback().commit();
// Write user data version = 2
InstallUtils.processUserData(TestApp.A);
InstallUtils.processUserData(TestApp.B);
+ InstallUtils.processUserData(TestApp.C);
RollbackInfo info = RollbackUtils.getAvailableRollback(TestApp.A);
RollbackUtils.rollback(info.getRollbackId());
// Read user data version from userdata.txt
// A's user data version is -1 for user data is wiped.
// B's user data version is 1 as rollback committed.
+ // C's user data version is -1 for user data is wiped.
assertThat(InstallUtils.getUserDataVersion(TestApp.A)).isEqualTo(-1);
assertThat(InstallUtils.getUserDataVersion(TestApp.B)).isEqualTo(1);
+ assertThat(InstallUtils.getUserDataVersion(TestApp.C)).isEqualTo(-1);
+ } finally {
+ InstallUtils.dropShellPermissionIdentity();
+ }
+ }
+
+ /**
+ * Tests an app can be rolled back to the previous signing key.
+ *
+ * <p>The rollback capability in the signing lineage allows an app to be updated to an APK
+ * signed with a previous signing key in the lineage; however this often defeats the purpose
+ * of key rotation as a compromised key could then be used to roll an app back to the previous
+ * key. To avoid requiring the rollback capability to support app rollbacks the PackageManager
+ * allows an app to be rolled back to the previous signing key if the rollback install reason
+ * is set.
+ */
+ @Test
+ public void testRollbackAfterKeyRotation() throws Exception {
+ try {
+ InstallUtils.adoptShellPermissionIdentity(
+ Manifest.permission.INSTALL_PACKAGES,
+ Manifest.permission.DELETE_PACKAGES,
+ Manifest.permission.TEST_MANAGE_ROLLBACKS,
+ Manifest.permission.MANAGE_ROLLBACKS);
+
+ // Uninstall TestApp.A
+ Uninstall.packages(TestApp.A);
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(-1);
+
+ // Install v1 of the app with the original signing key (without rollbacks enabled).
+ Install.single(TestApp.AOriginal1).commit();
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
+
+ // Upgrade from v1 to v2 with the rotated signing key, with rollbacks enabled.
+ Install.single(TestApp.ARotated2).setEnableRollback().commit();
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
+
+ // Roll back the app.
+ RollbackInfo available = waitForAvailableRollback(TestApp.A);
+ RollbackUtils.rollback(available.getRollbackId());
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
} finally {
InstallUtils.dropShellPermissionIdentity();
}
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
index eaf9c7b4cb2e..642b19e6d961 100644
--- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
@@ -34,9 +34,7 @@ import androidx.test.platform.app.InstrumentationRegistry;
import com.android.cts.install.lib.Install;
import com.android.cts.install.lib.InstallUtils;
-import com.android.cts.install.lib.LocalIntentSender;
import com.android.cts.install.lib.TestApp;
-import com.android.cts.install.lib.Uninstall;
import com.android.cts.rollback.lib.Rollback;
import com.android.cts.rollback.lib.RollbackUtils;
import com.android.internal.R;
@@ -89,8 +87,7 @@ public class StagedRollbackTest {
* Enable rollback phase.
*/
@Test
- public void testBadApkOnly_Phase1() throws Exception {
- Uninstall.packages(TestApp.A);
+ public void testBadApkOnly_Phase1_Install() throws Exception {
assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(-1);
Install.single(TestApp.A1).commit();
@@ -105,7 +102,7 @@ public class StagedRollbackTest {
* Confirm that rollback was successfully enabled.
*/
@Test
- public void testBadApkOnly_Phase2() throws Exception {
+ public void testBadApkOnly_Phase2_VerifyInstall() throws Exception {
assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
InstallUtils.processUserData(TestApp.A);
@@ -126,21 +123,11 @@ public class StagedRollbackTest {
}
/**
- * Test rollbacks of staged installs involving only apks with bad update.
- * Trigger rollback phase.
- */
- @Test
- public void testBadApkOnly_Phase3() throws Exception {
- // One more crash to trigger rollback
- RollbackUtils.sendCrashBroadcast(TestApp.A, 1);
- }
-
- /**
* Test rollbacks of staged installs involving only apks.
* Confirm rollback phase.
*/
@Test
- public void testBadApkOnly_Phase4() throws Exception {
+ public void testBadApkOnly_Phase3_VerifyRollback() throws Exception {
assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
InstallUtils.processUserData(TestApp.A);
@@ -159,8 +146,7 @@ public class StagedRollbackTest {
* Stage install an apk with rollback that will be later triggered by unattributable crash.
*/
@Test
- public void testNativeWatchdogTriggersRollback_Phase1() throws Exception {
- Uninstall.packages(TestApp.A);
+ public void testNativeWatchdogTriggersRollback_Phase1_Install() throws Exception {
Install.single(TestApp.A1).commit();
assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
@@ -171,7 +157,7 @@ public class StagedRollbackTest {
* Verify the rollback is available.
*/
@Test
- public void testNativeWatchdogTriggersRollback_Phase2() throws Exception {
+ public void testNativeWatchdogTriggersRollback_Phase2_VerifyInstall() throws Exception {
assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
RollbackManager rm = RollbackUtils.getRollbackManager();
assertThat(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(),
@@ -182,7 +168,7 @@ public class StagedRollbackTest {
* Verify the rollback is committed after crashing.
*/
@Test
- public void testNativeWatchdogTriggersRollback_Phase3() throws Exception {
+ public void testNativeWatchdogTriggersRollback_Phase3_VerifyRollback() throws Exception {
assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
RollbackManager rm = RollbackUtils.getRollbackManager();
assertThat(getUniqueRollbackInfoForPackage(rm.getRecentlyCommittedRollbacks(),
@@ -193,8 +179,7 @@ public class StagedRollbackTest {
* Stage install an apk with rollback that will be later triggered by unattributable crash.
*/
@Test
- public void testNativeWatchdogTriggersRollbackForAll_Phase1() throws Exception {
- Uninstall.packages(TestApp.A);
+ public void testNativeWatchdogTriggersRollbackForAll_Phase1_InstallA() throws Exception {
Install.single(TestApp.A1).commit();
assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
@@ -205,14 +190,13 @@ public class StagedRollbackTest {
* Verify the rollback is available and then install another package with rollback.
*/
@Test
- public void testNativeWatchdogTriggersRollbackForAll_Phase2() throws Exception {
+ public void testNativeWatchdogTriggersRollbackForAll_Phase2_InstallB() throws Exception {
assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
RollbackManager rm = RollbackUtils.getRollbackManager();
assertThat(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(),
TestApp.A)).isNotNull();
// Install another package with rollback
- Uninstall.packages(TestApp.B);
Install.single(TestApp.B1).commit();
assertThat(InstallUtils.getInstalledVersion(TestApp.B)).isEqualTo(1);
@@ -223,7 +207,7 @@ public class StagedRollbackTest {
* Verify the rollbacks are available.
*/
@Test
- public void testNativeWatchdogTriggersRollbackForAll_Phase3() throws Exception {
+ public void testNativeWatchdogTriggersRollbackForAll_Phase3_VerifyInstall() throws Exception {
assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
assertThat(InstallUtils.getInstalledVersion(TestApp.B)).isEqualTo(2);
RollbackManager rm = RollbackUtils.getRollbackManager();
@@ -237,7 +221,7 @@ public class StagedRollbackTest {
* Verify the rollbacks are committed after crashing.
*/
@Test
- public void testNativeWatchdogTriggersRollbackForAll_Phase4() throws Exception {
+ public void testNativeWatchdogTriggersRollbackForAll_Phase4_VerifyRollback() throws Exception {
assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
assertThat(InstallUtils.getInstalledVersion(TestApp.B)).isEqualTo(1);
RollbackManager rm = RollbackUtils.getRollbackManager();
@@ -248,8 +232,7 @@ public class StagedRollbackTest {
}
@Test
- public void testPreviouslyAbandonedRollbacks_Phase1() throws Exception {
- Uninstall.packages(TestApp.A);
+ public void testPreviouslyAbandonedRollbacks_Phase1_InstallAndAbandon() throws Exception {
Install.single(TestApp.A1).commit();
assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
@@ -258,15 +241,11 @@ public class StagedRollbackTest {
.getPackageManager().getPackageInstaller();
pi.abandonSession(sessionId);
- // Remove the first intent sender result, so that the next staged install session does not
- // erroneously think that it has itself been abandoned.
- // TODO(b/136260017): Restructure LocalIntentSender to negate the need for this step.
- LocalIntentSender.getIntentSenderResult();
Install.single(TestApp.A2).setStaged().setEnableRollback().commit();
}
@Test
- public void testPreviouslyAbandonedRollbacks_Phase2() throws Exception {
+ public void testPreviouslyAbandonedRollbacks_Phase2_Rollback() throws Exception {
assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
InstallUtils.processUserData(TestApp.A);
@@ -277,10 +256,9 @@ public class StagedRollbackTest {
}
@Test
- public void testPreviouslyAbandonedRollbacks_Phase3() throws Exception {
+ public void testPreviouslyAbandonedRollbacks_Phase3_VerifyRollback() throws Exception {
assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
InstallUtils.processUserData(TestApp.A);
- Uninstall.packages(TestApp.A);
}
private static String getModuleMetadataPackageName() {
@@ -289,7 +267,7 @@ public class StagedRollbackTest {
}
@Test
- public void testRollbackWhitelistedApp_Phase1() throws Exception {
+ public void testRollbackAllowlistedApp_Phase1_Install() throws Exception {
// Remove available rollbacks
String pkgName = getModuleMetadataPackageName();
RollbackUtils.getRollbackManager().expireRollbackForPackage(pkgName);
@@ -301,7 +279,7 @@ public class StagedRollbackTest {
Manifest.permission.INSTALL_PACKAGES,
Manifest.permission.MANAGE_ROLLBACKS);
- // Re-install a whitelisted app with rollbacks enabled
+ // Re-install a allowlisted app with rollbacks enabled
String filePath = InstrumentationRegistry.getInstrumentation().getContext()
.getPackageManager().getPackageInfo(pkgName, 0).applicationInfo.sourceDir;
TestApp app = new TestApp("ModuleMetadata", pkgName, -1, false, new File(filePath));
@@ -310,50 +288,56 @@ public class StagedRollbackTest {
}
@Test
- public void testRollbackWhitelistedApp_Phase2() throws Exception {
+ public void testRollbackAllowlistedApp_Phase2_VerifyInstall() throws Exception {
assertThat(RollbackUtils.getAvailableRollback(getModuleMetadataPackageName())).isNotNull();
}
@Test
- public void testRollbackDataPolicy_Phase1() throws Exception {
- Uninstall.packages(TestApp.A, TestApp.B);
- Install.multi(TestApp.A1, TestApp.B1).commit();
+ public void testRollbackDataPolicy_Phase1_Install() throws Exception {
+ Install.multi(TestApp.A1, TestApp.B1, TestApp.C1).commit();
// Write user data version = 1
InstallUtils.processUserData(TestApp.A);
InstallUtils.processUserData(TestApp.B);
+ InstallUtils.processUserData(TestApp.C);
Install a2 = Install.single(TestApp.A2).setStaged()
.setEnableRollback(PackageManager.RollbackDataPolicy.WIPE);
Install b2 = Install.single(TestApp.B2).setStaged()
.setEnableRollback(PackageManager.RollbackDataPolicy.RESTORE);
- Install.multi(a2, b2).setEnableRollback().setStaged().commit();
+ // The rollback data policy of C2 is specified in the manifest
+ Install c2 = Install.single(TestApp.C2).setStaged().setEnableRollback();
+ Install.multi(a2, b2, c2).setEnableRollback().setStaged().commit();
}
@Test
- public void testRollbackDataPolicy_Phase2() throws Exception {
+ public void testRollbackDataPolicy_Phase2_Rollback() throws Exception {
assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
assertThat(InstallUtils.getInstalledVersion(TestApp.B)).isEqualTo(2);
// Write user data version = 2
InstallUtils.processUserData(TestApp.A);
InstallUtils.processUserData(TestApp.B);
+ InstallUtils.processUserData(TestApp.C);
RollbackInfo info = RollbackUtils.getAvailableRollback(TestApp.A);
RollbackUtils.rollback(info.getRollbackId());
}
@Test
- public void testRollbackDataPolicy_Phase3() throws Exception {
+ public void testRollbackDataPolicy_Phase3_VerifyRollback() throws Exception {
assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
assertThat(InstallUtils.getInstalledVersion(TestApp.B)).isEqualTo(1);
+ assertThat(InstallUtils.getInstalledVersion(TestApp.C)).isEqualTo(1);
// Read user data version from userdata.txt
// A's user data version is -1 for user data is wiped.
// B's user data version is 1 as rollback committed.
+ // C's user data version is -1 for user data is wiped.
assertThat(InstallUtils.getUserDataVersion(TestApp.A)).isEqualTo(-1);
assertThat(InstallUtils.getUserDataVersion(TestApp.B)).isEqualTo(1);
+ assertThat(InstallUtils.getUserDataVersion(TestApp.C)).isEqualTo(-1);
}
@Test
- public void testCleanUp() throws Exception {
+ public void expireRollbacks() throws Exception {
// testNativeWatchdogTriggersRollback will fail if multiple staged sessions are
// committed on a device which doesn't support checkpoint. Let's clean up all rollbacks
// so there is only one rollback to commit when testing native crashes.
@@ -376,7 +360,7 @@ public class StagedRollbackTest {
APK_IN_APEX_TESTAPEX_NAME + "_v2Crashing.apex");
@Test
- public void testRollbackApexWithApk_Phase1() throws Exception {
+ public void testRollbackApexWithApk_Phase1_Install() throws Exception {
assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
InstallUtils.processUserData(TestApp.A);
@@ -386,7 +370,7 @@ public class StagedRollbackTest {
}
@Test
- public void testRollbackApexWithApk_Phase2() throws Exception {
+ public void testRollbackApexWithApk_Phase2_Rollback() throws Exception {
assertThat(InstallUtils.getInstalledVersion(APK_IN_APEX_TESTAPEX_NAME)).isEqualTo(2);
assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
InstallUtils.processUserData(TestApp.A);
@@ -414,7 +398,7 @@ public class StagedRollbackTest {
}
@Test
- public void testRollbackApexWithApk_Phase3() throws Exception {
+ public void testRollbackApexWithApk_Phase3_VerifyRollback() throws Exception {
assertThat(InstallUtils.getInstalledVersion(APK_IN_APEX_TESTAPEX_NAME)).isEqualTo(1);
assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
InstallUtils.processUserData(TestApp.A);
@@ -424,7 +408,7 @@ public class StagedRollbackTest {
* Installs an apex with an apk that can crash.
*/
@Test
- public void testRollbackApexWithApkCrashing_Phase1() throws Exception {
+ public void testRollbackApexWithApkCrashing_Phase1_Install() throws Exception {
assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
int sessionId = Install.single(TEST_APEX_WITH_APK_V2_CRASHING).setStaged()
.setEnableRollback().commit();
@@ -435,7 +419,7 @@ public class StagedRollbackTest {
* Verifies rollback has been enabled successfully. Then makes TestApp.A crash.
*/
@Test
- public void testRollbackApexWithApkCrashing_Phase2() throws Exception {
+ public void testRollbackApexWithApkCrashing_Phase2_Crash() throws Exception {
assertThat(InstallUtils.getInstalledVersion(APK_IN_APEX_TESTAPEX_NAME)).isEqualTo(2);
assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
@@ -445,25 +429,27 @@ public class StagedRollbackTest {
Rollback.from(TEST_APEX_WITH_APK_V2).to(TEST_APEX_WITH_APK_V1),
Rollback.from(TestApp.A, 0).to(TestApp.A1));
- // Crash TestApp.A PackageWatchdog#TRIGGER_FAILURE_COUNT times to trigger rollback
- RollbackUtils.sendCrashBroadcast(TestApp.A, 5);
+ // Crash TestApp.A PackageWatchdog#TRIGGER_FAILURE_COUNT-1 times
+ RollbackUtils.sendCrashBroadcast(TestApp.A, 4);
+ // Sleep for a while to make sure we don't trigger rollback
+ Thread.sleep(TimeUnit.SECONDS.toMillis(30));
}
@Test
- public void testRollbackApexWithApkCrashing_Phase3() throws Exception {
+ public void testRollbackApexWithApkCrashing_Phase3_VerifyRollback() throws Exception {
assertThat(InstallUtils.getInstalledVersion(APK_IN_APEX_TESTAPEX_NAME)).isEqualTo(1);
assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
}
@Test
- public void testRollbackApexDataDirectories_Phase1() throws Exception {
+ public void testRollbackApexDataDirectories_Phase1_Install() throws Exception {
int sessionId = Install.single(TEST_APEX_WITH_APK_V2).setStaged().setEnableRollback()
.commit();
InstallUtils.waitForSessionReady(sessionId);
}
@Test
- public void testRollbackApexDataDirectories_Phase2() throws Exception {
+ public void testRollbackApexDataDirectories_Phase2_Rollback() throws Exception {
RollbackInfo available = RollbackUtils.getAvailableRollback(APK_IN_APEX_TESTAPEX_NAME);
RollbackUtils.rollback(available.getRollbackId(), TEST_APEX_WITH_APK_V2);
@@ -475,6 +461,26 @@ public class StagedRollbackTest {
}
@Test
+ public void testRollbackApkDataDirectories_Phase1_InstallV1() throws Exception {
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(-1);
+ Install.single(TestApp.A1).commit();
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
+ }
+
+ @Test
+ public void testRollbackApkDataDirectories_Phase2_InstallV2() throws Exception {
+ Install.single(TestApp.A2).setStaged().setEnableRollback().commit();
+ }
+
+ @Test
+ public void testRollbackApkDataDirectories_Phase3_Rollback() throws Exception {
+ RollbackInfo available = RollbackUtils.getAvailableRollback(TestApp.A);
+ RollbackUtils.rollback(available.getRollbackId(), TestApp.A2);
+ RollbackInfo committed = RollbackUtils.getCommittedRollbackById(available.getRollbackId());
+ InstallUtils.waitForSessionReady(committed.getCommittedSessionId());
+ }
+
+ @Test
public void isCheckpointSupported() {
Context context = InstrumentationRegistry.getInstrumentation().getContext();
StorageManager sm = (StorageManager) context.getSystemService(Context.STORAGE_SERVICE);
@@ -482,6 +488,45 @@ public class StagedRollbackTest {
}
@Test
+ public void testWatchdogMonitorsAcrossReboots_Phase1_Install() throws Exception {
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(-1);
+ Install.single(TestApp.A1).commit();
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
+ InstallUtils.processUserData(TestApp.A);
+
+ Install.single(TestApp.ACrashing2).setEnableRollback().setStaged().commit();
+ }
+
+ @Test
+ public void testWatchdogMonitorsAcrossReboots_Phase2_VerifyInstall() throws Exception {
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
+
+ // Trigger rollback of test app.
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ROLLBACK,
+ PROPERTY_WATCHDOG_TRIGGER_FAILURE_COUNT,
+ Integer.toString(5), false);
+
+ // The final crash that causes rollback will come from the host side.
+ RollbackUtils.sendCrashBroadcast(TestApp.A, 4);
+ }
+
+ @Test
+ public void testWatchdogMonitorsAcrossReboots_Phase3_VerifyRollback() {
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
+ InstallUtils.processUserData(TestApp.A);
+
+ RollbackManager rm = RollbackUtils.getRollbackManager();
+ RollbackInfo rollback = getUniqueRollbackInfoForPackage(
+ rm.getRecentlyCommittedRollbacks(), TestApp.A);
+ assertThat(rollback).isNotNull();
+ assertThat(rollback).packagesContainsExactly(
+ Rollback.from(TestApp.A2).to(TestApp.A1));
+ assertThat(rollback).causePackagesContainsExactly(TestApp.ACrashing2);
+ assertThat(rollback).isStaged();
+ assertThat(rollback.getCommittedSessionId()).isNotEqualTo(-1);
+ }
+
+ @Test
public void testExpireSession_Phase1_Install() throws Exception {
assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(-1);
Install.single(TestApp.A1).commit();
diff --git a/tests/RollbackTest/StagedRollbackTest.xml b/tests/RollbackTest/StagedRollbackTest.xml
index 83fef8e0a04b..0ca4dafae59d 100644
--- a/tests/RollbackTest/StagedRollbackTest.xml
+++ b/tests/RollbackTest/StagedRollbackTest.xml
@@ -24,6 +24,8 @@
<option name="run-command" value="pm uninstall com.android.cts.install.lib.testapp.B" />
<option name="teardown-command" value="pm uninstall com.android.cts.install.lib.testapp.A" />
<option name="teardown-command" value="pm uninstall com.android.cts.install.lib.testapp.B" />
+ <option name="run-command" value="setprop persist.rollback.is_test 1" />
+ <option name="teardown-command" value="setprop persist.rollback.is_test 0" />
</target_preparer>
<test class="com.android.tradefed.testtype.HostTest" >
<option name="class" value="com.android.tests.rollback.host.StagedRollbackTest" />
diff --git a/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java b/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
index bd6b81374168..1aa5c249ff18 100644
--- a/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
+++ b/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
@@ -16,15 +16,16 @@
package com.android.tests.rollback.host;
-import static com.android.tests.rollback.host.WatchdogEventLogger.watchdogEventOccurred;
+import static com.android.tests.rollback.host.WatchdogEventLogger.Subject.assertThat;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.junit.Assume.assumeTrue;
import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
+import com.android.ddmlib.Log;
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.device.IFileEntry;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
@@ -53,6 +54,7 @@ import java.util.stream.Collectors;
*/
@RunWith(DeviceJUnit4ClassRunner.class)
public class StagedRollbackTest extends BaseHostJUnit4Test {
+ private static final String TAG = "StagedRollbackTest";
private static final int NATIVE_CRASHES_THRESHOLD = 5;
/**
@@ -62,9 +64,9 @@ public class StagedRollbackTest extends BaseHostJUnit4Test {
* For example, <code>runPhase("testApkOnlyEnableRollback");</code>
*/
private void runPhase(String phase) throws Exception {
- assertTrue(runDeviceTests("com.android.tests.rollback",
+ assertThat(runDeviceTests("com.android.tests.rollback",
"com.android.tests.rollback.StagedRollbackTest",
- phase));
+ phase)).isTrue();
}
private static final String APK_IN_APEX_TESTAPEX_NAME = "com.android.apex.apkrollback.test";
@@ -97,14 +99,20 @@ public class StagedRollbackTest extends BaseHostJUnit4Test {
public void setUp() throws Exception {
deleteFiles("/system/apex/" + APK_IN_APEX_TESTAPEX_NAME + "*.apex",
"/data/apex/active/" + APK_IN_APEX_TESTAPEX_NAME + "*.apex");
- runPhase("testCleanUp");
+ runPhase("expireRollbacks");
mLogger.start(getDevice());
+ getDevice().uninstallPackage("com.android.cts.install.lib.testapp.A");
+ getDevice().uninstallPackage("com.android.cts.install.lib.testapp.B");
+ getDevice().uninstallPackage("com.android.cts.install.lib.testapp.C");
}
@After
public void tearDown() throws Exception {
+ getDevice().uninstallPackage("com.android.cts.install.lib.testapp.A");
+ getDevice().uninstallPackage("com.android.cts.install.lib.testapp.B");
+ getDevice().uninstallPackage("com.android.cts.install.lib.testapp.C");
mLogger.stop();
- runPhase("testCleanUp");
+ runPhase("expireRollbacks");
deleteFiles("/system/apex/" + APK_IN_APEX_TESTAPEX_NAME + "*.apex",
"/data/apex/active/" + APK_IN_APEX_TESTAPEX_NAME + "*.apex",
apexDataDirDeSys(APK_IN_APEX_TESTAPEX_NAME) + "*",
@@ -126,50 +134,55 @@ public class StagedRollbackTest extends BaseHostJUnit4Test {
}
if (found) {
- if (!getDevice().isAdbRoot()) {
+ try {
getDevice().enableAdbRoot();
- }
- getDevice().remountSystemWritable();
- for (String file : files) {
- getDevice().executeShellCommand("rm -rf " + file);
+ getDevice().remountSystemWritable();
+ for (String file : files) {
+ getDevice().executeShellCommand("rm -rf " + file);
+ }
+ } finally {
+ getDevice().disableAdbRoot();
}
getDevice().reboot();
}
}
+ private void waitForDeviceNotAvailable(long timeout, TimeUnit unit) {
+ assertWithMessage("waitForDeviceNotAvailable() timed out in %s %s", timeout, unit)
+ .that(getDevice().waitForDeviceNotAvailable(unit.toMillis(timeout))).isTrue();
+ }
+
/**
* Tests watchdog triggered staged rollbacks involving only apks.
*/
@Test
public void testBadApkOnly() throws Exception {
- runPhase("testBadApkOnly_Phase1");
+ runPhase("testBadApkOnly_Phase1_Install");
getDevice().reboot();
- runPhase("testBadApkOnly_Phase2");
+ runPhase("testBadApkOnly_Phase2_VerifyInstall");
- // Trigger rollback and wait for reboot to happen
- runPhase("testBadApkOnly_Phase3");
- assertTrue(getDevice().waitForDeviceNotAvailable(TimeUnit.MINUTES.toMillis(2)));
+ // Launch the app to crash to trigger rollback
+ startActivity(TESTAPP_A);
+ // Wait for reboot to happen
+ waitForDeviceNotAvailable(2, TimeUnit.MINUTES);
getDevice().waitForDeviceAvailable();
- runPhase("testBadApkOnly_Phase4");
+ runPhase("testBadApkOnly_Phase3_VerifyRollback");
- List<String> watchdogEvents = mLogger.getWatchdogLoggingEvents();
- assertTrue(watchdogEventOccurred(watchdogEvents, ROLLBACK_INITIATE, null,
- REASON_APP_CRASH, TESTAPP_A));
- assertTrue(watchdogEventOccurred(watchdogEvents, ROLLBACK_BOOT_TRIGGERED, null,
- null, null));
- assertTrue(watchdogEventOccurred(watchdogEvents, ROLLBACK_SUCCESS, null, null, null));
+ assertThat(mLogger).eventOccurred(ROLLBACK_INITIATE, null, REASON_APP_CRASH, TESTAPP_A);
+ assertThat(mLogger).eventOccurred(ROLLBACK_BOOT_TRIGGERED, null, null, null);
+ assertThat(mLogger).eventOccurred(ROLLBACK_SUCCESS, null, null, null);
}
@Test
public void testNativeWatchdogTriggersRollback() throws Exception {
- runPhase("testNativeWatchdogTriggersRollback_Phase1");
+ runPhase("testNativeWatchdogTriggersRollback_Phase1_Install");
// Reboot device to activate staged package
getDevice().reboot();
- runPhase("testNativeWatchdogTriggersRollback_Phase2");
+ runPhase("testNativeWatchdogTriggersRollback_Phase2_VerifyInstall");
// crash system_server enough times to trigger a rollback
crashProcess("system_server", NATIVE_CRASHES_THRESHOLD);
@@ -182,18 +195,15 @@ public class StagedRollbackTest extends BaseHostJUnit4Test {
// 3. Staged rollback session becomes ready.
// 4. Device actually reboots.
// So we give a generous timeout here.
- assertTrue(getDevice().waitForDeviceNotAvailable(TimeUnit.MINUTES.toMillis(5)));
+ waitForDeviceNotAvailable(5, TimeUnit.MINUTES);
getDevice().waitForDeviceAvailable();
// verify rollback committed
- runPhase("testNativeWatchdogTriggersRollback_Phase3");
+ runPhase("testNativeWatchdogTriggersRollback_Phase3_VerifyRollback");
- List<String> watchdogEvents = mLogger.getWatchdogLoggingEvents();
- assertTrue(watchdogEventOccurred(watchdogEvents, ROLLBACK_INITIATE, null,
- REASON_NATIVE_CRASH, null));
- assertTrue(watchdogEventOccurred(watchdogEvents, ROLLBACK_BOOT_TRIGGERED, null,
- null, null));
- assertTrue(watchdogEventOccurred(watchdogEvents, ROLLBACK_SUCCESS, null, null, null));
+ assertThat(mLogger).eventOccurred(ROLLBACK_INITIATE, null, REASON_NATIVE_CRASH, null);
+ assertThat(mLogger).eventOccurred(ROLLBACK_BOOT_TRIGGERED, null, null, null);
+ assertThat(mLogger).eventOccurred(ROLLBACK_SUCCESS, null, null, null);
}
@Test
@@ -202,15 +212,15 @@ public class StagedRollbackTest extends BaseHostJUnit4Test {
assumeTrue(isCheckpointSupported());
// Install a package with rollback enabled.
- runPhase("testNativeWatchdogTriggersRollbackForAll_Phase1");
+ runPhase("testNativeWatchdogTriggersRollbackForAll_Phase1_InstallA");
getDevice().reboot();
// Once previous staged install is applied, install another package
- runPhase("testNativeWatchdogTriggersRollbackForAll_Phase2");
+ runPhase("testNativeWatchdogTriggersRollbackForAll_Phase2_InstallB");
getDevice().reboot();
// Verify the new staged install has also been applied successfully.
- runPhase("testNativeWatchdogTriggersRollbackForAll_Phase3");
+ runPhase("testNativeWatchdogTriggersRollbackForAll_Phase3_VerifyInstall");
// crash system_server enough times to trigger a rollback
crashProcess("system_server", NATIVE_CRASHES_THRESHOLD);
@@ -223,18 +233,15 @@ public class StagedRollbackTest extends BaseHostJUnit4Test {
// 3. Staged rollback session becomes ready.
// 4. Device actually reboots.
// So we give a generous timeout here.
- assertTrue(getDevice().waitForDeviceNotAvailable(TimeUnit.MINUTES.toMillis(5)));
+ waitForDeviceNotAvailable(5, TimeUnit.MINUTES);
getDevice().waitForDeviceAvailable();
// verify all available rollbacks have been committed
- runPhase("testNativeWatchdogTriggersRollbackForAll_Phase4");
+ runPhase("testNativeWatchdogTriggersRollbackForAll_Phase4_VerifyRollback");
- List<String> watchdogEvents = mLogger.getWatchdogLoggingEvents();
- assertTrue(watchdogEventOccurred(watchdogEvents, ROLLBACK_INITIATE, null,
- REASON_NATIVE_CRASH, null));
- assertTrue(watchdogEventOccurred(watchdogEvents, ROLLBACK_BOOT_TRIGGERED, null,
- null, null));
- assertTrue(watchdogEventOccurred(watchdogEvents, ROLLBACK_SUCCESS, null, null, null));
+ assertThat(mLogger).eventOccurred(ROLLBACK_INITIATE, null, REASON_NATIVE_CRASH, null);
+ assertThat(mLogger).eventOccurred(ROLLBACK_BOOT_TRIGGERED, null, null, null);
+ assertThat(mLogger).eventOccurred(ROLLBACK_SUCCESS, null, null, null);
}
/**
@@ -242,31 +249,41 @@ public class StagedRollbackTest extends BaseHostJUnit4Test {
*/
@Test
public void testPreviouslyAbandonedRollbacks() throws Exception {
- runPhase("testPreviouslyAbandonedRollbacks_Phase1");
+ runPhase("testPreviouslyAbandonedRollbacks_Phase1_InstallAndAbandon");
getDevice().reboot();
- runPhase("testPreviouslyAbandonedRollbacks_Phase2");
+ runPhase("testPreviouslyAbandonedRollbacks_Phase2_Rollback");
getDevice().reboot();
- runPhase("testPreviouslyAbandonedRollbacks_Phase3");
+ runPhase("testPreviouslyAbandonedRollbacks_Phase3_VerifyRollback");
}
/**
- * Tests we can enable rollback for a whitelisted app.
+ * Tests we can enable rollback for a allowlisted app.
*/
@Test
- public void testRollbackWhitelistedApp() throws Exception {
+ public void testRollbackAllowlistedApp() throws Exception {
assumeTrue(hasMainlineModule());
- runPhase("testRollbackWhitelistedApp_Phase1");
+ runPhase("testRollbackAllowlistedApp_Phase1_Install");
getDevice().reboot();
- runPhase("testRollbackWhitelistedApp_Phase2");
+ runPhase("testRollbackAllowlistedApp_Phase2_VerifyInstall");
}
@Test
public void testRollbackDataPolicy() throws Exception {
- runPhase("testRollbackDataPolicy_Phase1");
+ List<String> before = getSnapshotDirectories("/data/misc_ce/0/rollback");
+
+ runPhase("testRollbackDataPolicy_Phase1_Install");
getDevice().reboot();
- runPhase("testRollbackDataPolicy_Phase2");
+ runPhase("testRollbackDataPolicy_Phase2_Rollback");
getDevice().reboot();
- runPhase("testRollbackDataPolicy_Phase3");
+ runPhase("testRollbackDataPolicy_Phase3_VerifyRollback");
+
+ // Verify snapshots are deleted after restoration
+ List<String> after = getSnapshotDirectories("/data/misc_ce/0/rollback");
+ // Only check directories newly created during the test
+ after.removeAll(before);
+ // There should be only one /data/misc_ce/0/rollback/<rollbackId> created during test
+ assertThat(after).hasSize(1);
+ assertDirectoryIsEmpty(after.get(0));
}
/**
@@ -274,13 +291,12 @@ public class StagedRollbackTest extends BaseHostJUnit4Test {
*/
@Test
public void testRollbackApexWithApk() throws Exception {
- getDevice().uninstallPackage("com.android.cts.install.lib.testapp.A");
pushTestApex();
- runPhase("testRollbackApexWithApk_Phase1");
+ runPhase("testRollbackApexWithApk_Phase1_Install");
getDevice().reboot();
- runPhase("testRollbackApexWithApk_Phase2");
+ runPhase("testRollbackApexWithApk_Phase2_Rollback");
getDevice().reboot();
- runPhase("testRollbackApexWithApk_Phase3");
+ runPhase("testRollbackApexWithApk_Phase3_VerifyRollback");
}
/**
@@ -288,26 +304,24 @@ public class StagedRollbackTest extends BaseHostJUnit4Test {
*/
@Test
public void testRollbackApexWithApkCrashing() throws Exception {
- getDevice().uninstallPackage("com.android.cts.install.lib.testapp.A");
pushTestApex();
// Install an apex with apk that crashes
- runPhase("testRollbackApexWithApkCrashing_Phase1");
+ runPhase("testRollbackApexWithApkCrashing_Phase1_Install");
getDevice().reboot();
// Verify apex was installed and then crash the apk
- runPhase("testRollbackApexWithApkCrashing_Phase2");
- // Wait for crash to trigger rollback
- assertTrue(getDevice().waitForDeviceNotAvailable(TimeUnit.MINUTES.toMillis(5)));
+ runPhase("testRollbackApexWithApkCrashing_Phase2_Crash");
+ // Launch the app to crash to trigger rollback
+ startActivity(TESTAPP_A);
+ // Wait for reboot to happen
+ waitForDeviceNotAvailable(2, TimeUnit.MINUTES);
getDevice().waitForDeviceAvailable();
// Verify rollback occurred due to crash of apk-in-apex
- runPhase("testRollbackApexWithApkCrashing_Phase3");
+ runPhase("testRollbackApexWithApkCrashing_Phase3_VerifyRollback");
- List<String> watchdogEvents = mLogger.getWatchdogLoggingEvents();
- assertTrue(watchdogEventOccurred(watchdogEvents, ROLLBACK_INITIATE, null,
- REASON_APP_CRASH, TESTAPP_A));
- assertTrue(watchdogEventOccurred(watchdogEvents, ROLLBACK_BOOT_TRIGGERED, null,
- null, null));
- assertTrue(watchdogEventOccurred(watchdogEvents, ROLLBACK_SUCCESS, null, null, null));
+ assertThat(mLogger).eventOccurred(ROLLBACK_INITIATE, null, REASON_APP_CRASH, TESTAPP_A);
+ assertThat(mLogger).eventOccurred(ROLLBACK_BOOT_TRIGGERED, null, null, null);
+ assertThat(mLogger).eventOccurred(ROLLBACK_SUCCESS, null, null, null);
}
/**
@@ -322,37 +336,45 @@ public class StagedRollbackTest extends BaseHostJUnit4Test {
String oldFilePath1 = apexDataDirDeSys(APK_IN_APEX_TESTAPEX_NAME) + "/" + TEST_FILENAME_1;
String oldFilePath2 =
apexDataDirDeSys(APK_IN_APEX_TESTAPEX_NAME) + TEST_SUBDIR + TEST_FILENAME_2;
- assertTrue(getDevice().pushString(TEST_STRING_1, oldFilePath1));
- assertTrue(getDevice().pushString(TEST_STRING_2, oldFilePath2));
+ runAsRoot(() -> {
+ pushString(TEST_STRING_1, oldFilePath1);
+ pushString(TEST_STRING_2, oldFilePath2);
+ });
// Install new version of the APEX with rollback enabled
- runPhase("testRollbackApexDataDirectories_Phase1");
+ runPhase("testRollbackApexDataDirectories_Phase1_Install");
getDevice().reboot();
// Replace files in data directory
- getDevice().deleteFile(oldFilePath1);
- getDevice().deleteFile(oldFilePath2);
String newFilePath3 = apexDataDirDeSys(APK_IN_APEX_TESTAPEX_NAME) + "/" + TEST_FILENAME_3;
String newFilePath4 =
apexDataDirDeSys(APK_IN_APEX_TESTAPEX_NAME) + TEST_SUBDIR + TEST_FILENAME_4;
- assertTrue(getDevice().pushString(TEST_STRING_3, newFilePath3));
- assertTrue(getDevice().pushString(TEST_STRING_4, newFilePath4));
+ runAsRoot(() -> {
+ getDevice().deleteFile(oldFilePath1);
+ getDevice().deleteFile(oldFilePath2);
+ pushString(TEST_STRING_3, newFilePath3);
+ pushString(TEST_STRING_4, newFilePath4);
+ });
// Roll back the APEX
- runPhase("testRollbackApexDataDirectories_Phase2");
+ runPhase("testRollbackApexDataDirectories_Phase2_Rollback");
getDevice().reboot();
// Verify that old files have been restored and new files are gone
- assertEquals(TEST_STRING_1, getDevice().pullFileContents(oldFilePath1));
- assertEquals(TEST_STRING_2, getDevice().pullFileContents(oldFilePath2));
- assertNull(getDevice().pullFile(newFilePath3));
- assertNull(getDevice().pullFile(newFilePath4));
+ runAsRoot(() -> {
+ assertFileContents(TEST_STRING_1, oldFilePath1);
+ assertFileContents(TEST_STRING_2, oldFilePath2);
+ assertFileNotExists(newFilePath3);
+ assertFileNotExists(newFilePath4);
+ });
// Verify snapshots are deleted after restoration
List<String> after = getSnapshotDirectories("/data/misc/apexrollback");
// Only check directories newly created during the test
after.removeAll(before);
- after.forEach(dir -> assertDirectoryIsEmpty(dir));
+ // There should be only one /data/misc/apexrollback/<rollbackId> created during test
+ assertThat(after).hasSize(1);
+ assertDirectoryIsEmpty(after.get(0));
}
/**
@@ -368,38 +390,46 @@ public class StagedRollbackTest extends BaseHostJUnit4Test {
APK_IN_APEX_TESTAPEX_NAME, 0) + "/" + TEST_FILENAME_1;
String oldFilePath2 =
apexDataDirDeUser(APK_IN_APEX_TESTAPEX_NAME, 0) + TEST_SUBDIR + TEST_FILENAME_2;
- assertTrue(getDevice().pushString(TEST_STRING_1, oldFilePath1));
- assertTrue(getDevice().pushString(TEST_STRING_2, oldFilePath2));
+ runAsRoot(() -> {
+ pushString(TEST_STRING_1, oldFilePath1);
+ pushString(TEST_STRING_2, oldFilePath2);
+ });
// Install new version of the APEX with rollback enabled
- runPhase("testRollbackApexDataDirectories_Phase1");
+ runPhase("testRollbackApexDataDirectories_Phase1_Install");
getDevice().reboot();
// Replace files in data directory
- getDevice().deleteFile(oldFilePath1);
- getDevice().deleteFile(oldFilePath2);
String newFilePath3 =
apexDataDirDeUser(APK_IN_APEX_TESTAPEX_NAME, 0) + "/" + TEST_FILENAME_3;
String newFilePath4 =
apexDataDirDeUser(APK_IN_APEX_TESTAPEX_NAME, 0) + TEST_SUBDIR + TEST_FILENAME_4;
- assertTrue(getDevice().pushString(TEST_STRING_3, newFilePath3));
- assertTrue(getDevice().pushString(TEST_STRING_4, newFilePath4));
+ runAsRoot(() -> {
+ getDevice().deleteFile(oldFilePath1);
+ getDevice().deleteFile(oldFilePath2);
+ pushString(TEST_STRING_3, newFilePath3);
+ pushString(TEST_STRING_4, newFilePath4);
+ });
// Roll back the APEX
- runPhase("testRollbackApexDataDirectories_Phase2");
+ runPhase("testRollbackApexDataDirectories_Phase2_Rollback");
getDevice().reboot();
// Verify that old files have been restored and new files are gone
- assertEquals(TEST_STRING_1, getDevice().pullFileContents(oldFilePath1));
- assertEquals(TEST_STRING_2, getDevice().pullFileContents(oldFilePath2));
- assertNull(getDevice().pullFile(newFilePath3));
- assertNull(getDevice().pullFile(newFilePath4));
+ runAsRoot(() -> {
+ assertFileContents(TEST_STRING_1, oldFilePath1);
+ assertFileContents(TEST_STRING_2, oldFilePath2);
+ assertFileNotExists(newFilePath3);
+ assertFileNotExists(newFilePath4);
+ });
// Verify snapshots are deleted after restoration
List<String> after = getSnapshotDirectories("/data/misc_de/0/apexrollback");
// Only check directories newly created during the test
after.removeAll(before);
- after.forEach(dir -> assertDirectoryIsEmpty(dir));
+ // There should be only one /data/misc_de/0/apexrollback/<rollbackId> created during test
+ assertThat(after).hasSize(1);
+ assertDirectoryIsEmpty(after.get(0));
}
/**
@@ -414,37 +444,144 @@ public class StagedRollbackTest extends BaseHostJUnit4Test {
String oldFilePath1 = apexDataDirCe(APK_IN_APEX_TESTAPEX_NAME, 0) + "/" + TEST_FILENAME_1;
String oldFilePath2 =
apexDataDirCe(APK_IN_APEX_TESTAPEX_NAME, 0) + TEST_SUBDIR + TEST_FILENAME_2;
- assertTrue(getDevice().pushString(TEST_STRING_1, oldFilePath1));
- assertTrue(getDevice().pushString(TEST_STRING_2, oldFilePath2));
+ runAsRoot(() -> {
+ pushString(TEST_STRING_1, oldFilePath1);
+ pushString(TEST_STRING_2, oldFilePath2);
+ });
// Install new version of the APEX with rollback enabled
- runPhase("testRollbackApexDataDirectories_Phase1");
+ runPhase("testRollbackApexDataDirectories_Phase1_Install");
getDevice().reboot();
// Replace files in data directory
- getDevice().deleteFile(oldFilePath1);
- getDevice().deleteFile(oldFilePath2);
String newFilePath3 = apexDataDirCe(APK_IN_APEX_TESTAPEX_NAME, 0) + "/" + TEST_FILENAME_3;
String newFilePath4 =
apexDataDirCe(APK_IN_APEX_TESTAPEX_NAME, 0) + TEST_SUBDIR + TEST_FILENAME_4;
- assertTrue(getDevice().pushString(TEST_STRING_3, newFilePath3));
- assertTrue(getDevice().pushString(TEST_STRING_4, newFilePath4));
+ runAsRoot(() -> {
+ getDevice().deleteFile(oldFilePath1);
+ getDevice().deleteFile(oldFilePath2);
+ pushString(TEST_STRING_3, newFilePath3);
+ pushString(TEST_STRING_4, newFilePath4);
+ });
// Roll back the APEX
- runPhase("testRollbackApexDataDirectories_Phase2");
+ runPhase("testRollbackApexDataDirectories_Phase2_Rollback");
getDevice().reboot();
// Verify that old files have been restored and new files are gone
- assertEquals(TEST_STRING_1, getDevice().pullFileContents(oldFilePath1));
- assertEquals(TEST_STRING_2, getDevice().pullFileContents(oldFilePath2));
- assertNull(getDevice().pullFile(newFilePath3));
- assertNull(getDevice().pullFile(newFilePath4));
+ runAsRoot(() -> {
+ assertFileContents(TEST_STRING_1, oldFilePath1);
+ assertFileContents(TEST_STRING_2, oldFilePath2);
+ assertFileNotExists(newFilePath3);
+ assertFileNotExists(newFilePath4);
+ });
// Verify snapshots are deleted after restoration
List<String> after = getSnapshotDirectories("/data/misc_ce/0/apexrollback");
// Only check directories newly created during the test
after.removeAll(before);
- after.forEach(dir -> assertDirectoryIsEmpty(dir));
+ // There should be only one /data/misc_ce/0/apexrollback/<rollbackId> created during test
+ assertThat(after).hasSize(1);
+ assertDirectoryIsEmpty(after.get(0));
+ }
+
+ /**
+ * Tests that data in DE apk data directory is restored when apk is rolled back.
+ */
+ @Test
+ public void testRollbackApkDataDirectories_De() throws Exception {
+ // Install version 1 of TESTAPP_A
+ runPhase("testRollbackApkDataDirectories_Phase1_InstallV1");
+
+ // Push files to apk data directory
+ String oldFilePath1 = apkDataDirDe(TESTAPP_A, 0) + "/" + TEST_FILENAME_1;
+ String oldFilePath2 = apkDataDirDe(TESTAPP_A, 0) + TEST_SUBDIR + TEST_FILENAME_2;
+ runAsRoot(() -> {
+ pushString(TEST_STRING_1, oldFilePath1);
+ pushString(TEST_STRING_2, oldFilePath2);
+ });
+
+ // Install version 2 of TESTAPP_A with rollback enabled
+ runPhase("testRollbackApkDataDirectories_Phase2_InstallV2");
+ getDevice().reboot();
+
+ // Replace files in data directory
+ String newFilePath3 = apkDataDirDe(TESTAPP_A, 0) + "/" + TEST_FILENAME_3;
+ String newFilePath4 = apkDataDirDe(TESTAPP_A, 0) + TEST_SUBDIR + TEST_FILENAME_4;
+ runAsRoot(() -> {
+ getDevice().deleteFile(oldFilePath1);
+ getDevice().deleteFile(oldFilePath2);
+ pushString(TEST_STRING_3, newFilePath3);
+ pushString(TEST_STRING_4, newFilePath4);
+ });
+
+ // Roll back the APK
+ runPhase("testRollbackApkDataDirectories_Phase3_Rollback");
+ getDevice().reboot();
+
+ // Verify that old files have been restored and new files are gone
+ runAsRoot(() -> {
+ assertFileContents(TEST_STRING_1, oldFilePath1);
+ assertFileContents(TEST_STRING_2, oldFilePath2);
+ assertFileNotExists(newFilePath3);
+ assertFileNotExists(newFilePath4);
+ });
+ }
+
+ @Test
+ public void testExpireApexRollback() throws Exception {
+ List<String> before = getSnapshotDirectories("/data/misc_ce/0/apexrollback");
+ pushTestApex();
+
+ // Push files to apex data directory
+ String oldFilePath1 = apexDataDirCe(APK_IN_APEX_TESTAPEX_NAME, 0) + "/" + TEST_FILENAME_1;
+ String oldFilePath2 =
+ apexDataDirCe(APK_IN_APEX_TESTAPEX_NAME, 0) + TEST_SUBDIR + TEST_FILENAME_2;
+ runAsRoot(() -> {
+ pushString(TEST_STRING_1, oldFilePath1);
+ pushString(TEST_STRING_2, oldFilePath2);
+ });
+
+ // Install new version of the APEX with rollback enabled
+ runPhase("testRollbackApexDataDirectories_Phase1_Install");
+ getDevice().reboot();
+
+ List<String> after = getSnapshotDirectories("/data/misc_ce/0/apexrollback");
+ // Only check directories newly created during the test
+ after.removeAll(before);
+ // There should be only one /data/misc_ce/0/apexrollback/<rollbackId> created during test
+ assertThat(after).hasSize(1);
+ // Expire all rollbacks and check CE snapshot directories are deleted
+ runPhase("expireRollbacks");
+ runAsRoot(() -> {
+ for (String dir : after) {
+ assertFileNotExists(dir);
+ }
+ });
+ }
+
+ /**
+ * Tests that packages are monitored across multiple reboots.
+ */
+ @Test
+ public void testWatchdogMonitorsAcrossReboots() throws Exception {
+ runPhase("testWatchdogMonitorsAcrossReboots_Phase1_Install");
+
+ // The first reboot will make the rollback available.
+ // Information about which packages are monitored will be persisted to a file before the
+ // second reboot, and read from disk after the second reboot.
+ getDevice().reboot();
+ getDevice().reboot();
+
+ runPhase("testWatchdogMonitorsAcrossReboots_Phase2_VerifyInstall");
+
+ // Launch the app to crash to trigger rollback
+ startActivity(TESTAPP_A);
+ // Wait for reboot to happen
+ waitForDeviceNotAvailable(2, TimeUnit.MINUTES);
+ getDevice().waitForDeviceAvailable();
+
+ runPhase("testWatchdogMonitorsAcrossReboots_Phase3_VerifyRollback");
}
/**
@@ -472,14 +609,33 @@ public class StagedRollbackTest extends BaseHostJUnit4Test {
CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(getBuild());
final String fileName = APK_IN_APEX_TESTAPEX_NAME + "_v1.apex";
final File apex = buildHelper.getTestFile(fileName);
- if (!getDevice().isAdbRoot()) {
+ try {
getDevice().enableAdbRoot();
+ getDevice().remountSystemWritable();
+ assertThat(getDevice().pushFile(apex, "/system/apex/" + fileName)).isTrue();
+ } finally {
+ getDevice().disableAdbRoot();
}
- getDevice().remountSystemWritable();
- assertTrue(getDevice().pushFile(apex, "/system/apex/" + fileName));
getDevice().reboot();
}
+ private void pushString(String contents, String path) throws Exception {
+ assertWithMessage("Failed to push file to device, content=%s path=%s", contents, path)
+ .that(getDevice().pushString(contents, path)).isTrue();
+ }
+
+ private void assertFileContents(String expectedContents, String path) throws Exception {
+ String actualContents = getDevice().pullFileContents(path);
+ assertWithMessage("Failed to retrieve file=%s", path).that(actualContents).isNotNull();
+ assertWithMessage("Mismatched file contents, path=%s", path)
+ .that(actualContents).isEqualTo(expectedContents);
+ }
+
+ private void assertFileNotExists(String path) throws Exception {
+ assertWithMessage("File shouldn't exist, path=%s", path)
+ .that(getDevice().getFileEntry(path)).isNull();
+ }
+
private static String apexDataDirDeSys(String apexName) {
return String.format("/data/misc/apexdata/%s", apexName);
}
@@ -492,28 +648,49 @@ public class StagedRollbackTest extends BaseHostJUnit4Test {
return String.format("/data/misc_ce/%d/apexdata/%s", userId, apexName);
}
- private List<String> getSnapshotDirectories(String baseDir) {
+ private static String apkDataDirDe(String apexName, int userId) {
+ return String.format("/data/user_de/%d/%s", userId, apexName);
+ }
+
+ private List<String> getSnapshotDirectories(String baseDir) throws Exception {
try {
- return getDevice().getFileEntry(baseDir).getChildren(false)
+ getDevice().enableAdbRoot();
+ IFileEntry f = getDevice().getFileEntry(baseDir);
+ if (f == null) {
+ Log.d(TAG, "baseDir doesn't exist: " + baseDir);
+ return Collections.EMPTY_LIST;
+ }
+ List<String> list = f.getChildren(false)
.stream().filter(entry -> entry.getName().matches("\\d+(-prerestore)?"))
.map(entry -> entry.getFullPath())
.collect(Collectors.toList());
- } catch (Exception e) {
- // Return an empty list if any error
- return Collections.EMPTY_LIST;
+ Log.d(TAG, "getSnapshotDirectories=" + list);
+ return list;
+ } finally {
+ getDevice().disableAdbRoot();
}
}
- private void assertDirectoryIsEmpty(String path) {
+ private void assertDirectoryIsEmpty(String path) throws Exception {
try {
+ getDevice().enableAdbRoot();
IFileEntry file = getDevice().getFileEntry(path);
- assertTrue("Not a directory: " + path, file.isDirectory());
- assertTrue("Directory not empty: " + path, file.getChildren(false).isEmpty());
+ assertWithMessage("Not a directory: " + path).that(file.isDirectory()).isTrue();
+ assertWithMessage("Directory not empty: " + path)
+ .that(file.getChildren(false)).isEmpty();
} catch (DeviceNotAvailableException e) {
fail("Can't access directory: " + path);
+ } finally {
+ getDevice().disableAdbRoot();
}
}
+ private void startActivity(String packageName) throws Exception {
+ String cmd = "am start -S -a android.intent.action.MAIN "
+ + "-c android.intent.category.LAUNCHER " + packageName;
+ getDevice().executeShellCommand(cmd);
+ }
+
private void crashProcess(String processName, int numberOfCrashes) throws Exception {
String pid = "";
String lastPid = "invalid";
diff --git a/tests/RollbackTest/lib/src/com/android/tests/rollback/host/WatchdogEventLogger.java b/tests/RollbackTest/lib/src/com/android/tests/rollback/host/WatchdogEventLogger.java
index 88731504eafe..8c16079dca85 100644
--- a/tests/RollbackTest/lib/src/com/android/tests/rollback/host/WatchdogEventLogger.java
+++ b/tests/RollbackTest/lib/src/com/android/tests/rollback/host/WatchdogEventLogger.java
@@ -17,52 +17,52 @@
package com.android.tests.rollback.host;
import com.android.tradefed.device.ITestDevice;
-import com.android.tradefed.device.LogcatReceiver;
-import com.android.tradefed.result.InputStreamSource;
+import com.google.common.truth.FailureMetadata;
+import com.google.common.truth.Truth;
-import java.io.BufferedReader;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.util.ArrayList;
-import java.util.List;
+import static com.google.common.truth.Truth.assertThat;
public class WatchdogEventLogger {
- private LogcatReceiver mReceiver;
+ private static final String[] ROLLBACK_EVENT_TYPES = {
+ "ROLLBACK_INITIATE", "ROLLBACK_BOOT_TRIGGERED", "ROLLBACK_SUCCESS"};
+ private static final String[] ROLLBACK_EVENT_ATTRS = {
+ "logPackage", "rollbackReason", "failedPackageName"};
+ private static final String PROP_PREFIX = "persist.sys.rollbacktest.";
- public void start(ITestDevice device) {
- mReceiver = new LogcatReceiver(device, "logcat -s WatchdogRollbackLogger",
- device.getOptions().getMaxLogcatDataSize(), 0);
- mReceiver.start();
- }
+ private ITestDevice mDevice;
- public void stop() {
- if (mReceiver != null) {
- mReceiver.stop();
- mReceiver.clear();
+ private void resetProperties(boolean enabled) throws Exception {
+ try {
+ mDevice.enableAdbRoot();
+ assertThat(mDevice.setProperty(
+ PROP_PREFIX + "enabled", String.valueOf(enabled))).isTrue();
+ for (String type : ROLLBACK_EVENT_TYPES) {
+ String key = PROP_PREFIX + type;
+ assertThat(mDevice.setProperty(key, "")).isTrue();
+ for (String attr : ROLLBACK_EVENT_ATTRS) {
+ assertThat(mDevice.setProperty(key + "." + attr, "")).isTrue();
+ }
+ }
+ } finally {
+ mDevice.disableAdbRoot();
}
}
- /**
- * Returns a list of all Watchdog logging events which have occurred.
- */
- public List<String> getWatchdogLoggingEvents() throws Exception {
- try (InputStreamSource logcatStream = mReceiver.getLogcatData()) {
- return getWatchdogLoggingEvents(logcatStream);
- }
+ public void start(ITestDevice device) throws Exception {
+ mDevice = device;
+ resetProperties(true);
}
- private static List<String> getWatchdogLoggingEvents(InputStreamSource inputStreamSource)
- throws Exception {
- List<String> watchdogEvents = new ArrayList<>();
- InputStream inputStream = inputStreamSource.createInputStream();
- BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
- String line;
- while ((line = reader.readLine()) != null) {
- if (line.contains("Watchdog event occurred")) {
- watchdogEvents.add(line);
- }
+ public void stop() throws Exception {
+ if (mDevice != null) {
+ resetProperties(false);
}
- return watchdogEvents;
+ }
+
+ private boolean matchProperty(String type, String attr, String expectedVal) throws Exception {
+ String key = PROP_PREFIX + type + "." + attr;
+ String val = mDevice.getProperty(key);
+ return expectedVal == null || expectedVal.equals(val);
}
/**
@@ -71,33 +71,37 @@ public class WatchdogEventLogger {
* Check the value of all non-null parameters against the list of Watchdog events that have
* occurred, and return {@code true} if an event exists which matches all criteria.
*/
- public static boolean watchdogEventOccurred(List<String> loggingEvents,
- String type, String logPackage,
+ public boolean watchdogEventOccurred(String type, String logPackage,
String rollbackReason, String failedPackageName) throws Exception {
- List<String> eventCriteria = new ArrayList<>();
- if (type != null) {
- eventCriteria.add("type: " + type);
- }
- if (logPackage != null) {
- eventCriteria.add("logPackage: " + logPackage);
+ return mDevice.getBooleanProperty(PROP_PREFIX + type, false)
+ && matchProperty(type, "logPackage", logPackage)
+ && matchProperty(type, "rollbackReason", rollbackReason)
+ && matchProperty(type, "failedPackageName", failedPackageName);
+ }
+
+ static class Subject extends com.google.common.truth.Subject {
+ private final WatchdogEventLogger mActual;
+
+ private Subject(FailureMetadata failureMetadata, WatchdogEventLogger subject) {
+ super(failureMetadata, subject);
+ mActual = subject;
}
- if (rollbackReason != null) {
- eventCriteria.add("rollbackReason: " + rollbackReason);
+
+ private static com.google.common.truth.Subject.Factory<Subject,
+ WatchdogEventLogger> loggers() {
+ return Subject::new;
}
- if (failedPackageName != null) {
- eventCriteria.add("failedPackageName: " + failedPackageName);
+
+ static Subject assertThat(WatchdogEventLogger actual) {
+ return Truth.assertAbout(loggers()).that(actual);
}
- for (String loggingEvent: loggingEvents) {
- boolean matchesCriteria = true;
- for (String criterion: eventCriteria) {
- if (!loggingEvent.contains(criterion)) {
- matchesCriteria = false;
- }
- }
- if (matchesCriteria) {
- return true;
- }
+
+ void eventOccurred(String type, String logPackage, String rollbackReason,
+ String failedPackageName) throws Exception {
+ check("watchdogEventOccurred(type=%s, logPackage=%s, rollbackReason=%s, "
+ + "failedPackageName=%s)", type, logPackage, rollbackReason, failedPackageName)
+ .that(mActual.watchdogEventOccurred(type, logPackage, rollbackReason,
+ failedPackageName)).isTrue();
}
- return false;
}
}
diff --git a/tests/SerialChat/AndroidManifest.xml b/tests/SerialChat/AndroidManifest.xml
index 0efdb58d72cb..7aedb52752c5 100644
--- a/tests/SerialChat/AndroidManifest.xml
+++ b/tests/SerialChat/AndroidManifest.xml
@@ -15,16 +15,18 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.serialchat">
+ package="com.android.serialchat">
<uses-permission android:name="android.permission.SERIAL_PORT"/>
<application android:label="Serial Chat">
- <activity android:name="SerialChat" android:label="Serial Chat">
+ <activity android:name="SerialChat"
+ android:label="Serial Chat"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
diff --git a/tests/ServiceCrashTest/AndroidManifest.xml b/tests/ServiceCrashTest/AndroidManifest.xml
index 387c8b8ae36b..e906fe2109e1 100644
--- a/tests/ServiceCrashTest/AndroidManifest.xml
+++ b/tests/ServiceCrashTest/AndroidManifest.xml
@@ -1,23 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.tests.servicecrashtest">
+ package="com.android.tests.servicecrashtest">
<application android:label="Service Crash Test">
- <uses-library android:name="android.test.runner" />
+ <uses-library android:name="android.test.runner"/>
<service android:name=".CrashingService"
- android:process=":badservice" />
+ android:process=":badservice"/>
- <activity android:name=".MainActivity" >
+ <activity android:name=".MainActivity"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
+ <action android:name="android.intent.action.MAIN"/>
</intent-filter>
</activity>
</application>
<instrumentation android:label="Test bound service crash restart"
- android:name="android.test.InstrumentationTestRunner"
- android:targetPackage="com.android.tests.servicecrashtest" />
+ android:name="android.test.InstrumentationTestRunner"
+ android:targetPackage="com.android.tests.servicecrashtest"/>
</manifest>
diff --git a/tests/SharedLibrary/client/AndroidManifest.xml b/tests/SharedLibrary/client/AndroidManifest.xml
index d1167fa7322f..9903a98c0ae9 100644
--- a/tests/SharedLibrary/client/AndroidManifest.xml
+++ b/tests/SharedLibrary/client/AndroidManifest.xml
@@ -15,23 +15,26 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.google.android.test.lib_client">
- <application android:label="@string/app_title" android:theme="@style/Theme">
- <uses-library android:name="android.test.runner" />
- <uses-library android:name="com.google.android.test.shared_library" />
- <activity android:name="ActivityMain">
+ package="com.google.android.test.lib_client">
+ <application android:label="@string/app_title"
+ android:theme="@style/Theme">
+ <uses-library android:name="android.test.runner"/>
+ <uses-library android:name="com.google.android.test.shared_library"/>
+ <activity android:name="ActivityMain"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <receiver android:name="DependentAppwidgetProvider">
+ <receiver android:name="DependentAppwidgetProvider"
+ android:exported="true">
<intent-filter>
- <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
+ <action android:name="android.appwidget.action.APPWIDGET_UPDATE"/>
</intent-filter>
<meta-data android:name="android.appwidget.provider"
- android:resource="@xml/dependent_appwidget_info" />
+ android:resource="@xml/dependent_appwidget_info"/>
</receiver>
</application>
</manifest>
diff --git a/tests/SharedLibrary/lib/AndroidManifest.xml b/tests/SharedLibrary/lib/AndroidManifest.xml
index bb939dd4cb55..df2fdca18f6e 100644
--- a/tests/SharedLibrary/lib/AndroidManifest.xml
+++ b/tests/SharedLibrary/lib/AndroidManifest.xml
@@ -15,15 +15,16 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.google.android.test.shared_library"
- android:versionCode="2">
+ package="com.google.android.test.shared_library"
+ android:versionCode="2">
<application android:label="SharedLibrary">
- <library android:name="com.google.android.test.shared_library" />
+ <library android:name="com.google.android.test.shared_library"/>
<activity android:name="ActivityMain"
- android:icon="@drawable/size_48x48">
+ android:icon="@drawable/size_48x48"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
diff --git a/tests/ShowWhenLockedApp/AndroidManifest.xml b/tests/ShowWhenLockedApp/AndroidManifest.xml
index a872e061526f..82957b719a48 100644
--- a/tests/ShowWhenLockedApp/AndroidManifest.xml
+++ b/tests/ShowWhenLockedApp/AndroidManifest.xml
@@ -16,12 +16,13 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.showwhenlocked">
+ package="com.android.showwhenlocked">
<application android:label="ShowWhenLocked">
<activity android:name=".ShowWhenLockedActivity"
- android:showWhenLocked="true"
- android:turnScreenOn="true"
- android:launchMode="singleTask">
+ android:showWhenLocked="true"
+ android:turnScreenOn="true"
+ android:launchMode="singleTask"
+ android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
diff --git a/tests/SilkFX/Android.bp b/tests/SilkFX/Android.bp
new file mode 100644
index 000000000000..088d9a2d7f41
--- /dev/null
+++ b/tests/SilkFX/Android.bp
@@ -0,0 +1,37 @@
+//
+// Copyright (C) 2010 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 {
+ // 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"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+android_test {
+ name: "SilkFX",
+ srcs: ["**/*.java", "**/*.kt"],
+ platform_apis: true,
+ certificate: "platform",
+ static_libs: [
+ "androidx.core_core",
+ "androidx.appcompat_appcompat",
+ "com.google.android.material_material",
+ "androidx-constraintlayout_constraintlayout",
+ ],
+}
diff --git a/tests/AutoVerify/app4/AndroidManifest.xml b/tests/SilkFX/AndroidManifest.xml
index 1c975f8336c9..c30d76137f76 100644
--- a/tests/AutoVerify/app4/AndroidManifest.xml
+++ b/tests/SilkFX/AndroidManifest.xml
@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2020 The Android Open Source Project
+<!-- Copyright (C) 2010 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.
@@ -16,30 +15,39 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.test.autoverify" >
+ package="com.android.test.silkfx">
- <uses-sdk android:targetSdkVersion="26" />
+ <uses-sdk android:minSdkVersion="30"/>
- <application
- android:label="@string/app_name" >
- <activity
- android:name=".MainActivity"
- android:label="@string/app_name" >
+ <uses-permission android:name="android.permission.CONTROL_DISPLAY_BRIGHTNESS" />
+
+ <application android:label="SilkFX"
+ android:theme="@android:style/Theme.Material">
+
+ <activity android:name=".Main"
+ android:label="SilkFX Demos"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
+ </activity>
- <!-- intentionally does not autoVerify -->
+ <activity android:name=".app.CommonDemoActivity" />
+
+ <activity android:name=".hdr.GlowActivity"
+ android:label="Glow Examples"/>
+
+ <activity android:name=".materials.GlassActivity"
+ android:label="Glass Examples"
+ android:banner="@drawable/background1"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.VIEW" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.BROWSABLE" />
- <data android:scheme="http" />
- <data android:scheme="https" />
- <data android:host="explicit.example.com" />
- <data android:host="*.wildcard.tld" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LEANBACK_LAUNCHER" />
</intent-filter>
</activity>
+
</application>
</manifest>
diff --git a/tests/SilkFX/res/drawable-hdpi/background1.jpeg b/tests/SilkFX/res/drawable-hdpi/background1.jpeg
new file mode 100644
index 000000000000..dcdfa7b850bc
--- /dev/null
+++ b/tests/SilkFX/res/drawable-hdpi/background1.jpeg
Binary files differ
diff --git a/tests/SilkFX/res/drawable-hdpi/background2.jpeg b/tests/SilkFX/res/drawable-hdpi/background2.jpeg
new file mode 100644
index 000000000000..dc7ce84e6784
--- /dev/null
+++ b/tests/SilkFX/res/drawable-hdpi/background2.jpeg
Binary files differ
diff --git a/tests/SilkFX/res/drawable-hdpi/background3.jpeg b/tests/SilkFX/res/drawable-hdpi/background3.jpeg
new file mode 100644
index 000000000000..12b3429e3920
--- /dev/null
+++ b/tests/SilkFX/res/drawable-hdpi/background3.jpeg
Binary files differ
diff --git a/tests/SilkFX/res/drawable-hdpi/noise.png b/tests/SilkFX/res/drawable-hdpi/noise.png
new file mode 100644
index 000000000000..053995dad760
--- /dev/null
+++ b/tests/SilkFX/res/drawable-hdpi/noise.png
Binary files differ
diff --git a/tests/SilkFX/res/drawable-nodpi/dark_notification.png b/tests/SilkFX/res/drawable-nodpi/dark_notification.png
new file mode 100644
index 000000000000..6de6c2ae785c
--- /dev/null
+++ b/tests/SilkFX/res/drawable-nodpi/dark_notification.png
Binary files differ
diff --git a/tests/SilkFX/res/drawable-nodpi/light_notification.png b/tests/SilkFX/res/drawable-nodpi/light_notification.png
new file mode 100644
index 000000000000..81a67cd3d388
--- /dev/null
+++ b/tests/SilkFX/res/drawable-nodpi/light_notification.png
Binary files differ
diff --git a/tests/SilkFX/res/layout-television/activity_glass.xml b/tests/SilkFX/res/layout-television/activity_glass.xml
new file mode 100644
index 000000000000..1f566860da3d
--- /dev/null
+++ b/tests/SilkFX/res/layout-television/activity_glass.xml
@@ -0,0 +1,302 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+** Copyright 2020, 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.
+-->
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ tools:context=".MainActivity">
+
+ <ImageView
+ android:id="@+id/background"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:scaleType="matrix"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent"
+ tools:srcCompat="@drawable/background1" />
+
+ <com.android.test.silkfx.materials.GlassView
+ android:id="@+id/materialView"
+ android:layout_width="400dp"
+ android:layout_height="100dp"
+ android:layout_marginEnd="64dp"
+ android:layout_marginStart="64dp"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toEndOf="@id/background"
+ app:layout_constraintStart_toStartOf="@id/background"
+ app:layout_constraintTop_toTopOf="parent">
+ <TextView
+ android:id="@+id/textOverlay"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textSize="18dp"
+ android:layout_gravity="center"
+ android:textColor="#ffffff"
+ android:text="Lorem Ipsum dolor sit amet." />
+ </com.android.test.silkfx.materials.GlassView>
+
+ <androidx.constraintlayout.widget.ConstraintLayout
+ android:id="@+id/bottomPanel"
+ android:layout_width="400dp"
+ android:layout_height="wrap_content"
+ android:background="?android:attr/colorBackground"
+ android:paddingTop="24dp"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent">
+
+ <SeekBar
+ android:id="@+id/materialOpacity"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="12dp"
+ android:layout_marginEnd="12dp"
+ android:layout_marginBottom="16dp"
+ android:max="100"
+ android:progress="12"
+ app:layout_constraintBottom_toTopOf="@+id/scrimOpacityTitle"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintHorizontal_bias="1.0"
+ app:layout_constraintStart_toStartOf="parent" />
+
+ <SeekBar
+ android:id="@+id/zoom"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="16dp"
+ android:layout_marginEnd="12dp"
+ android:layout_marginStart="12dp"
+ android:min="-100"
+ android:max="100"
+ android:progress="-15"
+ app:layout_constraintBottom_toTopOf="@+id/blurRadiusTitle"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintHorizontal_bias="1.0"
+ app:layout_constraintStart_toStartOf="parent" />
+
+ <SeekBar
+ android:id="@+id/blurRadius"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="16dp"
+ android:layout_marginEnd="12dp"
+ android:layout_marginStart="12dp"
+ android:max="150"
+ android:progress="40"
+ app:layout_constraintBottom_toTopOf="@+id/materialOpacityTitle"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintHorizontal_bias="1.0"
+ app:layout_constraintStart_toStartOf="parent" />
+
+ <SeekBar
+ android:id="@+id/scrimOpacity"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="12dp"
+ android:layout_marginEnd="12dp"
+ android:layout_marginBottom="16dp"
+ android:max="100"
+ android:progress="50"
+ app:layout_constraintBottom_toTopOf="@+id/noiseOpacityTitle"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintHorizontal_bias="1.0"
+ app:layout_constraintStart_toStartOf="parent" />
+
+ <SeekBar
+ android:id="@+id/noiseOpacity"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="12dp"
+ android:layout_marginEnd="12dp"
+ android:layout_marginBottom="24dp"
+ android:max="100"
+ android:progress="15"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintHorizontal_bias="0.0"
+ app:layout_constraintStart_toStartOf="parent" />
+
+ <TextView
+ android:id="@+id/scrimOpacityTitle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="24dp"
+ android:layout_marginBottom="8dp"
+ android:text="Scrim Opacity"
+ android:textColor="@android:color/white"
+ app:layout_constraintBottom_toTopOf="@+id/scrimOpacity"
+ app:layout_constraintStart_toStartOf="parent" />
+
+ <TextView
+ android:id="@+id/materialOpacityTitle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="24dp"
+ android:layout_marginBottom="8dp"
+ android:text="Soft light Opacity"
+ android:textColor="@android:color/white"
+ app:layout_constraintBottom_toTopOf="@+id/materialOpacity"
+ app:layout_constraintStart_toStartOf="parent" />
+
+ <TextView
+ android:id="@+id/zoomTitle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="24dp"
+ android:layout_marginBottom="8dp"
+ android:text="Zoom"
+ android:textColor="@android:color/white"
+ app:layout_constraintBottom_toTopOf="@+id/zoom"
+ app:layout_constraintStart_toStartOf="parent" />
+
+ <TextView
+ android:id="@+id/blurRadiusTitle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="24dp"
+ android:layout_marginBottom="8dp"
+ android:text="Blur Radius"
+ android:textColor="@android:color/white"
+ app:layout_constraintBottom_toTopOf="@+id/blurRadius"
+ app:layout_constraintStart_toStartOf="parent" />
+
+ <TextView
+ android:id="@+id/noiseOpacityTitle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="24dp"
+ android:layout_marginBottom="8dp"
+ android:textColor="@android:color/white"
+ android:text="Noise Opacity"
+ app:layout_constraintBottom_toTopOf="@+id/noiseOpacity"
+ app:layout_constraintStart_toStartOf="parent" />
+
+ <ImageView
+ android:id="@+id/background1"
+ android:layout_width="64dp"
+ android:layout_height="64dp"
+ android:layout_marginStart="24dp"
+ android:layout_marginBottom="16dp"
+ android:foreground="?android:attr/selectableItemBackgroundBorderless"
+ android:clickable="true"
+ android:onClick="onBackgroundClick"
+ android:scaleType="centerCrop"
+ app:layout_constraintBottom_toTopOf="@+id/lightMaterialSwitch"
+ app:layout_constraintStart_toStartOf="parent"
+ android:src="@drawable/background1" />
+
+ <ImageView
+ android:id="@+id/background2"
+ android:layout_width="64dp"
+ android:layout_height="64dp"
+ android:layout_marginStart="8dp"
+ android:foreground="?android:attr/selectableItemBackgroundBorderless"
+ android:clickable="true"
+ android:onClick="onBackgroundClick"
+ android:scaleType="centerCrop"
+ app:layout_constraintBottom_toBottomOf="@+id/background1"
+ app:layout_constraintStart_toEndOf="@+id/background1"
+ android:src="@drawable/background2" />
+
+ <ImageView
+ android:id="@+id/background3"
+ android:layout_width="64dp"
+ android:layout_height="64dp"
+ android:layout_marginStart="8dp"
+ android:scaleType="centerCrop"
+ android:foreground="?android:attr/selectableItemBackgroundBorderless"
+ android:clickable="true"
+ android:onClick="onBackgroundClick"
+ app:layout_constraintBottom_toBottomOf="@+id/background1"
+ app:layout_constraintStart_toEndOf="@+id/background2"
+ android:src="@drawable/background3" />
+
+ <Button
+ android:id="@+id/pickImage"
+ android:layout_width="64dp"
+ android:layout_height="64dp"
+ android:layout_marginStart="8dp"
+ android:scaleType="centerCrop"
+ android:foreground="?android:attr/selectableItemBackgroundBorderless"
+ android:clickable="true"
+ android:onClick="onPickImageClick"
+ app:layout_constraintBottom_toBottomOf="@+id/background1"
+ app:layout_constraintStart_toEndOf="@+id/background3"
+ android:text="Pick file" />
+
+ <Switch
+ android:id="@+id/lightMaterialSwitch"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="24dp"
+ android:layout_marginBottom="8dp"
+ android:text="Light Material"
+ app:layout_constraintBottom_toTopOf="@+id/zoomTitle"
+ app:layout_constraintStart_toStartOf="parent" />
+
+ <TextView
+ android:id="@+id/blurRadiusValue"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="TextView"
+ android:layout_marginLeft="8dp"
+ app:layout_constraintBottom_toBottomOf="@+id/blurRadiusTitle"
+ app:layout_constraintStart_toEndOf="@+id/blurRadiusTitle" />
+
+ <TextView
+ android:id="@+id/zoomValue"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="TextView"
+ android:layout_marginLeft="8dp"
+ app:layout_constraintBottom_toBottomOf="@+id/zoomTitle"
+ app:layout_constraintStart_toEndOf="@+id/zoomTitle" />
+
+ <TextView
+ android:id="@+id/materialOpacityValue"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="TextView"
+ android:layout_marginLeft="8dp"
+ app:layout_constraintBottom_toBottomOf="@+id/materialOpacityTitle"
+ app:layout_constraintStart_toEndOf="@+id/materialOpacityTitle" />
+
+ <TextView
+ android:id="@+id/noiseOpacityValue"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="TextView"
+ android:layout_marginLeft="8dp"
+ app:layout_constraintBottom_toBottomOf="@+id/noiseOpacityTitle"
+ app:layout_constraintStart_toEndOf="@+id/noiseOpacityTitle" />
+
+
+ <TextView
+ android:id="@+id/scrimOpacityValue"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="TextView"
+ android:layout_marginLeft="8dp"
+ app:layout_constraintBottom_toBottomOf="@+id/scrimOpacityTitle"
+ app:layout_constraintStart_toEndOf="@+id/scrimOpacityTitle" />
+
+ </androidx.constraintlayout.widget.ConstraintLayout>
+
+
+</androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/tests/SilkFX/res/layout/activity_glass.xml b/tests/SilkFX/res/layout/activity_glass.xml
new file mode 100644
index 000000000000..aa09f276d5c8
--- /dev/null
+++ b/tests/SilkFX/res/layout/activity_glass.xml
@@ -0,0 +1,303 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+** Copyright 2012, 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.
+-->
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ tools:context=".MainActivity">
+
+ <ImageView
+ android:id="@+id/background"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:scaleType="matrix"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent"
+ tools:srcCompat="@drawable/background1" />
+
+ <com.android.test.silkfx.materials.GlassView
+ android:id="@+id/materialView"
+ android:layout_width="0dp"
+ android:layout_height="180dp"
+ android:layout_marginEnd="64dp"
+ android:layout_marginStart="64dp"
+ app:layout_constraintBottom_toTopOf="@+id/bottomPanel"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent">
+ <TextView
+ android:id="@+id/textOverlay"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textSize="18dp"
+ android:layout_gravity="center"
+ android:textColor="#ffffff"
+ android:text="Lorem Ipsum dolor sit amet." />
+ </com.android.test.silkfx.materials.GlassView>
+
+ <androidx.constraintlayout.widget.ConstraintLayout
+ android:id="@+id/bottomPanel"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:background="?android:attr/colorBackground"
+ android:paddingTop="24dp"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent">
+
+ <SeekBar
+ android:id="@+id/materialOpacity"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="12dp"
+ android:layout_marginEnd="12dp"
+ android:layout_marginBottom="16dp"
+ android:max="100"
+ android:progress="12"
+ app:layout_constraintBottom_toTopOf="@+id/scrimOpacityTitle"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintHorizontal_bias="1.0"
+ app:layout_constraintStart_toStartOf="parent" />
+
+ <SeekBar
+ android:id="@+id/zoom"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="16dp"
+ android:layout_marginEnd="12dp"
+ android:layout_marginStart="12dp"
+ android:min="-100"
+ android:max="100"
+ android:progress="-15"
+ app:layout_constraintBottom_toTopOf="@+id/blurRadiusTitle"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintHorizontal_bias="1.0"
+ app:layout_constraintStart_toStartOf="parent" />
+
+ <SeekBar
+ android:id="@+id/blurRadius"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="16dp"
+ android:layout_marginEnd="12dp"
+ android:layout_marginStart="12dp"
+ android:max="150"
+ android:progress="40"
+ app:layout_constraintBottom_toTopOf="@+id/materialOpacityTitle"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintHorizontal_bias="1.0"
+ app:layout_constraintStart_toStartOf="parent" />
+
+ <SeekBar
+ android:id="@+id/scrimOpacity"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="12dp"
+ android:layout_marginEnd="12dp"
+ android:layout_marginBottom="16dp"
+ android:max="100"
+ android:progress="50"
+ app:layout_constraintBottom_toTopOf="@+id/noiseOpacityTitle"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintHorizontal_bias="1.0"
+ app:layout_constraintStart_toStartOf="parent" />
+
+ <SeekBar
+ android:id="@+id/noiseOpacity"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="12dp"
+ android:layout_marginEnd="12dp"
+ android:layout_marginBottom="24dp"
+ android:max="100"
+ android:progress="15"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintHorizontal_bias="0.0"
+ app:layout_constraintStart_toStartOf="parent" />
+
+ <TextView
+ android:id="@+id/scrimOpacityTitle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="24dp"
+ android:layout_marginBottom="8dp"
+ android:text="Scrim Opacity"
+ android:textColor="@android:color/white"
+ app:layout_constraintBottom_toTopOf="@+id/scrimOpacity"
+ app:layout_constraintStart_toStartOf="parent" />
+
+ <TextView
+ android:id="@+id/materialOpacityTitle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="24dp"
+ android:layout_marginBottom="8dp"
+ android:text="Soft light Opacity"
+ android:textColor="@android:color/white"
+ app:layout_constraintBottom_toTopOf="@+id/materialOpacity"
+ app:layout_constraintStart_toStartOf="parent" />
+
+ <TextView
+ android:id="@+id/zoomTitle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="24dp"
+ android:layout_marginBottom="8dp"
+ android:text="Zoom"
+ android:textColor="@android:color/white"
+ app:layout_constraintBottom_toTopOf="@+id/zoom"
+ app:layout_constraintStart_toStartOf="parent" />
+
+ <TextView
+ android:id="@+id/blurRadiusTitle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="24dp"
+ android:layout_marginBottom="8dp"
+ android:text="Blur Radius"
+ android:textColor="@android:color/white"
+ app:layout_constraintBottom_toTopOf="@+id/blurRadius"
+ app:layout_constraintStart_toStartOf="parent" />
+
+ <TextView
+ android:id="@+id/noiseOpacityTitle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="24dp"
+ android:layout_marginBottom="8dp"
+ android:textColor="@android:color/white"
+ android:text="Noise Opacity"
+ app:layout_constraintBottom_toTopOf="@+id/noiseOpacity"
+ app:layout_constraintStart_toStartOf="parent" />
+
+ <ImageView
+ android:id="@+id/background1"
+ android:layout_width="64dp"
+ android:layout_height="64dp"
+ android:layout_marginStart="24dp"
+ android:layout_marginBottom="16dp"
+ android:foreground="?android:attr/selectableItemBackgroundBorderless"
+ android:clickable="true"
+ android:onClick="onBackgroundClick"
+ android:scaleType="centerCrop"
+ app:layout_constraintBottom_toTopOf="@+id/lightMaterialSwitch"
+ app:layout_constraintStart_toStartOf="parent"
+ android:src="@drawable/background1" />
+
+ <ImageView
+ android:id="@+id/background2"
+ android:layout_width="64dp"
+ android:layout_height="64dp"
+ android:layout_marginStart="8dp"
+ android:foreground="?android:attr/selectableItemBackgroundBorderless"
+ android:clickable="true"
+ android:onClick="onBackgroundClick"
+ android:scaleType="centerCrop"
+ app:layout_constraintBottom_toBottomOf="@+id/background1"
+ app:layout_constraintStart_toEndOf="@+id/background1"
+ android:src="@drawable/background2" />
+
+ <ImageView
+ android:id="@+id/background3"
+ android:layout_width="64dp"
+ android:layout_height="64dp"
+ android:layout_marginStart="8dp"
+ android:scaleType="centerCrop"
+ android:foreground="?android:attr/selectableItemBackgroundBorderless"
+ android:clickable="true"
+ android:onClick="onBackgroundClick"
+ app:layout_constraintBottom_toBottomOf="@+id/background1"
+ app:layout_constraintStart_toEndOf="@+id/background2"
+ android:src="@drawable/background3" />
+
+ <Button
+ android:id="@+id/pickImage"
+ android:layout_width="64dp"
+ android:layout_height="64dp"
+ android:layout_marginStart="8dp"
+ android:scaleType="centerCrop"
+ android:foreground="?android:attr/selectableItemBackgroundBorderless"
+ android:clickable="true"
+ android:onClick="onPickImageClick"
+ app:layout_constraintBottom_toBottomOf="@+id/background1"
+ app:layout_constraintStart_toEndOf="@+id/background3"
+ android:text="Pick file" />
+
+ <Switch
+ android:id="@+id/lightMaterialSwitch"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="24dp"
+ android:layout_marginBottom="8dp"
+ android:text="Light Material"
+ app:layout_constraintBottom_toTopOf="@+id/zoomTitle"
+ app:layout_constraintStart_toStartOf="parent" />
+
+ <TextView
+ android:id="@+id/blurRadiusValue"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="TextView"
+ android:layout_marginLeft="8dp"
+ app:layout_constraintBottom_toBottomOf="@+id/blurRadiusTitle"
+ app:layout_constraintStart_toEndOf="@+id/blurRadiusTitle" />
+
+ <TextView
+ android:id="@+id/zoomValue"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="TextView"
+ android:layout_marginLeft="8dp"
+ app:layout_constraintBottom_toBottomOf="@+id/zoomTitle"
+ app:layout_constraintStart_toEndOf="@+id/zoomTitle" />
+
+ <TextView
+ android:id="@+id/materialOpacityValue"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="TextView"
+ android:layout_marginLeft="8dp"
+ app:layout_constraintBottom_toBottomOf="@+id/materialOpacityTitle"
+ app:layout_constraintStart_toEndOf="@+id/materialOpacityTitle" />
+
+ <TextView
+ android:id="@+id/noiseOpacityValue"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="TextView"
+ android:layout_marginLeft="8dp"
+ app:layout_constraintBottom_toBottomOf="@+id/noiseOpacityTitle"
+ app:layout_constraintStart_toEndOf="@+id/noiseOpacityTitle" />
+
+
+ <TextView
+ android:id="@+id/scrimOpacityValue"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="TextView"
+ android:layout_marginLeft="8dp"
+ app:layout_constraintBottom_toBottomOf="@+id/scrimOpacityTitle"
+ app:layout_constraintStart_toEndOf="@+id/scrimOpacityTitle" />
+
+ </androidx.constraintlayout.widget.ConstraintLayout>
+
+
+</androidx.constraintlayout.widget.ConstraintLayout> \ No newline at end of file
diff --git a/tests/SilkFX/res/layout/bling_notifications.xml b/tests/SilkFX/res/layout/bling_notifications.xml
new file mode 100644
index 000000000000..6d266b701a68
--- /dev/null
+++ b/tests/SilkFX/res/layout/bling_notifications.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 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.
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <com.android.test.silkfx.hdr.BlingyNotification
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_margin="8dp"
+ android:src="@drawable/dark_notification" />
+
+ <com.android.test.silkfx.hdr.BlingyNotification
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_margin="8dp"
+ android:src="@drawable/light_notification" />
+
+</LinearLayout> \ No newline at end of file
diff --git a/tests/SilkFX/res/layout/color_mode_controls.xml b/tests/SilkFX/res/layout/color_mode_controls.xml
new file mode 100644
index 000000000000..c0c0bab8a605
--- /dev/null
+++ b/tests/SilkFX/res/layout/color_mode_controls.xml
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 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.
+ -->
+
+<com.android.test.silkfx.common.ColorModeControls
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <TextView
+ android:id="@+id/current_mode"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+
+ <Button
+ android:id="@+id/mode_default"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:text="Default (sRGB)" />
+
+ <Button
+ android:id="@+id/mode_wide"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:text="Wide Gamut (P3)" />
+
+ <Button
+ android:id="@+id/mode_hdr"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:text="HDR" />
+
+ <Button
+ android:id="@+id/mode_hdr10"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:text="HDR10" />
+
+ </LinearLayout>
+
+</com.android.test.silkfx.common.ColorModeControls> \ No newline at end of file
diff --git a/tests/SilkFX/res/layout/common_base.xml b/tests/SilkFX/res/layout/common_base.xml
new file mode 100644
index 000000000000..944c6846fbf7
--- /dev/null
+++ b/tests/SilkFX/res/layout/common_base.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 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.
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <include layout="@layout/color_mode_controls" />
+
+ <FrameLayout android:id="@+id/demo_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1" />
+
+ <com.android.test.silkfx.common.HDRIndicator
+ android:layout_width="match_parent"
+ android:layout_height="50dp"
+ android:layout_margin="8dp" />
+
+</LinearLayout> \ No newline at end of file
diff --git a/tests/SilkFX/res/layout/hdr_glows.xml b/tests/SilkFX/res/layout/hdr_glows.xml
new file mode 100644
index 000000000000..b6050645866a
--- /dev/null
+++ b/tests/SilkFX/res/layout/hdr_glows.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 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.
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <include layout="@layout/color_mode_controls" />
+
+ <com.android.test.silkfx.hdr.GlowingCard
+ android:layout_width="match_parent"
+ android:layout_height="100dp"
+ android:layout_margin="8dp" />
+
+ <com.android.test.silkfx.hdr.GlowingCard
+ android:id="@+id/card2"
+ android:layout_width="match_parent"
+ android:layout_height="100dp"
+ android:layout_margin="8dp"/>
+
+ <com.android.test.silkfx.hdr.RadialGlow
+ android:layout_width="match_parent"
+ android:layout_height="200dp"
+ android:layout_margin="8dp" />
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1" />
+
+ <com.android.test.silkfx.common.HDRIndicator
+ android:layout_width="match_parent"
+ android:layout_height="50dp"
+ android:layout_margin="8dp" />
+
+</LinearLayout> \ No newline at end of file
diff --git a/tests/SilkFX/src/com/android/test/silkfx/Main.kt b/tests/SilkFX/src/com/android/test/silkfx/Main.kt
new file mode 100644
index 000000000000..9ed8d2f5edf7
--- /dev/null
+++ b/tests/SilkFX/src/com/android/test/silkfx/Main.kt
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2020 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.test.silkfx
+
+import android.app.Activity
+import android.content.Context
+import android.content.Intent
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.BaseExpandableListAdapter
+import android.widget.ExpandableListView
+import android.widget.TextView
+import com.android.test.silkfx.app.CommonDemoActivity
+import com.android.test.silkfx.app.EXTRA_LAYOUT
+import com.android.test.silkfx.app.EXTRA_TITLE
+import com.android.test.silkfx.hdr.GlowActivity
+import com.android.test.silkfx.materials.GlassActivity
+import kotlin.reflect.KClass
+
+class Demo(val name: String, val makeIntent: (Context) -> Intent) {
+ constructor(name: String, activity: KClass<out Activity>) : this(name, { context ->
+ Intent(context, activity.java)
+ })
+ constructor(name: String, layout: Int) : this(name, { context ->
+ Intent(context, CommonDemoActivity::class.java).apply {
+ putExtra(EXTRA_LAYOUT, layout)
+ putExtra(EXTRA_TITLE, name)
+ }
+ })
+}
+data class DemoGroup(val groupName: String, val demos: List<Demo>)
+
+private val AllDemos = listOf(
+ DemoGroup("HDR", listOf(
+ Demo("Glow", GlowActivity::class),
+ Demo("Blingy Notifications", R.layout.bling_notifications)
+ )),
+ DemoGroup("Materials", listOf(
+ Demo("Glass", GlassActivity::class)
+ ))
+)
+
+class Main : Activity() {
+
+ public override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ val list = ExpandableListView(this)
+
+ setContentView(list)
+
+ val inflater = LayoutInflater.from(this)
+ list.setAdapter(object : BaseExpandableListAdapter() {
+ override fun getGroup(groupPosition: Int): DemoGroup {
+ return AllDemos[groupPosition]
+ }
+
+ override fun isChildSelectable(groupPosition: Int, childPosition: Int): Boolean = true
+
+ override fun hasStableIds(): Boolean = true
+
+ override fun getGroupView(
+ groupPosition: Int,
+ isExpanded: Boolean,
+ convertView: View?,
+ parent: ViewGroup?
+ ): View {
+ val view = (convertView ?: inflater.inflate(
+ android.R.layout.simple_expandable_list_item_1, parent, false)) as TextView
+ view.text = AllDemos[groupPosition].groupName
+ return view
+ }
+
+ override fun getChildrenCount(groupPosition: Int): Int {
+ return AllDemos[groupPosition].demos.size
+ }
+
+ override fun getChild(groupPosition: Int, childPosition: Int): Demo {
+ return AllDemos[groupPosition].demos[childPosition]
+ }
+
+ override fun getGroupId(groupPosition: Int): Long = groupPosition.toLong()
+
+ override fun getChildView(
+ groupPosition: Int,
+ childPosition: Int,
+ isLastChild: Boolean,
+ convertView: View?,
+ parent: ViewGroup?
+ ): View {
+ val view = (convertView ?: inflater.inflate(
+ android.R.layout.simple_expandable_list_item_1, parent, false)) as TextView
+ view.text = AllDemos[groupPosition].demos[childPosition].name
+ return view
+ }
+
+ override fun getChildId(groupPosition: Int, childPosition: Int): Long {
+ return (groupPosition.toLong() shl 32) or childPosition.toLong()
+ }
+
+ override fun getGroupCount(): Int {
+ return AllDemos.size
+ }
+ })
+
+ list.setOnChildClickListener { _, _, groupPosition, childPosition, _ ->
+ val demo = AllDemos[groupPosition].demos[childPosition]
+ startActivity(demo.makeIntent(this))
+ return@setOnChildClickListener true
+ }
+
+ AllDemos.forEachIndexed { index, _ -> list.expandGroup(index) }
+ }
+} \ No newline at end of file
diff --git a/tests/SilkFX/src/com/android/test/silkfx/app/BaseDemoActivity.kt b/tests/SilkFX/src/com/android/test/silkfx/app/BaseDemoActivity.kt
new file mode 100644
index 000000000000..89011b51b8d6
--- /dev/null
+++ b/tests/SilkFX/src/com/android/test/silkfx/app/BaseDemoActivity.kt
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2020 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.test.silkfx.app
+
+import android.app.Activity
+import android.content.Context
+import android.os.Bundle
+import android.util.AttributeSet
+import android.view.LayoutInflater
+import android.view.MenuItem
+import android.view.View
+
+open class BaseDemoActivity : Activity() {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ val inflater = LayoutInflater.from(this)
+ inflater.factory2 = object : LayoutInflater.Factory2 {
+ private val sClassPrefixList = arrayOf(
+ "android.widget.",
+ "android.webkit.",
+ "android.app.",
+ null
+ )
+ override fun onCreateView(
+ parent: View?,
+ name: String,
+ context: Context,
+ attrs: AttributeSet
+ ): View? {
+ return onCreateView(name, context, attrs)
+ }
+
+ override fun onCreateView(name: String, context: Context, attrs: AttributeSet): View? {
+ for (prefix in sClassPrefixList) {
+ try {
+ val view = inflater.createView(name, prefix, attrs)
+ if (view != null) {
+ if (view is WindowObserver) {
+ view.setWindow(window)
+ }
+ return view
+ }
+ } catch (e: ClassNotFoundException) { }
+ }
+ return null
+ }
+ }
+ }
+
+ override fun onStart() {
+ super.onStart()
+ actionBar?.setDisplayHomeAsUpEnabled(true)
+ }
+
+ override fun onOptionsItemSelected(item: MenuItem): Boolean {
+ if (item.itemId == android.R.id.home) {
+ onBackPressed()
+ return true
+ }
+ return super.onOptionsItemSelected(item)
+ }
+} \ No newline at end of file
diff --git a/tests/SilkFX/src/com/android/test/silkfx/app/CommonDemoActivity.kt b/tests/SilkFX/src/com/android/test/silkfx/app/CommonDemoActivity.kt
new file mode 100644
index 000000000000..e0a0a20bc0a0
--- /dev/null
+++ b/tests/SilkFX/src/com/android/test/silkfx/app/CommonDemoActivity.kt
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2020 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.test.silkfx.app
+
+import com.android.test.silkfx.R
+import android.os.Bundle
+import android.view.LayoutInflater
+
+const val EXTRA_LAYOUT = "layout"
+const val EXTRA_TITLE = "title"
+
+class CommonDemoActivity : BaseDemoActivity() {
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ val extras = intent.extras ?: return finish()
+
+ val layout = extras.getInt(EXTRA_LAYOUT, -1)
+ if (layout == -1) {
+ finish()
+ return
+ }
+ val title = extras.getString(EXTRA_TITLE, "SilkFX")
+ window.setTitle(title)
+
+ setContentView(R.layout.common_base)
+ actionBar?.title = title
+ LayoutInflater.from(this).inflate(layout, findViewById(R.id.demo_container), true)
+ }
+} \ No newline at end of file
diff --git a/tests/AutoVerify/app3/src/com/android/test/autoverify/MainActivity.java b/tests/SilkFX/src/com/android/test/silkfx/app/WindowObserver.kt
index 09ef47212622..3d989a54cf27 100644
--- a/tests/AutoVerify/app3/src/com/android/test/autoverify/MainActivity.java
+++ b/tests/SilkFX/src/com/android/test/silkfx/app/WindowObserver.kt
@@ -13,3 +13,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
+package com.android.test.silkfx.app
+
+import android.view.Window
+
+interface WindowObserver {
+ fun setWindow(window: Window)
+} \ No newline at end of file
diff --git a/tests/SilkFX/src/com/android/test/silkfx/common/BaseDrawingView.kt b/tests/SilkFX/src/com/android/test/silkfx/common/BaseDrawingView.kt
new file mode 100644
index 000000000000..4b85953a24b9
--- /dev/null
+++ b/tests/SilkFX/src/com/android/test/silkfx/common/BaseDrawingView.kt
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2020 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.test.silkfx.common
+
+import android.content.Context
+import android.graphics.Color
+import android.graphics.ColorSpace
+import android.util.AttributeSet
+import android.view.View
+
+open class BaseDrawingView : View {
+ val scRGB = ColorSpace.get(ColorSpace.Named.EXTENDED_SRGB)
+ val bt2020 = ColorSpace.get(ColorSpace.Named.BT2020)
+ val lab = ColorSpace.get(ColorSpace.Named.CIE_LAB)
+
+ val density: Float
+ val dp: Int.() -> Float
+
+ fun color(red: Float, green: Float, blue: Float, alpha: Float = 1f): Long {
+ return Color.pack(red, green, blue, alpha, scRGB)
+ }
+
+ constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {
+ setWillNotDraw(false)
+ isClickable = true
+ density = resources.displayMetrics.density
+ dp = { this * density }
+ }
+} \ No newline at end of file
diff --git a/tests/SilkFX/src/com/android/test/silkfx/common/ColorModeControls.kt b/tests/SilkFX/src/com/android/test/silkfx/common/ColorModeControls.kt
new file mode 100644
index 000000000000..b41ee3a9ef2c
--- /dev/null
+++ b/tests/SilkFX/src/com/android/test/silkfx/common/ColorModeControls.kt
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2020 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.test.silkfx.common
+
+import android.content.Context
+import android.content.pm.ActivityInfo
+import android.hardware.display.DisplayManager
+import android.os.IBinder
+import android.util.AttributeSet
+import android.util.Log
+import android.view.SurfaceControl
+import android.view.SurfaceControlHdrLayerInfoListener
+import android.view.Window
+import android.widget.Button
+import android.widget.LinearLayout
+import android.widget.TextView
+import com.android.test.silkfx.R
+import com.android.test.silkfx.app.WindowObserver
+
+class ColorModeControls : LinearLayout, WindowObserver {
+ private val COLOR_MODE_HDR10 = 3
+ private val SDR_WHITE_POINTS = floatArrayOf(200f, 250f, 300f, 350f, 400f, 100f, 150f)
+
+ constructor(context: Context) : this(context, null)
+ constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {
+ displayManager = context.getSystemService(DisplayManager::class.java)!!
+ displayId = context.getDisplayId()
+ displayToken = SurfaceControl.getInternalDisplayToken()
+ }
+
+ private var window: Window? = null
+ private var currentModeDisplay: TextView? = null
+ private val displayManager: DisplayManager
+ private var targetSdrWhitePointIndex = 0
+ private var displayId: Int
+ private var displayToken: IBinder
+
+ private val whitePoint get() = SDR_WHITE_POINTS[targetSdrWhitePointIndex]
+
+ override fun onFinishInflate() {
+ super.onFinishInflate()
+ val window = window ?: throw IllegalStateException("Failed to attach window")
+
+ currentModeDisplay = findViewById(R.id.current_mode)!!
+ setColorMode(window.colorMode)
+
+ findViewById<Button>(R.id.mode_default)!!.setOnClickListener {
+ setColorMode(ActivityInfo.COLOR_MODE_DEFAULT)
+ }
+ findViewById<Button>(R.id.mode_wide)!!.setOnClickListener {
+ setColorMode(ActivityInfo.COLOR_MODE_WIDE_COLOR_GAMUT)
+ }
+ findViewById<Button>(R.id.mode_hdr)!!.setOnClickListener {
+ setColorMode(ActivityInfo.COLOR_MODE_HDR)
+ }
+ findViewById<Button>(R.id.mode_hdr10)!!.setOnClickListener {
+ setColorMode(COLOR_MODE_HDR10)
+ }
+ }
+
+ private fun setColorMode(newMode: Int) {
+ val window = window!!
+ var sdrWhitepointChanged = false
+ // Need to do this before setting the colorMode, as setting the colorMode will
+ // trigger the attribute change listener
+ if (newMode == ActivityInfo.COLOR_MODE_HDR ||
+ newMode == COLOR_MODE_HDR10) {
+ if (window.colorMode == newMode) {
+ targetSdrWhitePointIndex = (targetSdrWhitePointIndex + 1) % SDR_WHITE_POINTS.size
+ sdrWhitepointChanged = true
+ }
+ setBrightness(1.0f)
+ } else {
+ setBrightness(.4f)
+ }
+ window.colorMode = newMode
+ if (sdrWhitepointChanged) {
+ threadedRenderer?.setColorMode(newMode, whitePoint)
+ }
+ val whitePoint = whitePoint.toInt()
+ currentModeDisplay?.run {
+ text = "Current Mode: " + when (newMode) {
+ ActivityInfo.COLOR_MODE_DEFAULT -> "Default/SRGB"
+ ActivityInfo.COLOR_MODE_WIDE_COLOR_GAMUT -> "Wide Gamut"
+ ActivityInfo.COLOR_MODE_HDR -> "HDR (sdr white point $whitePoint)"
+ COLOR_MODE_HDR10 -> "HDR10 (sdr white point $whitePoint)"
+ else -> "Unknown"
+ }
+ }
+ }
+
+ override fun setWindow(window: Window) {
+ this.window = window
+ }
+
+ private fun setBrightness(level: Float) {
+ // To keep window state in sync
+ window?.attributes?.screenBrightness = level
+ invalidate()
+ // To force an 'immediate' snap to what we want
+ // Imperfect, but close enough, synchronization by waiting for frame commit to set the value
+ viewTreeObserver.registerFrameCommitCallback {
+ try {
+ SurfaceControl.setDisplayBrightness(displayToken, level)
+ displayManager.setTemporaryBrightness(displayId, level)
+ } catch (ex: Exception) {
+ // Ignore a permission denied rejection - it doesn't meaningfully change much
+ }
+ }
+ }
+
+ private val listener = object : SurfaceControlHdrLayerInfoListener() {
+ override fun onHdrInfoChanged(
+ displayToken: IBinder?,
+ numberOfHdrLayers: Int,
+ maxW: Int,
+ maxH: Int,
+ flags: Int
+ ) {
+ Log.d("HDRInfo", "onHdrInfoChanged: numLayer = $numberOfHdrLayers ($maxW x $maxH)" +
+ ", flags = $flags")
+ }
+ }
+
+ override fun onAttachedToWindow() {
+ super.onAttachedToWindow()
+
+ threadedRenderer?.setColorMode(window!!.colorMode, whitePoint)
+ listener.register(displayToken)
+ }
+
+ override fun onDetachedFromWindow() {
+ super.onDetachedFromWindow()
+ listener.unregister(displayToken)
+ }
+} \ No newline at end of file
diff --git a/tests/SilkFX/src/com/android/test/silkfx/common/HDRIndicator.kt b/tests/SilkFX/src/com/android/test/silkfx/common/HDRIndicator.kt
new file mode 100644
index 000000000000..f42161f63811
--- /dev/null
+++ b/tests/SilkFX/src/com/android/test/silkfx/common/HDRIndicator.kt
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2020 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.test.silkfx.common
+
+import android.content.Context
+import android.graphics.Canvas
+import android.graphics.Color
+import android.graphics.ColorSpace
+import android.graphics.Paint
+import android.graphics.RectF
+import android.util.AttributeSet
+import android.view.View
+
+class HDRIndicator(context: Context) : View(context) {
+ constructor(context: Context, attrs: AttributeSet?) : this(context)
+
+ val scRGB = ColorSpace.get(ColorSpace.Named.EXTENDED_SRGB)
+
+ override fun onDraw(canvas: Canvas) {
+ super.onDraw(canvas)
+
+ val paint = Paint()
+ paint.isAntiAlias = true
+ val rect = RectF(0f, 0f, width.toFloat(), height.toFloat())
+ paint.textSize = height.toFloat()
+
+ canvas.drawColor(Color.pack(1f, 1f, 1f, 1f, scRGB))
+
+ paint.setColor(Color.pack(1.1f, 1.1f, 1.1f, 1f, scRGB))
+ canvas.drawText("H", rect.left, rect.bottom, paint)
+ paint.setColor(Color.pack(1.2f, 1.2f, 1.2f, 1f, scRGB))
+ canvas.drawText("D", rect.left + height.toFloat(), rect.bottom, paint)
+ paint.setColor(Color.pack(1.3f, 1.3f, 1.3f, 1f, scRGB))
+ canvas.drawText("R", rect.left + height.toFloat() * 2, rect.bottom, paint)
+ }
+} \ No newline at end of file
diff --git a/tests/SilkFX/src/com/android/test/silkfx/hdr/BlingyNotification.kt b/tests/SilkFX/src/com/android/test/silkfx/hdr/BlingyNotification.kt
new file mode 100644
index 000000000000..4ad21faec9d4
--- /dev/null
+++ b/tests/SilkFX/src/com/android/test/silkfx/hdr/BlingyNotification.kt
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2020 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.test.silkfx.hdr
+
+import android.content.Context
+import android.graphics.Bitmap
+import android.graphics.BlendMode
+import android.graphics.Canvas
+import android.graphics.LinearGradient
+import android.graphics.Paint
+import android.graphics.Rect
+import android.graphics.Shader
+import android.graphics.drawable.BitmapDrawable
+import android.util.AttributeSet
+import com.android.test.silkfx.common.BaseDrawingView
+
+class BlingyNotification : BaseDrawingView {
+
+ private val image: Bitmap?
+ private val bounds = Rect()
+ private val paint = Paint()
+
+ constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {
+ val typed = context.obtainStyledAttributes(attrs, intArrayOf(android.R.attr.src))
+ val drawable = typed.getDrawable(0)
+ image = if (drawable is BitmapDrawable) {
+ drawable.bitmap
+ } else {
+ null
+ }
+ typed.recycle()
+ }
+
+ override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
+ val image = image ?: return super.onMeasure(widthMeasureSpec, heightMeasureSpec)
+
+ val widthMode = MeasureSpec.getMode(widthMeasureSpec)
+ val heightMode = MeasureSpec.getMode(heightMeasureSpec)
+
+ // Currently only used in this mode, so that's all we'll bother to support
+ if (widthMode == MeasureSpec.EXACTLY && heightMode != MeasureSpec.EXACTLY) {
+ val width = MeasureSpec.getSize(widthMeasureSpec)
+
+ var height = image.height * width / image.width
+ if (heightMode == MeasureSpec.AT_MOST) {
+ height = minOf(MeasureSpec.getSize(heightMeasureSpec), height)
+ }
+ setMeasuredDimension(width, height)
+ } else {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec)
+ }
+ }
+
+ override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
+ super.onSizeChanged(w, h, oldw, oldh)
+ bounds.set(0, 0, w, h)
+ paint.shader = LinearGradient(0f, 0f, w.toFloat(), 0f,
+ longArrayOf(
+ color(1f, 1f, 1f, 0f),
+ color(1f, 1f, 1f, .1f),
+ color(2f, 2f, 2f, .3f),
+ color(1f, 1f, 1f, .2f),
+ color(1f, 1f, 1f, 0f)
+ ),
+ floatArrayOf(.2f, .4f, .5f, .6f, .8f),
+ Shader.TileMode.CLAMP)
+ paint.blendMode = BlendMode.PLUS
+ }
+
+ override fun onDraw(canvas: Canvas) {
+ super.onDraw(canvas)
+
+ val image = image ?: return
+
+ canvas.drawBitmap(image, null, bounds, null)
+
+ canvas.save()
+ val frac = ((drawingTime % 2000) / 300f) - 1f
+ canvas.translate(width * frac, 0f)
+ canvas.rotate(-45f)
+ canvas.drawPaint(paint)
+ canvas.restore()
+ invalidate()
+ }
+} \ No newline at end of file
diff --git a/tests/AutoVerify/app2/src/com/android/test/autoverify/MainActivity.java b/tests/SilkFX/src/com/android/test/silkfx/hdr/GlowActivity.kt
index 09ef47212622..64dbb22ace43 100644
--- a/tests/AutoVerify/app2/src/com/android/test/autoverify/MainActivity.java
+++ b/tests/SilkFX/src/com/android/test/silkfx/hdr/GlowActivity.kt
@@ -13,3 +13,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
+package com.android.test.silkfx.hdr
+
+import android.os.Bundle
+import com.android.test.silkfx.R
+import com.android.test.silkfx.app.BaseDemoActivity
+
+class GlowActivity : BaseDemoActivity() {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.hdr_glows)
+ findViewById<GlowingCard>(R.id.card2)!!.setGlowIntensity(4f)
+ }
+}
diff --git a/tests/SilkFX/src/com/android/test/silkfx/hdr/GlowingCard.kt b/tests/SilkFX/src/com/android/test/silkfx/hdr/GlowingCard.kt
new file mode 100644
index 000000000000..b388bb659685
--- /dev/null
+++ b/tests/SilkFX/src/com/android/test/silkfx/hdr/GlowingCard.kt
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2020 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.test.silkfx.hdr
+
+import android.content.Context
+import android.graphics.Canvas
+import android.graphics.Color
+import android.graphics.LinearGradient
+import android.graphics.Paint
+import android.graphics.RectF
+import android.graphics.Shader
+import android.util.AttributeSet
+import com.android.test.silkfx.common.BaseDrawingView
+
+class GlowingCard : BaseDrawingView {
+
+ constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
+
+ val radius: Float
+ var COLOR_MAXIMIZER = 1f
+
+ init {
+ radius = 10.dp()
+ }
+
+ fun setGlowIntensity(multiplier: Float) {
+ COLOR_MAXIMIZER = multiplier
+ invalidate()
+ }
+
+ override fun setPressed(pressed: Boolean) {
+ super.setPressed(pressed)
+ invalidate()
+ }
+
+ override fun onDraw(canvas: Canvas) {
+ super.onDraw(canvas)
+ val paint = Paint()
+ paint.isAntiAlias = true
+ val rect = RectF(0f, 0f, width.toFloat(), height.toFloat())
+ val glowColor = Color.pack(.5f * COLOR_MAXIMIZER, .4f * COLOR_MAXIMIZER,
+ .75f * COLOR_MAXIMIZER, 1f, scRGB)
+
+ if (isPressed) {
+ paint.setColor(Color.pack(2f, 2f, 2f, 1f, scRGB))
+ paint.strokeWidth = 4.dp()
+ paint.style = Paint.Style.FILL
+ paint.shader = LinearGradient(rect.left, rect.bottom, rect.right, rect.top,
+ glowColor,
+ Color.pack(0f, 0f, 0f, 0f, scRGB),
+ Shader.TileMode.CLAMP)
+ canvas.drawRoundRect(rect, radius, radius, paint)
+ }
+
+ rect.inset(3.dp(), 3.dp())
+
+ paint.setColor(Color.pack(.14f, .14f, .14f, .8f, scRGB))
+ paint.style = Paint.Style.FILL
+ paint.shader = null
+ canvas.drawRoundRect(rect, radius, radius, paint)
+
+ rect.inset(5.dp(), 5.dp())
+ paint.textSize = 14.dp()
+ paint.isFakeBoldText = true
+
+ paint.color = Color.WHITE
+ canvas.drawText("glow = scRGB{${Color.red(glowColor)}, ${Color.green(glowColor)}, " +
+ "${Color.blue(glowColor)}}", rect.left, rect.centerY(), paint)
+ canvas.drawText("(press to activate)", rect.left, rect.bottom, paint)
+ }
+} \ No newline at end of file
diff --git a/tests/SilkFX/src/com/android/test/silkfx/hdr/RadialGlow.kt b/tests/SilkFX/src/com/android/test/silkfx/hdr/RadialGlow.kt
new file mode 100644
index 000000000000..599585e9d125
--- /dev/null
+++ b/tests/SilkFX/src/com/android/test/silkfx/hdr/RadialGlow.kt
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2020 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.test.silkfx.hdr
+
+import android.content.Context
+import android.graphics.Canvas
+import android.graphics.Paint
+import android.graphics.RadialGradient
+import android.graphics.RectF
+import android.graphics.Shader
+import android.util.AttributeSet
+import com.android.test.silkfx.common.BaseDrawingView
+import kotlin.math.min
+
+class RadialGlow : BaseDrawingView {
+
+ constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
+
+ var glowToggle = false
+
+ val glowColor = color(4f, 3.3f, 2.8f)
+ val bgColor = color(.15f, .15f, .15f)
+ val fgColor = color(.51f, .52f, .50f, .4f)
+ var glow: RadialGradient
+
+ init {
+ glow = RadialGradient(0f, 0f, 100.dp(), glowColor, bgColor, Shader.TileMode.CLAMP)
+ isClickable = true
+ setOnClickListener {
+ glowToggle = !glowToggle
+ invalidate()
+ }
+ }
+
+ override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
+ super.onSizeChanged(w, h, oldw, oldh)
+ glow = RadialGradient(0f, 0f,
+ min(w, h).toFloat(), glowColor, bgColor, Shader.TileMode.CLAMP)
+ }
+
+ override fun onDraw(canvas: Canvas) {
+ super.onDraw(canvas)
+ val radius = 10.dp()
+
+ val paint = Paint()
+ paint.isDither = true
+ paint.isAntiAlias = true
+ paint.textSize = 18.dp()
+ paint.textAlign = Paint.Align.CENTER
+
+ val rect = RectF(0f, 0f, width.toFloat(), height.toFloat())
+
+ paint.setColor(bgColor)
+ canvas.drawRoundRect(rect, radius, radius, paint)
+
+ if (glowToggle) {
+ paint.shader = glow
+ canvas.save()
+ val frac = (drawingTime % 5000) / 5000f
+ canvas.translate(rect.width() * frac, rect.height() - (rect.height() * frac))
+ canvas.drawPaint(paint)
+ canvas.restore()
+ paint.shader = null
+ invalidate()
+ }
+
+ paint.setColor(fgColor)
+ val innerRect = RectF(rect)
+ innerRect.inset(rect.width() / 4, rect.height() / 4)
+ canvas.drawRoundRect(innerRect, radius, radius, paint)
+
+ paint.setColor(color(1f, 1f, 1f))
+ canvas.drawText("Tap to toggle animation", rect.centerX(), innerRect.top - 4.dp(), paint)
+ canvas.drawText("Outside text", rect.centerX(), rect.bottom - 4.dp(), paint)
+ canvas.drawText("Inside text", innerRect.centerX(), innerRect.bottom - 4.dp(), paint)
+ }
+} \ No newline at end of file
diff --git a/tests/SilkFX/src/com/android/test/silkfx/materials/GlassActivity.kt b/tests/SilkFX/src/com/android/test/silkfx/materials/GlassActivity.kt
new file mode 100644
index 000000000000..dde245ff9baf
--- /dev/null
+++ b/tests/SilkFX/src/com/android/test/silkfx/materials/GlassActivity.kt
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2020 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.test.silkfx.materials
+
+import android.app.Activity
+import android.content.Intent
+import android.graphics.Bitmap
+import android.graphics.BitmapFactory
+import android.graphics.Color
+import android.os.Bundle
+import android.util.TypedValue
+import android.view.View
+import android.widget.ImageView
+import android.widget.SeekBar
+import android.widget.Switch
+import android.widget.TextView
+import com.android.test.silkfx.R
+
+class GlassActivity : Activity(), SeekBar.OnSeekBarChangeListener {
+
+ lateinit var backgroundButton1: ImageView
+ lateinit var backgroundButton2: ImageView
+ lateinit var backgroundButton3: ImageView
+ lateinit var backgroundView: ImageView
+ lateinit var materialView: GlassView
+ lateinit var lightMaterialSwitch: Switch
+ lateinit var noiseOpacitySeekBar: SeekBar
+ lateinit var materialOpacitySeekBar: SeekBar
+ lateinit var scrimOpacitySeekBar: SeekBar
+ lateinit var zoomSeekBar: SeekBar
+ lateinit var blurRadiusSeekBar: SeekBar
+ lateinit var noiseOpacityValue: TextView
+ lateinit var materialOpacityValue: TextView
+ lateinit var scrimOpacityValue: TextView
+ lateinit var blurRadiusValue: TextView
+ lateinit var zoomValue: TextView
+ lateinit var textOverlay: TextView
+
+ var background: Bitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888)
+ set(value) {
+ field = value
+ backgroundView.setImageBitmap(background)
+ materialView.backgroundBitmap = background
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_glass)
+ backgroundButton1 = requireViewById(R.id.background1)
+ backgroundButton2 = requireViewById(R.id.background2)
+ backgroundButton3 = requireViewById(R.id.background3)
+ backgroundView = requireViewById(R.id.background)
+ lightMaterialSwitch = requireViewById(R.id.lightMaterialSwitch)
+ materialView = requireViewById(R.id.materialView)
+ materialOpacitySeekBar = requireViewById(R.id.materialOpacity)
+ blurRadiusSeekBar = requireViewById(R.id.blurRadius)
+ zoomSeekBar = requireViewById(R.id.zoom)
+ noiseOpacitySeekBar = requireViewById(R.id.noiseOpacity)
+ scrimOpacitySeekBar = requireViewById(R.id.scrimOpacity)
+ noiseOpacityValue = requireViewById(R.id.noiseOpacityValue)
+ materialOpacityValue = requireViewById(R.id.materialOpacityValue)
+ scrimOpacityValue = requireViewById(R.id.scrimOpacityValue)
+ blurRadiusValue = requireViewById(R.id.blurRadiusValue)
+ zoomValue = requireViewById(R.id.zoomValue)
+ textOverlay = requireViewById(R.id.textOverlay)
+
+ background = BitmapFactory.decodeResource(resources, R.drawable.background1)
+
+ blurRadiusSeekBar.setOnSeekBarChangeListener(this)
+ materialOpacitySeekBar.setOnSeekBarChangeListener(this)
+ noiseOpacitySeekBar.setOnSeekBarChangeListener(this)
+ scrimOpacitySeekBar.setOnSeekBarChangeListener(this)
+
+ arrayOf(blurRadiusSeekBar, materialOpacitySeekBar, noiseOpacitySeekBar,
+ scrimOpacitySeekBar, zoomSeekBar).forEach {
+ it.setOnSeekBarChangeListener(this)
+ onProgressChanged(it, it.progress, fromUser = false)
+ }
+
+ lightMaterialSwitch.setOnCheckedChangeListener { _, isChecked ->
+ materialView.color = if (isChecked) Color.WHITE else Color.BLACK
+ textOverlay.setTextColor(if (isChecked) Color.BLACK else Color.WHITE)
+ }
+ }
+
+ override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
+ when (seekBar) {
+ blurRadiusSeekBar -> {
+ materialView.blurRadius = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
+ progress.toFloat(), resources.displayMetrics)
+ blurRadiusValue.text = progress.toString()
+ }
+ materialOpacitySeekBar -> {
+ materialView.materialOpacity = progress / seekBar.max.toFloat()
+ materialOpacityValue.text = progress.toString()
+ }
+ noiseOpacitySeekBar -> {
+ materialView.noiseOpacity = progress / seekBar.max.toFloat()
+ noiseOpacityValue.text = progress.toString()
+ }
+ scrimOpacitySeekBar -> {
+ materialView.scrimOpacity = progress / seekBar.max.toFloat()
+ scrimOpacityValue.text = progress.toString()
+ }
+ zoomSeekBar -> {
+ materialView.zoom = progress / seekBar.max.toFloat()
+ zoomValue.text = progress.toString()
+ }
+ else -> throw IllegalArgumentException("Unknown seek bar")
+ }
+ }
+
+ override fun onStop() {
+ super.onStop()
+ materialView.resetGyroOffsets()
+ }
+
+ override fun onStartTrackingTouch(seekBar: SeekBar?) {}
+ override fun onStopTrackingTouch(seekBar: SeekBar?) {}
+
+ fun onBackgroundClick(view: View) {
+ val resource = when (view) {
+ backgroundButton1 -> R.drawable.background1
+ backgroundButton2 -> R.drawable.background2
+ backgroundButton3 -> R.drawable.background3
+ else -> throw IllegalArgumentException("Invalid button")
+ }
+
+ background = BitmapFactory.decodeResource(resources, resource)
+ }
+
+ fun onPickImageClick(view: View) {
+ val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
+ addCategory(Intent.CATEGORY_OPENABLE)
+ type = "image/*"
+ }
+ startActivityForResult(intent, 0)
+ }
+
+ override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
+ if (resultCode === RESULT_OK) {
+ data?.data?.also {
+ contentResolver.openFileDescriptor(it, "r").let {
+ background = BitmapFactory.decodeFileDescriptor(it?.fileDescriptor)
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/tests/SilkFX/src/com/android/test/silkfx/materials/GlassView.kt b/tests/SilkFX/src/com/android/test/silkfx/materials/GlassView.kt
new file mode 100644
index 000000000000..2f2578b87f35
--- /dev/null
+++ b/tests/SilkFX/src/com/android/test/silkfx/materials/GlassView.kt
@@ -0,0 +1,230 @@
+/*
+ * Copyright (C) 2020 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.test.silkfx.materials
+
+import android.content.Context
+import android.graphics.Bitmap
+import android.graphics.BitmapFactory
+import android.graphics.BitmapShader
+import android.graphics.BlendMode
+import android.graphics.Canvas
+import android.graphics.Color
+import android.graphics.Outline
+import android.graphics.Paint
+import android.graphics.Rect
+import android.graphics.RenderEffect
+import android.graphics.RenderNode
+import android.graphics.Shader
+import android.hardware.Sensor
+import android.hardware.SensorEvent
+import android.hardware.SensorEventListener
+import android.hardware.SensorManager
+import android.util.AttributeSet
+import android.view.View
+import android.view.ViewOutlineProvider
+import android.widget.FrameLayout
+import com.android.test.silkfx.R
+import kotlin.math.sin
+import kotlin.math.sqrt
+
+class GlassView(context: Context, attributeSet: AttributeSet) : FrameLayout(context, attributeSet) {
+
+ private val textureTranslationMultiplier = 200f
+
+ private var gyroXRotation = 0f
+ private var gyroYRotation = 0f
+
+ private var noise = BitmapFactory.decodeResource(resources, R.drawable.noise)
+ private var materialPaint = Paint()
+ private var scrimPaint = Paint()
+ private var noisePaint = Paint()
+ private var blurPaint = Paint()
+
+ private val src = Rect()
+ private val dst = Rect()
+
+ private val sensorManager = context.getSystemService(SensorManager::class.java)
+ private val sensorListener = object : SensorEventListener {
+
+ // Constant to convert nanoseconds to seconds.
+ private val NS2S = 1.0f / 1000000000.0f
+ private val EPSILON = 0.000001f
+ private var timestamp: Float = 0f
+
+ override fun onSensorChanged(event: SensorEvent?) {
+ // This timestep's delta rotation to be multiplied by the current rotation
+ // after computing it from the gyro sample data.
+ if (timestamp != 0f && event != null) {
+ val dT = (event.timestamp - timestamp) * NS2S
+ // Axis of the rotation sample, not normalized yet.
+ var axisX: Float = event.values[0]
+ var axisY: Float = event.values[1]
+ var axisZ: Float = event.values[2]
+
+ // Calculate the angular speed of the sample
+ val omegaMagnitude: Float = sqrt(axisX * axisX + axisY * axisY + axisZ * axisZ)
+
+ // Normalize the rotation vector if it's big enough to get the axis
+ // (that is, EPSILON should represent your maximum allowable margin of error)
+ if (omegaMagnitude > EPSILON) {
+ axisX /= omegaMagnitude
+ axisY /= omegaMagnitude
+ axisZ /= omegaMagnitude
+ }
+
+ // Integrate around this axis with the angular speed by the timestep
+ // in order to get a delta rotation from this sample over the timestep
+ // We will convert this axis-angle representation of the delta rotation
+ // into a quaternion before turning it into the rotation matrix.
+ val thetaOverTwo: Float = omegaMagnitude * dT / 2.0f
+ val sinThetaOverTwo: Float = sin(thetaOverTwo)
+ gyroXRotation += sinThetaOverTwo * axisX
+ gyroYRotation += sinThetaOverTwo * axisY
+
+ invalidate()
+ }
+ timestamp = event?.timestamp?.toFloat() ?: 0f
+ }
+
+ override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) { }
+ }
+
+ var backgroundBitmap: Bitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888)
+ set(value) {
+ field = value
+ invalidate()
+ }
+
+ var noiseOpacity = 0.0f
+ set(value) {
+ field = value
+ noisePaint.alpha = (value * 255).toInt()
+ invalidate()
+ }
+
+ var materialOpacity = 0.0f
+ set(value) {
+ field = value
+ materialPaint.alpha = (value * 255).toInt()
+ invalidate()
+ }
+
+ var scrimOpacity = 0.5f
+ set(value) {
+ field = value
+ scrimPaint.alpha = (value * 255).toInt()
+ invalidate()
+ }
+
+ var zoom = 0.0f
+ set(value) {
+ field = value
+ invalidate()
+ }
+
+ var color = Color.BLACK
+ set(value) {
+ field = value
+ var alpha = materialPaint.alpha
+ materialPaint.color = color
+ materialPaint.alpha = alpha
+
+ alpha = scrimPaint.alpha
+ scrimPaint.color = color
+ scrimPaint.alpha = alpha
+ invalidate()
+ }
+
+ var blurRadius = 150f
+ set(value) {
+ field = value
+ renderNode.setRenderEffect(
+ RenderEffect.createBlurEffect(value, value, Shader.TileMode.CLAMP))
+ invalidate()
+ }
+
+ private var renderNodeIsDirty = true
+ private val renderNode = RenderNode("GlassRenderNode")
+
+ override fun invalidate() {
+ renderNodeIsDirty = true
+ super.invalidate()
+ }
+
+ init {
+ setWillNotDraw(false)
+ materialPaint.blendMode = BlendMode.SOFT_LIGHT
+ noisePaint.blendMode = BlendMode.SOFT_LIGHT
+ noisePaint.shader = BitmapShader(noise, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT)
+ scrimPaint.alpha = (scrimOpacity * 255).toInt()
+ noisePaint.alpha = (noiseOpacity * 255).toInt()
+ materialPaint.alpha = (materialOpacity * 255).toInt()
+ outlineProvider = object : ViewOutlineProvider() {
+ override fun getOutline(view: View?, outline: Outline?) {
+ outline?.setRoundRect(Rect(0, 0, width, height), 100f)
+ }
+ }
+ clipToOutline = true
+ }
+
+ override fun onAttachedToWindow() {
+ sensorManager?.getSensorList(Sensor.TYPE_GYROSCOPE)?.firstOrNull().let {
+ sensorManager?.registerListener(sensorListener, it, SensorManager.SENSOR_DELAY_GAME)
+ }
+ }
+
+ override fun onDetachedFromWindow() {
+ sensorManager?.unregisterListener(sensorListener)
+ }
+
+ override fun onDraw(canvas: Canvas?) {
+ updateGlassRenderNode()
+ canvas?.drawRenderNode(renderNode)
+ }
+
+ fun resetGyroOffsets() {
+ gyroXRotation = 0f
+ gyroYRotation = 0f
+ invalidate()
+ }
+
+ private fun updateGlassRenderNode() {
+ if (renderNodeIsDirty) {
+ renderNode.setPosition(0, 0, getWidth(), getHeight())
+
+ val canvas = renderNode.beginRecording()
+
+ src.set(-width / 2, -height / 2, width / 2, height / 2)
+ src.scale(1.0f + zoom)
+ val centerX = left + width / 2
+ val centerY = top + height / 2
+ val textureXOffset = (textureTranslationMultiplier * gyroYRotation).toInt()
+ val textureYOffset = (textureTranslationMultiplier * gyroXRotation).toInt()
+ src.set(src.left + centerX + textureXOffset, src.top + centerY + textureYOffset,
+ src.right + centerX + textureXOffset, src.bottom + centerY + textureYOffset)
+
+ dst.set(0, 0, width, height)
+ canvas.drawBitmap(backgroundBitmap, src, dst, blurPaint)
+ canvas.drawRect(dst, materialPaint)
+ canvas.drawRect(dst, noisePaint)
+ canvas.drawRect(dst, scrimPaint)
+
+ renderNode.endRecording()
+
+ renderNodeIsDirty = false
+ }
+ }
+} \ No newline at end of file
diff --git a/tests/SmokeTest/AndroidManifest.xml b/tests/SmokeTest/AndroidManifest.xml
index f141bdcc704f..57f0431ad2e3 100644
--- a/tests/SmokeTest/AndroidManifest.xml
+++ b/tests/SmokeTest/AndroidManifest.xml
@@ -15,18 +15,19 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.smoketest">
+ package="com.android.smoketest">
<application>
- <uses-library android:name="android.test.runner" />
- <activity android:name=".SmokeTestActivity"
- android:label="Smoke Tests">
+ <uses-library android:name="android.test.runner"/>
+ <activity android:name=".SmokeTestActivity"
+ android:label="Smoke Tests"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.TEST"/>
</intent-filter>
</activity>
</application>
-
+
</manifest>
diff --git a/tests/SmokeTestApps/AndroidManifest.xml b/tests/SmokeTestApps/AndroidManifest.xml
index 0f20107f60d1..89e63b1a4198 100644
--- a/tests/SmokeTestApps/AndroidManifest.xml
+++ b/tests/SmokeTestApps/AndroidManifest.xml
@@ -15,30 +15,33 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.smoketest.triggers">
+ package="com.android.smoketest.triggers">
<application android:label="something">
<activity android:name=".CrashyApp"
- android:label="Test Crashy App">
+ android:label="Test Crashy App"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:name=".CrashyApp2"
- android:label="Test Crashy App2">
+ android:label="Test Crashy App2"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:name=".UnresponsiveApp"
- android:label="Test Unresponsive App">
+ android:label="Test Unresponsive App"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
diff --git a/tests/SoundTriggerTestApp/AndroidManifest.xml b/tests/SoundTriggerTestApp/AndroidManifest.xml
index 87f3e92b3a60..587a25dd71bc 100644
--- a/tests/SoundTriggerTestApp/AndroidManifest.xml
+++ b/tests/SoundTriggerTestApp/AndroidManifest.xml
@@ -1,27 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.test.soundtrigger">
- <uses-permission android:name="android.permission.CAPTURE_AUDIO_HOTWORD" />
- <uses-permission android:name="android.permission.MANAGE_SOUND_TRIGGER" />
- <uses-permission android:name="android.permission.RECORD_AUDIO" />
- <uses-permission android:name="android.permission.WAKE_LOCK" />
+ package="com.android.test.soundtrigger">
+ <uses-permission android:name="android.permission.CAPTURE_AUDIO_HOTWORD"/>
+ <uses-permission android:name="android.permission.MANAGE_SOUND_TRIGGER"/>
+ <uses-permission android:name="android.permission.RECORD_AUDIO"/>
+ <uses-permission android:name="android.permission.WAKE_LOCK"/>
<application>
- <activity
- android:name=".SoundTriggerTestActivity"
- android:label="SoundTrigger Test Application"
- android:screenOrientation="portrait"
- android:theme="@android:style/Theme.Material">
+ <activity android:name=".SoundTriggerTestActivity"
+ android:label="SoundTrigger Test Application"
+ android:screenOrientation="portrait"
+ android:theme="@android:style/Theme.Material"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <service
- android:name=".SoundTriggerTestService"
- android:stopWithTask="false"
- android:exported="true">
+ <service android:name=".SoundTriggerTestService"
+ android:stopWithTask="false"
+ android:exported="true">
<intent-filter>
- <action android:name="com.android.intent.action.MANAGE_SOUND_TRIGGER" />
+ <action android:name="com.android.intent.action.MANAGE_SOUND_TRIGGER"/>
</intent-filter>
</service>
</application>
diff --git a/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerTestService.java b/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerTestService.java
index 9324ba0b8b72..380e29984c63 100644
--- a/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerTestService.java
+++ b/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerTestService.java
@@ -23,7 +23,6 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
-import android.hardware.soundtrigger.SoundTrigger.GenericSoundModel;
import android.media.AudioAttributes;
import android.media.AudioFormat;
import android.media.AudioManager;
@@ -31,6 +30,7 @@ import android.media.AudioRecord;
import android.media.AudioTrack;
import android.media.MediaPlayer;
import android.media.soundtrigger.SoundTriggerDetector;
+import android.media.soundtrigger.SoundTriggerManager;
import android.net.Uri;
import android.os.Binder;
import android.os.IBinder;
@@ -232,8 +232,8 @@ public class SoundTriggerTestService extends Service {
public AudioTrack captureAudioTrack;
}
- private GenericSoundModel createNewSoundModel(ModelInfo modelInfo) {
- return new GenericSoundModel(modelInfo.modelUuid, modelInfo.vendorUuid,
+ private SoundTriggerManager.Model createNewSoundModel(ModelInfo modelInfo) {
+ return SoundTriggerManager.Model.create(modelInfo.modelUuid, modelInfo.vendorUuid,
modelInfo.modelData);
}
@@ -246,16 +246,16 @@ public class SoundTriggerTestService extends Service {
postMessage("Loading model: " + modelInfo.name);
- GenericSoundModel soundModel = createNewSoundModel(modelInfo);
+ SoundTriggerManager.Model soundModel = createNewSoundModel(modelInfo);
boolean status = mSoundTriggerUtil.addOrUpdateSoundModel(soundModel);
if (status) {
postToast("Successfully loaded " + modelInfo.name + ", UUID="
- + soundModel.getUuid());
+ + soundModel.getModelUuid());
setModelState(modelInfo, "Loaded");
} else {
postErrorToast("Failed to load " + modelInfo.name + ", UUID="
- + soundModel.getUuid() + "!");
+ + soundModel.getModelUuid() + "!");
setModelState(modelInfo, "Failed to load");
}
}
@@ -269,7 +269,7 @@ public class SoundTriggerTestService extends Service {
postMessage("Unloading model: " + modelInfo.name);
- GenericSoundModel soundModel = mSoundTriggerUtil.getSoundModel(modelUuid);
+ SoundTriggerManager.Model soundModel = mSoundTriggerUtil.getSoundModel(modelUuid);
if (soundModel == null) {
postErrorToast("Sound model not found for " + modelInfo.name + "!");
return;
@@ -278,11 +278,11 @@ public class SoundTriggerTestService extends Service {
boolean status = mSoundTriggerUtil.deleteSoundModel(modelUuid);
if (status) {
postToast("Successfully unloaded " + modelInfo.name + ", UUID="
- + soundModel.getUuid());
+ + soundModel.getModelUuid());
setModelState(modelInfo, "Unloaded");
} else {
postErrorToast("Failed to unload " +
- modelInfo.name + ", UUID=" + soundModel.getUuid() + "!");
+ modelInfo.name + ", UUID=" + soundModel.getModelUuid() + "!");
setModelState(modelInfo, "Failed to unload");
}
}
@@ -294,12 +294,12 @@ public class SoundTriggerTestService extends Service {
return;
}
postMessage("Reloading model: " + modelInfo.name);
- GenericSoundModel soundModel = mSoundTriggerUtil.getSoundModel(modelUuid);
+ SoundTriggerManager.Model soundModel = mSoundTriggerUtil.getSoundModel(modelUuid);
if (soundModel == null) {
postErrorToast("Sound model not found for " + modelInfo.name + "!");
return;
}
- GenericSoundModel updated = createNewSoundModel(modelInfo);
+ SoundTriggerManager.Model updated = createNewSoundModel(modelInfo);
boolean status = mSoundTriggerUtil.addOrUpdateSoundModel(updated);
if (status) {
postToast("Successfully reloaded " + modelInfo.name + ", UUID="
diff --git a/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerUtil.java b/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerUtil.java
index 6b89b62bb1e3..cfe8c855ac81 100644
--- a/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerUtil.java
+++ b/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerUtil.java
@@ -18,7 +18,6 @@ package com.android.test.soundtrigger;
import android.annotation.Nullable;
import android.content.Context;
-import android.hardware.soundtrigger.SoundTrigger.GenericSoundModel;
import android.media.soundtrigger.SoundTriggerDetector;
import android.media.soundtrigger.SoundTriggerManager;
import android.os.RemoteException;
@@ -37,13 +36,10 @@ import java.util.UUID;
public class SoundTriggerUtil {
private static final String TAG = "SoundTriggerTestUtil";
- private final ISoundTriggerService mSoundTriggerService;
private final SoundTriggerManager mSoundTriggerManager;
private final Context mContext;
public SoundTriggerUtil(Context context) {
- mSoundTriggerService = ISoundTriggerService.Stub.asInterface(
- ServiceManager.getService(Context.SOUND_TRIGGER_SERVICE));
mSoundTriggerManager = (SoundTriggerManager) context.getSystemService(
Context.SOUND_TRIGGER_SERVICE);
mContext = context;
@@ -55,15 +51,11 @@ public class SoundTriggerUtil {
*
* @param soundModel The sound model to add/update.
*/
- public boolean addOrUpdateSoundModel(GenericSoundModel soundModel) {
- try {
- if (soundModel == null) {
- throw new RuntimeException("Bad sound model");
- }
- mSoundTriggerService.updateSoundModel(soundModel);
- } catch (RemoteException e) {
- Log.e(TAG, "RemoteException in updateSoundModel", e);
+ public boolean addOrUpdateSoundModel(SoundTriggerManager.Model soundModel) {
+ if (soundModel == null) {
+ throw new RuntimeException("Bad sound model");
}
+ mSoundTriggerManager.updateModel(soundModel);
return true;
}
@@ -71,19 +63,15 @@ public class SoundTriggerUtil {
* Gets the sound model for the given keyphrase, null if none exists.
* If a sound model for a given keyphrase exists, and it needs to be updated,
* it should be obtained using this method, updated and then passed in to
- * {@link #addOrUpdateSoundModel(GenericSoundModel)} without changing the IDs.
+ * {@link #addOrUpdateSoundModel(SoundTriggerManager.Model)} without changing the IDs.
*
* @param modelId The model ID to look-up the sound model for.
* @return The sound model if one was found, null otherwise.
*/
@Nullable
- public GenericSoundModel getSoundModel(UUID modelId) {
- GenericSoundModel model = null;
- try {
- model = mSoundTriggerService.getSoundModel(new ParcelUuid(modelId));
- } catch (RemoteException e) {
- Log.e(TAG, "RemoteException in updateKeyphraseSoundModel");
- }
+ public SoundTriggerManager.Model getSoundModel(UUID modelId) {
+ SoundTriggerManager.Model model = null;
+ model = mSoundTriggerManager.getModel(modelId);
if (model == null) {
Log.w(TAG, "No models present for the given keyphrase ID");
@@ -100,12 +88,7 @@ public class SoundTriggerUtil {
* @return {@code true} if the call succeeds, {@code false} otherwise.
*/
public boolean deleteSoundModel(UUID modelId) {
- try {
- mSoundTriggerService.deleteSoundModel(new ParcelUuid(modelId));
- } catch (RemoteException e) {
- Log.e(TAG, "RemoteException in deleteSoundModel");
- return false;
- }
+ mSoundTriggerManager.deleteModel(modelId);
return true;
}
diff --git a/tests/Split/AndroidManifest.xml b/tests/Split/AndroidManifest.xml
index 0de8344077f6..e0365273107e 100644
--- a/tests/Split/AndroidManifest.xml
+++ b/tests/Split/AndroidManifest.xml
@@ -15,13 +15,14 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.example.split">
+ package="com.android.example.split">
<application android:label="@string/app_title"
- android:icon="@mipmap/ic_app">
- <activity android:name="ActivityMain">
+ android:icon="@mipmap/ic_app">
+ <activity android:name="ActivityMain"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
diff --git a/tests/StagedInstallTest/Android.bp b/tests/StagedInstallTest/Android.bp
index 086ef95877e6..7a564fcaa99e 100644
--- a/tests/StagedInstallTest/Android.bp
+++ b/tests/StagedInstallTest/Android.bp
@@ -31,7 +31,11 @@ android_test_helper_app {
],
test_suites: ["general-tests"],
java_resources: [
+ ":com.android.apex.apkrollback.test_v2",
":StagedInstallTestApexV2",
+ ":StagedInstallTestApexV2_WrongSha",
+ ":test.rebootless_apex_v1",
+ ":test.rebootless_apex_v2",
],
platform_apis: true,
}
@@ -50,8 +54,11 @@ java_test_host {
"cts-install-lib-host",
],
data: [
+ ":com.android.apex.apkrollback.test_v1",
":StagedInstallTestApexV2",
+ ":StagedInstallTestApexV2_WrongSha",
":TestAppAv1",
+ ":test.rebootless_apex_v1",
],
test_suites: ["general-tests"],
test_config: "StagedInstallInternalTest.xml",
diff --git a/tests/StagedInstallTest/TEST_MAPPING b/tests/StagedInstallTest/TEST_MAPPING
index 73094c5db06b..cc31f2c98425 100644
--- a/tests/StagedInstallTest/TEST_MAPPING
+++ b/tests/StagedInstallTest/TEST_MAPPING
@@ -1,5 +1,5 @@
{
- "presubmit": [
+ "presubmit-large": [
{
"name": "StagedInstallInternalTest",
"options": [
diff --git a/tests/StagedInstallTest/app/AndroidManifest.xml b/tests/StagedInstallTest/app/AndroidManifest.xml
index a678f1ec3691..d7ac9d0f9ce4 100644
--- a/tests/StagedInstallTest/app/AndroidManifest.xml
+++ b/tests/StagedInstallTest/app/AndroidManifest.xml
@@ -20,8 +20,6 @@
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
<application>
- <receiver android:name="com.android.cts.install.lib.LocalIntentSender"
- android:exported="true" />
<uses-library android:name="android.test.runner" />
</application>
diff --git a/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java b/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java
index a0f4e0ad7e6a..c610641932df 100644
--- a/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java
+++ b/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java
@@ -29,9 +29,12 @@ import static org.mockito.Mockito.verify;
import android.Manifest;
import android.content.pm.ApexStagedEvent;
+import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManagerNative;
import android.content.pm.IStagedApexObserver;
+import android.content.pm.PackageInfo;
import android.content.pm.PackageInstaller;
+import android.content.pm.PackageManager;
import android.content.pm.StagedApexInfo;
import android.os.IBinder;
import android.os.ServiceManager;
@@ -61,9 +64,12 @@ import java.util.function.Consumer;
@RunWith(JUnit4.class)
public class StagedInstallInternalTest {
-
- private static final String TAG = StagedInstallInternalTest.class.getSimpleName();
-
+ private static final String APK_IN_APEX_TESTAPEX_NAME = "com.android.apex.apkrollback.test";
+ private static final TestApp TEST_APEX_WITH_APK_V2 = new TestApp("TestApexWithApkV2",
+ APK_IN_APEX_TESTAPEX_NAME, 2, /*isApex*/true, APK_IN_APEX_TESTAPEX_NAME + "_v2.apex");
+ private static final TestApp APEX_WRONG_SHA_V2 = new TestApp(
+ "ApexWrongSha2", SHIM_APEX_PACKAGE_NAME, 2, /* isApex= */ true,
+ "com.android.apex.cts.shim.v2_wrong_sha.apex");
private static final TestApp APEX_V2 = new TestApp(
"ApexV2", SHIM_APEX_PACKAGE_NAME, 2, /* isApex= */ true,
"com.android.apex.cts.shim.v2.apex");
@@ -100,6 +106,24 @@ public class StagedInstallInternalTest {
}
@Test
+ public void testDuplicateApkInApexShouldFail_Commit() throws Exception {
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
+ // Duplicate packages(TestApp.A) in TEST_APEX_WITH_APK_V2(apk-in-apex) and TestApp.A2(apk)
+ // should fail to install.
+ int sessionId = Install.multi(TEST_APEX_WITH_APK_V2, TestApp.A2).setStaged().commit();
+ storeSessionId(sessionId);
+ }
+
+ @Test
+ public void testDuplicateApkInApexShouldFail_Verify() throws Exception {
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
+ int sessionId = retrieveLastSessionId();
+ PackageInstaller.SessionInfo info =
+ InstallUtils.getPackageInstaller().getSessionInfo(sessionId);
+ assertThat(info.isStagedSessionFailed()).isTrue();
+ }
+
+ @Test
public void testSystemServerRestartDoesNotAffectStagedSessions_Commit() throws Exception {
int sessionId = Install.single(TestApp.A1).setStaged().commit();
assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(-1);
@@ -115,6 +139,38 @@ public class StagedInstallInternalTest {
}
@Test
+ public void testAbandonStagedSessionShouldCleanUp() throws Exception {
+ int id1 = Install.single(TestApp.A1).setStaged().createSession();
+ InstallUtils.getPackageInstaller().abandonSession(id1);
+ int id2 = Install.multi(TestApp.A1).setStaged().createSession();
+ InstallUtils.getPackageInstaller().abandonSession(id2);
+ int id3 = Install.single(TestApp.A1).setStaged().commit();
+ InstallUtils.getPackageInstaller().abandonSession(id3);
+ int id4 = Install.multi(TestApp.A1).setStaged().commit();
+ InstallUtils.getPackageInstaller().abandonSession(id4);
+ }
+
+ @Test
+ public void testStagedSessionShouldCleanUpOnVerificationFailure() throws Exception {
+ InstallUtils.commitExpectingFailure(AssertionError.class, "apexd verification failed",
+ Install.single(APEX_WRONG_SHA_V2).setStaged());
+ }
+
+ @Test
+ public void testStagedSessionShouldCleanUpOnOnSuccess_Commit() throws Exception {
+ int sessionId = Install.single(TestApp.A1).setStaged().commit();
+ storeSessionId(sessionId);
+ }
+
+ @Test
+ public void testStagedSessionShouldCleanUpOnOnSuccess_Verify() throws Exception {
+ int sessionId = retrieveLastSessionId();
+ PackageInstaller.SessionInfo info = InstallUtils.getStagedSessionInfo(sessionId);
+ assertThat(info).isNotNull();
+ assertThat(info.isStagedSessionApplied()).isTrue();
+ }
+
+ @Test
public void testStagedInstallationShouldCleanUpOnValidationFailure() throws Exception {
InstallUtils.commitExpectingFailure(AssertionError.class, "INSTALL_FAILED_INVALID_APK",
Install.single(TestApp.AIncompleteSplit).setStaged());
@@ -128,6 +184,239 @@ public class StagedInstallInternalTest {
}
@Test
+ public void testFailStagedSessionIfStagingDirectoryDeleted_Commit() throws Exception {
+ int sessionId = Install.multi(TestApp.A1, TestApp.Apex1).setStaged().commit();
+ assertSessionReady(sessionId);
+ storeSessionId(sessionId);
+ }
+
+ @Test
+ public void testFailStagedSessionIfStagingDirectoryDeleted_Verify() throws Exception {
+ int sessionId = retrieveLastSessionId();
+ PackageInstaller.SessionInfo info =
+ InstallUtils.getPackageInstaller().getSessionInfo(sessionId);
+ assertThat(info.isStagedSessionFailed()).isTrue();
+ }
+
+ @Test
+ public void testApexActivationFailureIsCapturedInSession_Commit() throws Exception {
+ int sessionId = Install.single(TestApp.Apex1).setStaged().commit();
+ assertSessionReady(sessionId);
+ storeSessionId(sessionId);
+ }
+
+ @Test
+ public void testApexActivationFailureIsCapturedInSession_Verify() throws Exception {
+ int sessionId = retrieveLastSessionId();
+ assertSessionFailedWithMessage(sessionId, "has unexpected SHA512 hash");
+ }
+
+ @Test
+ public void testActiveApexIsRevertedOnCheckpointRollback_Prepare() throws Exception {
+ int sessionId = Install.single(TestApp.Apex2).setStaged().commit();
+ assertSessionReady(sessionId);
+ storeSessionId(sessionId);
+ }
+
+ @Test
+ public void testActiveApexIsRevertedOnCheckpointRollback_Commit() throws Exception {
+ // Verify apex installed during preparation was successful
+ int sessionId = retrieveLastSessionId();
+ assertSessionApplied(sessionId);
+ assertThat(InstallUtils.getInstalledVersion(SHIM_APEX_PACKAGE_NAME)).isEqualTo(2);
+ // Commit a new staged session
+ sessionId = Install.single(TestApp.Apex3).setStaged().commit();
+ assertSessionReady(sessionId);
+ storeSessionId(sessionId);
+ }
+
+ @Test
+ public void testActiveApexIsRevertedOnCheckpointRollback_VerifyPostReboot() throws Exception {
+ int sessionId = retrieveLastSessionId();
+ assertSessionFailed(sessionId);
+ assertThat(InstallUtils.getInstalledVersion(SHIM_APEX_PACKAGE_NAME)).isEqualTo(2);
+ }
+
+ @Test
+ public void testApexIsNotActivatedIfNotInCheckpointMode_Commit() throws Exception {
+ int sessionId = Install.single(TestApp.Apex2).setStaged().commit();
+ assertSessionReady(sessionId);
+ storeSessionId(sessionId);
+ assertThat(InstallUtils.getInstalledVersion(SHIM_APEX_PACKAGE_NAME)).isEqualTo(1);
+ }
+
+ @Test
+ public void testApexIsNotActivatedIfNotInCheckpointMode_VerifyPostReboot() throws Exception {
+ int sessionId = retrieveLastSessionId();
+ assertSessionFailed(sessionId);
+ assertThat(InstallUtils.getInstalledVersion(SHIM_APEX_PACKAGE_NAME)).isEqualTo(1);
+ }
+
+ @Test
+ public void testApexInstallerNotInAllowListCanNotInstall_staged() throws Exception {
+ assertThat(InstallUtils.getInstalledVersion(SHIM_APEX_PACKAGE_NAME)).isEqualTo(1);
+ // We don't really care which APEX we are trying to install here, since the session creation
+ // should fail immediately.
+ InstallUtils.commitExpectingFailure(
+ SecurityException.class,
+ "Installer not allowed to commit staged install",
+ Install.single(APEX_WRONG_SHA_V2).setBypassStangedInstallerCheck(false)
+ .setStaged());
+ }
+
+ @Test
+ public void testApexInstallerNotInAllowListCanNotInstall_nonStaged() throws Exception {
+ assertThat(InstallUtils.getInstalledVersion(SHIM_APEX_PACKAGE_NAME)).isEqualTo(1);
+ // We don't really care which APEX we are trying to install here, since the session creation
+ // should fail immediately.
+ InstallUtils.commitExpectingFailure(
+ SecurityException.class,
+ "Installer not allowed to commit non-staged APEX install",
+ Install.single(APEX_WRONG_SHA_V2).setBypassStangedInstallerCheck(false));
+ }
+
+ @Test
+ public void testApexNotInAllowListCanNotInstall_staged() throws Exception {
+ assertThat(InstallUtils.getInstalledVersion("test.apex.rebootless")).isEqualTo(1);
+ TestApp apex = new TestApp("apex", "test.apex.rebootless", 2,
+ /* isApex= */ true, "test.rebootless_apex_v2.apex");
+ InstallUtils.commitExpectingFailure(
+ AssertionError.class,
+ "Update of APEX package test.apex.rebootless is not allowed "
+ + "for com.android.tests.stagedinstallinternal",
+ Install.single(apex).setBypassAllowedApexUpdateCheck(false).setStaged());
+ }
+
+ @Test
+ public void testApexNotInAllowListCanNotInstall_nonStaged() throws Exception {
+ assertThat(InstallUtils.getInstalledVersion("test.apex.rebootless")).isEqualTo(1);
+ TestApp apex = new TestApp("apex", "test.apex.rebootless", 2,
+ /* isApex= */ true, "test.rebootless_apex_v2.apex");
+ InstallUtils.commitExpectingFailure(
+ AssertionError.class,
+ "Update of APEX package test.apex.rebootless is not allowed "
+ + "for com.android.tests.stagedinstallinternal",
+ Install.single(apex).setBypassAllowedApexUpdateCheck(false));
+ }
+
+ @Test
+ public void testVendorApexWrongInstaller_staged() throws Exception {
+ assertThat(InstallUtils.getInstalledVersion("test.apex.rebootless")).isEqualTo(1);
+ TestApp apex = new TestApp("apex", "test.apex.rebootless", 2,
+ /* isApex= */ true, "test.rebootless_apex_v2.apex");
+ InstallUtils.commitExpectingFailure(
+ AssertionError.class,
+ "Update of APEX package test.apex.rebootless is not allowed "
+ + "for com.android.tests.stagedinstallinternal",
+ Install.single(apex).setBypassAllowedApexUpdateCheck(false).setStaged());
+ }
+
+ @Test
+ public void testVendorApexWrongInstaller_nonStaged() throws Exception {
+ assertThat(InstallUtils.getInstalledVersion("test.apex.rebootless")).isEqualTo(1);
+ TestApp apex = new TestApp("apex", "test.apex.rebootless", 2,
+ /* isApex= */ true, "test.rebootless_apex_v2.apex");
+ InstallUtils.commitExpectingFailure(
+ AssertionError.class,
+ "Update of APEX package test.apex.rebootless is not allowed "
+ + "for com.android.tests.stagedinstallinternal",
+ Install.single(apex).setBypassAllowedApexUpdateCheck(false));
+ }
+
+ @Test
+ public void testVendorApexCorrectInstaller_staged() throws Exception {
+ assertThat(InstallUtils.getInstalledVersion("test.apex.rebootless")).isEqualTo(1);
+ TestApp apex = new TestApp("apex", "test.apex.rebootless", 2,
+ /* isApex= */ true, "test.rebootless_apex_v2.apex");
+ int sessionId =
+ Install.single(apex).setBypassAllowedApexUpdateCheck(false).setStaged().commit();
+ InstallUtils.getPackageInstaller().abandonSession(sessionId);
+ }
+
+ @Test
+ public void testVendorApexCorrectInstaller_nonStaged() throws Exception {
+ assertThat(InstallUtils.getInstalledVersion("test.apex.rebootless")).isEqualTo(1);
+ TestApp apex = new TestApp("apex", "test.apex.rebootless", 2,
+ /* isApex= */ true, "test.rebootless_apex_v2.apex");
+ Install.single(apex).setBypassAllowedApexUpdateCheck(false).commit();
+ assertThat(InstallUtils.getInstalledVersion("test.apex.rebootless")).isEqualTo(2);
+ }
+
+ @Test
+ public void testRebootlessUpdates() throws Exception {
+ InstallUtils.dropShellPermissionIdentity();
+ InstallUtils.adoptShellPermissionIdentity(Manifest.permission.INSTALL_PACKAGE_UPDATES);
+
+ final PackageManager pm =
+ InstrumentationRegistry.getInstrumentation().getContext().getPackageManager();
+ {
+ PackageInfo apex = pm.getPackageInfo("test.apex.rebootless", PackageManager.MATCH_APEX);
+ assertThat(apex.getLongVersionCode()).isEqualTo(1);
+ assertThat(apex.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM)
+ .isEqualTo(ApplicationInfo.FLAG_SYSTEM);
+ assertThat(apex.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED)
+ .isEqualTo(ApplicationInfo.FLAG_INSTALLED);
+ assertThat(apex.applicationInfo.sourceDir).startsWith("/system/apex");
+ }
+
+ TestApp apex1 = new TestApp("TestRebootlessApexV1", "test.apex.rebootless", 1,
+ /* isApex= */ true, "test.rebootless_apex_v1.apex");
+ Install.single(apex1).commit();
+
+ {
+ PackageInfo apex = pm.getPackageInfo("test.apex.rebootless", PackageManager.MATCH_APEX);
+ assertThat(apex.getLongVersionCode()).isEqualTo(1);
+ assertThat(apex.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM).isEqualTo(0);
+ assertThat(apex.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED)
+ .isEqualTo(ApplicationInfo.FLAG_INSTALLED);
+ assertThat(apex.applicationInfo.sourceDir).startsWith("/data/apex/active");
+ }
+ {
+ PackageInfo apex = pm.getPackageInfo("test.apex.rebootless",
+ PackageManager.MATCH_APEX | PackageManager.MATCH_FACTORY_ONLY);
+ assertThat(apex.getLongVersionCode()).isEqualTo(1);
+ assertThat(apex.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM)
+ .isEqualTo(ApplicationInfo.FLAG_SYSTEM);
+ assertThat(apex.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED).isEqualTo(0);
+ assertThat(apex.applicationInfo.sourceDir).startsWith("/system/apex");
+ }
+
+ TestApp apex2 = new TestApp("TestRebootlessApexV1", "test.apex.rebootless", 2,
+ /* isApex= */ true, "test.rebootless_apex_v2.apex");
+ Install.single(apex2).commit();
+
+ {
+ PackageInfo apex = pm.getPackageInfo("test.apex.rebootless", PackageManager.MATCH_APEX);
+ assertThat(apex.getLongVersionCode()).isEqualTo(2);
+ assertThat(apex.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM).isEqualTo(0);
+ assertThat(apex.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED)
+ .isEqualTo(ApplicationInfo.FLAG_INSTALLED);
+ assertThat(apex.applicationInfo.sourceDir).startsWith("/data/apex/active");
+ }
+ {
+ PackageInfo apex = pm.getPackageInfo("test.apex.rebootless",
+ PackageManager.MATCH_APEX | PackageManager.MATCH_FACTORY_ONLY);
+ assertThat(apex.getLongVersionCode()).isEqualTo(1);
+ assertThat(apex.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM)
+ .isEqualTo(ApplicationInfo.FLAG_SYSTEM);
+ assertThat(apex.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED).isEqualTo(0);
+ assertThat(apex.applicationInfo.sourceDir).startsWith("/system/apex");
+ }
+ }
+
+ @Test
+ public void testRebootlessUpdate_hasStagedSessionWithSameApex_fails() throws Exception {
+ assertThat(InstallUtils.getInstalledVersion(SHIM_APEX_PACKAGE_NAME)).isEqualTo(1);
+
+ int sessionId = Install.single(APEX_V2).setStaged().commit();
+ assertSessionReady(sessionId);
+ InstallUtils.commitExpectingFailure(
+ AssertionError.class,
+ "Staged session " + sessionId + " already contains " + SHIM_APEX_PACKAGE_NAME,
+ Install.single(APEX_V2));
+ }
+
+ @Test
public void testGetStagedModuleNames() throws Exception {
// Before staging a session
String[] result = getPackageManagerNative().getStagedApexModuleNames();
@@ -192,6 +481,24 @@ public class StagedInstallInternalTest {
assertThat(binder).isNotNull();
return IPackageManagerNative.Stub.asInterface(binder);
}
+ private static void assertSessionApplied(int sessionId) {
+ assertSessionState(sessionId, (session) -> {
+ assertThat(session.isStagedSessionApplied()).isTrue();
+ });
+ }
+
+ private static void assertSessionFailed(int sessionId) {
+ assertSessionState(sessionId, (session) -> {
+ assertThat(session.isStagedSessionFailed()).isTrue();
+ });
+ }
+
+ private static void assertSessionFailedWithMessage(int sessionId, String msg) {
+ assertSessionState(sessionId, (session) -> {
+ assertThat(session.isStagedSessionFailed()).isTrue();
+ assertThat(session.getStagedSessionErrorMessage()).contains(msg);
+ });
+ }
private static void assertSessionReady(int sessionId) {
assertSessionState(sessionId,
diff --git a/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java b/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java
index f92c31c0ba6a..31021031b47a 100644
--- a/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java
+++ b/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java
@@ -21,16 +21,20 @@ import static com.android.cts.shim.lib.ShimPackage.SHIM_APEX_PACKAGE_NAME;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
import static org.junit.Assume.assumeTrue;
import android.cts.install.lib.host.InstallUtilsHost;
import android.platform.test.annotations.LargeTest;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
import com.android.ddmlib.Log;
import com.android.tests.rollback.host.AbandonSessionsRule;
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
+import com.android.tradefed.util.CommandResult;
+import com.android.tradefed.util.CommandStatus;
import com.android.tradefed.util.ProcessInfo;
import org.junit.After;
@@ -39,8 +43,9 @@ import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.io.BufferedWriter;
import java.io.File;
-import java.util.Collections;
+import java.io.FileWriter;
import java.util.List;
import java.util.stream.Collectors;
@@ -52,9 +57,13 @@ public class StagedInstallInternalTest extends BaseHostJUnit4Test {
@Rule
public AbandonSessionsRule mHostTestRule = new AbandonSessionsRule(this);
-
private static final String SHIM_V2 = "com.android.apex.cts.shim.v2.apex";
+ private static final String APEX_WRONG_SHA = "com.android.apex.cts.shim.v2_wrong_sha.apex";
private static final String APK_A = "TestAppAv1.apk";
+ private static final String APK_IN_APEX_TESTAPEX_NAME = "com.android.apex.apkrollback.test";
+
+ private static final String TEST_VENDOR_APEX_ALLOW_LIST =
+ "/vendor/etc/sysconfig/test-vendor-apex-allow-list.xml";
private final InstallUtilsHost mHostUtils = new InstallUtilsHost(this);
@@ -79,6 +88,12 @@ public class StagedInstallInternalTest extends BaseHostJUnit4Test {
} catch (AssertionError e) {
Log.e(TAG, e);
}
+ deleteFiles("/system/apex/" + APK_IN_APEX_TESTAPEX_NAME + "*.apex",
+ "/data/apex/active/" + APK_IN_APEX_TESTAPEX_NAME + "*.apex",
+ "/data/apex/active/" + SHIM_APEX_PACKAGE_NAME + "*.apex",
+ "/system/apex/test.rebootless_apex_v1.apex",
+ "/data/apex/active/test.apex.rebootless*.apex",
+ TEST_VENDOR_APEX_ALLOW_LIST);
}
@Before
@@ -91,6 +106,73 @@ public class StagedInstallInternalTest extends BaseHostJUnit4Test {
cleanUp();
}
+ /**
+ * Deletes files and reboots the device if necessary.
+ * @param files the paths of files which might contain wildcards
+ */
+ private void deleteFiles(String... files) throws Exception {
+ boolean found = false;
+ for (String file : files) {
+ CommandResult result = getDevice().executeShellV2Command("ls " + file);
+ if (result.getStatus() == CommandStatus.SUCCESS) {
+ found = true;
+ break;
+ }
+ }
+
+ if (found) {
+ if (!getDevice().isAdbRoot()) {
+ getDevice().enableAdbRoot();
+ }
+ getDevice().remountSystemWritable();
+ for (String file : files) {
+ getDevice().executeShellCommand("rm -rf " + file);
+ }
+ getDevice().reboot();
+ }
+ }
+
+ private void pushTestApex(String fileName) throws Exception {
+ CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(getBuild());
+ final File apex = buildHelper.getTestFile(fileName);
+ if (!getDevice().isAdbRoot()) {
+ getDevice().enableAdbRoot();
+ }
+ getDevice().remountSystemWritable();
+ assertTrue(getDevice().pushFile(apex, "/system/apex/" + fileName));
+ }
+
+ private void pushTestVendorApexAllowList(String installerPackageName) throws Exception {
+ if (!getDevice().isAdbRoot()) {
+ getDevice().enableAdbRoot();
+ }
+ getDevice().remountSystemWritable();
+ File file = File.createTempFile("test-vendor-apex-allow-list", ".xml");
+ try (BufferedWriter writer = new BufferedWriter(new FileWriter(file))) {
+ final String fmt =
+ "<config>\n"
+ + " <allowed-vendor-apex package=\"test.apex.rebootless\" "
+ + " installerPackage=\"%s\" />\n"
+ + "</config>";
+ writer.write(String.format(fmt, installerPackageName));
+ }
+ getDevice().pushFile(file, TEST_VENDOR_APEX_ALLOW_LIST);
+ }
+
+ /**
+ * Tests that duplicate packages in apk-in-apex and apk should fail to install.
+ */
+ @Test
+ @LargeTest
+ public void testDuplicateApkInApexShouldFail() throws Exception {
+ pushTestApex(APK_IN_APEX_TESTAPEX_NAME + "_v1.apex");
+ getDevice().reboot();
+
+ runPhase("testDuplicateApkInApexShouldFail_Commit");
+ getDevice().reboot();
+ runPhase("testDuplicateApkInApexShouldFail_Verify");
+ }
+
@Test
public void testSystemServerRestartDoesNotAffectStagedSessions() throws Exception {
runPhase("testSystemServerRestartDoesNotAffectStagedSessions_Commit");
@@ -187,6 +269,37 @@ public class StagedInstallInternalTest extends BaseHostJUnit4Test {
}
@Test
+ public void testAbandonStagedSessionShouldCleanUp() throws Exception {
+ List<String> before = getStagingDirectories();
+ runPhase("testAbandonStagedSessionShouldCleanUp");
+ List<String> after = getStagingDirectories();
+ // The staging directories generated during the test should be deleted
+ assertThat(after).isEqualTo(before);
+ }
+
+ @Test
+ public void testStagedSessionShouldCleanUpOnVerificationFailure() throws Exception {
+ assumeTrue("Device does not support updating APEX",
+ mHostUtils.isApexUpdateSupported());
+ List<String> before = getStagingDirectories();
+ runPhase("testStagedSessionShouldCleanUpOnVerificationFailure");
+ List<String> after = getStagingDirectories();
+ assertThat(after).isEqualTo(before);
+ }
+
+ @Test
+ @LargeTest
+ public void testStagedSessionShouldCleanUpOnOnSuccess() throws Exception {
+ List<String> before = getStagingDirectories();
+ runPhase("testStagedSessionShouldCleanUpOnOnSuccess_Commit");
+ assertThat(getStagingDirectories()).isNotEqualTo(before);
+ getDevice().reboot();
+ runPhase("testStagedSessionShouldCleanUpOnOnSuccess_Verify");
+ List<String> after = getStagingDirectories();
+ assertThat(after).isEqualTo(before);
+ }
+
+ @Test
public void testStagedInstallationShouldCleanUpOnValidationFailure() throws Exception {
List<String> before = getStagingDirectories();
runPhase("testStagedInstallationShouldCleanUpOnValidationFailure");
@@ -204,16 +317,165 @@ public class StagedInstallInternalTest extends BaseHostJUnit4Test {
}
@Test
+ @LargeTest
public void testOrphanedStagingDirectoryGetsCleanedUpOnReboot() throws Exception {
//create random directories in /data/app-staging folder
getDevice().enableAdbRoot();
getDevice().executeShellCommand("mkdir /data/app-staging/session_123");
- getDevice().executeShellCommand("mkdir /data/app-staging/random_name");
+ getDevice().executeShellCommand("mkdir /data/app-staging/session_456");
+ getDevice().disableAdbRoot();
+
+ assertThat(getStagingDirectories()).contains("session_123");
+ assertThat(getStagingDirectories()).contains("session_456");
+ getDevice().reboot();
+ assertThat(getStagingDirectories()).doesNotContain("session_123");
+ assertThat(getStagingDirectories()).doesNotContain("session_456");
+ }
+
+ @Test
+ @LargeTest
+ public void testFailStagedSessionIfStagingDirectoryDeleted() throws Exception {
+ // Create a staged session
+ runPhase("testFailStagedSessionIfStagingDirectoryDeleted_Commit");
+
+ // Delete the staging directory
+ getDevice().enableAdbRoot();
+ getDevice().executeShellCommand("rm -r /data/app-staging");
+ getDevice().disableAdbRoot();
+
+ getDevice().reboot();
+
+ runPhase("testFailStagedSessionIfStagingDirectoryDeleted_Verify");
+ }
+
+ @Test
+ public void testApexActivationFailureIsCapturedInSession() throws Exception {
+ // We initiate staging a normal apex update which passes pre-reboot verification.
+ // Then we replace the valid apex waiting in /data/app-staging with something
+ // that cannot be activated and reboot. The apex should fail to activate, which
+ // is what we want for this test.
+ runPhase("testApexActivationFailureIsCapturedInSession_Commit");
+ final String sessionId = getDevice().executeShellCommand(
+ "pm get-stagedsessions --only-ready --only-parent --only-sessionid").trim();
+ assertThat(sessionId).isNotEmpty();
+ // Now replace the valid staged apex with something invalid
+ getDevice().enableAdbRoot();
+ getDevice().executeShellCommand("rm /data/app-staging/session_" + sessionId + "/*");
+ final File invalidApexFile = mHostUtils.getTestFile(APEX_WRONG_SHA);
+ getDevice().pushFile(invalidApexFile,
+ "/data/app-staging/session_" + sessionId + "/base.apex");
+ getDevice().reboot();
+
+ runPhase("testApexActivationFailureIsCapturedInSession_Verify");
+ }
+
+ @Test
+ public void testActiveApexIsRevertedOnCheckpointRollback() throws Exception {
+ assumeTrue("Device does not support updating APEX",
+ mHostUtils.isApexUpdateSupported());
+ assumeTrue("Device does not support file-system checkpoint",
+ mHostUtils.isCheckpointSupported());
+
+ // Install something so that /data/apex/active is not empty
+ runPhase("testActiveApexIsRevertedOnCheckpointRollback_Prepare");
+ getDevice().reboot();
+
+ // Stage another session which will be installed during fs-rollback mode
+ runPhase("testActiveApexIsRevertedOnCheckpointRollback_Commit");
+
+ // Set checkpoint to 0 so that we enter fs-rollback mode immediately on reboot
+ getDevice().enableAdbRoot();
+ getDevice().executeShellCommand("vdc checkpoint startCheckpoint 0");
getDevice().disableAdbRoot();
+ getDevice().reboot();
- assertThat(getStagingDirectories()).isNotEmpty();
+ // Verify that session was reverted and we have fallen back to
+ // apex installed during preparation stage.
+ runPhase("testActiveApexIsRevertedOnCheckpointRollback_VerifyPostReboot");
+ }
+
+ @Test
+ public void testApexIsNotActivatedIfNotInCheckpointMode() throws Exception {
+ assumeTrue("Device does not support updating APEX",
+ mHostUtils.isApexUpdateSupported());
+ assumeTrue("Device does not support file-system checkpoint",
+ mHostUtils.isCheckpointSupported());
+
+ runPhase("testApexIsNotActivatedIfNotInCheckpointMode_Commit");
+ // Delete checkpoint file in /metadata so that device thinks
+ // fs-checkpointing was never activated
+ getDevice().enableAdbRoot();
+ getDevice().executeShellCommand("rm /metadata/vold/checkpoint");
+ getDevice().disableAdbRoot();
getDevice().reboot();
- assertThat(getStagingDirectories()).isEmpty();
+ // Verify that session was not installed when not in fs-checkpoint mode
+ runPhase("testApexIsNotActivatedIfNotInCheckpointMode_VerifyPostReboot");
+ }
+
+ @Test
+ public void testApexInstallerNotInAllowListCanNotInstall() throws Exception {
+ assumeTrue("Device does not support updating APEX",
+ mHostUtils.isApexUpdateSupported());
+
+ runPhase("testApexInstallerNotInAllowListCanNotInstall_staged");
+ runPhase("testApexInstallerNotInAllowListCanNotInstall_nonStaged");
+ }
+
+ @Test
+ @LargeTest
+ public void testApexNotInAllowListCanNotInstall() throws Exception {
+ assumeTrue("Device does not support updating APEX",
+ mHostUtils.isApexUpdateSupported());
+
+ pushTestApex("test.rebootless_apex_v1.apex");
+ getDevice().reboot();
+
+ runPhase("testApexNotInAllowListCanNotInstall_staged");
+ runPhase("testApexNotInAllowListCanNotInstall_nonStaged");
+ }
+
+ @Test
+ @LargeTest
+ public void testVendorApexWrongInstaller() throws Exception {
+ assumeTrue("Device does not support updating APEX",
+ mHostUtils.isApexUpdateSupported());
+
+ pushTestVendorApexAllowList("com.wrong.installer");
+ pushTestApex("test.rebootless_apex_v1.apex");
+ getDevice().reboot();
+
+ runPhase("testVendorApexWrongInstaller_staged");
+ runPhase("testVendorApexWrongInstaller_nonStaged");
+ }
+
+ @Test
+ @LargeTest
+ public void testVendorApexCorrectInstaller() throws Exception {
+ assumeTrue("Device does not support updating APEX",
+ mHostUtils.isApexUpdateSupported());
+
+ pushTestVendorApexAllowList("com.android.tests.stagedinstallinternal");
+ pushTestApex("test.rebootless_apex_v1.apex");
+ getDevice().reboot();
+
+ runPhase("testVendorApexCorrectInstaller_staged");
+ runPhase("testVendorApexCorrectInstaller_nonStaged");
+ }
+
+ @Test
+ public void testRebootlessUpdates() throws Exception {
+ pushTestApex("test.rebootless_apex_v1.apex");
+ getDevice().reboot();
+
+ runPhase("testRebootlessUpdates");
+ }
+
+ @Test
+ public void testRebootlessUpdate_hasStagedSessionWithSameApex_fails() throws Exception {
+ assumeTrue("Device does not support updating APEX",
+ mHostUtils.isApexUpdateSupported());
+
+ runPhase("testRebootlessUpdate_hasStagedSessionWithSameApex_fails");
}
@Test
@@ -239,9 +501,6 @@ public class StagedInstallInternalTest extends BaseHostJUnit4Test {
.stream().filter(entry -> entry.getName().matches("session_\\d+"))
.map(entry -> entry.getName())
.collect(Collectors.toList());
- } catch (Exception e) {
- // Return an empty list if any error
- return Collections.EMPTY_LIST;
} finally {
getDevice().disableAdbRoot();
}
@@ -249,7 +508,7 @@ public class StagedInstallInternalTest extends BaseHostJUnit4Test {
private void restartSystemServer() throws Exception {
// Restart the system server
- long oldStartTime = getDevice().getProcessByName("system_server").getStartTime();
+ final ProcessInfo oldPs = getDevice().getProcessByName("system_server");
getDevice().enableAdbRoot(); // Need root to restart system server
assertThat(getDevice().executeShellCommand("am restart")).contains("Restart the system");
@@ -257,18 +516,16 @@ public class StagedInstallInternalTest extends BaseHostJUnit4Test {
// Wait for new system server process to start
final long start = System.currentTimeMillis();
- long newStartTime = oldStartTime;
while (System.currentTimeMillis() < start + SYSTEM_SERVER_TIMEOUT_MS) {
final ProcessInfo newPs = getDevice().getProcessByName("system_server");
if (newPs != null) {
- newStartTime = newPs.getStartTime();
- if (newStartTime != oldStartTime) {
- break;
+ if (newPs.getPid() != oldPs.getPid()) {
+ getDevice().waitForDeviceAvailable();
+ return;
}
}
Thread.sleep(500);
}
- assertThat(newStartTime).isNotEqualTo(oldStartTime);
- getDevice().waitForDeviceAvailable();
+ fail("Timed out in restarting system server");
}
}
diff --git a/tests/StatusBar/AndroidManifest.xml b/tests/StatusBar/AndroidManifest.xml
index 6a082e990dab..8744dae1b360 100644
--- a/tests/StatusBar/AndroidManifest.xml
+++ b/tests/StatusBar/AndroidManifest.xml
@@ -1,56 +1,68 @@
+<?xml version="1.0" encoding="utf-8"?>
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.statusbartest">
- <uses-permission android:name="android.permission.DEVICE_POWER" />
- <uses-permission android:name="android.permission.WAKE_LOCK" />
- <uses-permission android:name="android.permission.STATUS_BAR" />
- <uses-permission android:name="android.permission.EXPAND_STATUS_BAR" />
- <uses-permission android:name="android.permission.VIBRATE" />
- <uses-permission android:name="android.permission.CHANGE_COMPONENT_ENABLED_STATE" />
- <uses-permission android:name="android.permission.MANAGE_NOTIFICATIONS" />
+ package="com.android.statusbartest">
+ <uses-permission android:name="android.permission.DEVICE_POWER"/>
+ <uses-permission android:name="android.permission.WAKE_LOCK"/>
+ <uses-permission android:name="android.permission.STATUS_BAR"/>
+ <uses-permission android:name="android.permission.EXPAND_STATUS_BAR"/>
+ <uses-permission android:name="android.permission.VIBRATE"/>
+ <uses-permission android:name="android.permission.CHANGE_COMPONENT_ENABLED_STATE"/>
+ <uses-permission android:name="android.permission.MANAGE_NOTIFICATIONS"/>
<application>
- <activity android:name="StatusBarTest" android:label="_StatusBar">
+ <activity android:name="StatusBarTest"
+ android:label="_StatusBar"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="NotificationTestList" android:label="_Notifications">
+ <activity android:name="NotificationTestList"
+ android:label="_Notifications"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:name="NotificationBuilderTest"
- android:label="_Notify Builder"
- android:theme="@android:style/Theme.Holo"
- android:hardwareAccelerated="true"
- >
+ android:label="_Notify Builder"
+ android:theme="@android:style/Theme.Holo"
+ android:hardwareAccelerated="true"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="ToastTest" android:label="_Toasts">
+ <activity android:name="ToastTest"
+ android:label="_Toasts"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="PowerTest" android:label="_Power">
+ <activity android:name="PowerTest"
+ android:label="_Power"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="ConfirmationActivity" android:theme="@android:style/Theme.Dialog">
+ <activity android:name="ConfirmationActivity"
+ android:theme="@android:style/Theme.Dialog">
</activity>
- <activity android:name="TestAlertActivity" android:theme="@android:style/Theme.Dialog">
+ <activity android:name="TestAlertActivity"
+ android:theme="@android:style/Theme.Dialog">
</activity>
</application>
</manifest>
diff --git a/tests/StatusBar/src/com/android/statusbartest/NotificationBuilderTest.java b/tests/StatusBar/src/com/android/statusbartest/NotificationBuilderTest.java
index 9862116e376b..601688ed783d 100644
--- a/tests/StatusBar/src/com/android/statusbartest/NotificationBuilderTest.java
+++ b/tests/StatusBar/src/com/android/statusbartest/NotificationBuilderTest.java
@@ -497,7 +497,7 @@ public class NotificationBuilderTest extends Activity
intent.setData(Uri.fromParts("content", "//status_bar_test/delete/" + id, null));
intent.putExtra(ConfirmationActivity.EXTRA_TITLE, "Delete intent");
intent.putExtra(ConfirmationActivity.EXTRA_TEXT, "id: " + id);
- return PendingIntent.getActivity(this, 0, intent, 0);
+ return PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_MUTABLE_UNAUDITED);
}
private PendingIntent makeContentIntent(int id) {
@@ -505,7 +505,7 @@ public class NotificationBuilderTest extends Activity
intent.setData(Uri.fromParts("content", "//status_bar_test/content/" + id, null));
intent.putExtra(ConfirmationActivity.EXTRA_TITLE, "Content intent");
intent.putExtra(ConfirmationActivity.EXTRA_TEXT, "id: " + id);
- return PendingIntent.getActivity(this, 0, intent, 0);
+ return PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_MUTABLE_UNAUDITED);
}
}
diff --git a/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java b/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
index 163250d9d666..ef324e7c1377 100644
--- a/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
+++ b/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
@@ -25,27 +25,22 @@ import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
-import android.content.Context;
import android.content.ContentResolver;
+import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Icon;
import android.media.AudioAttributes;
+import android.net.Uri;
import android.os.Bundle;
-import android.os.Vibrator;
import android.os.Handler;
-import android.os.UserHandle;
-import android.util.Log;
-import android.net.Uri;
+import android.os.PowerManager;
import android.os.SystemClock;
+import android.os.Vibrator;
+import android.util.Log;
import android.widget.RemoteViews;
-import android.os.PowerManager;
-
-// private NM API
-import android.app.INotificationManager;
import android.widget.Toast;
public class NotificationTestList extends TestActivity
@@ -185,6 +180,7 @@ public class NotificationTestList extends TestActivity
.setContentTitle("default priority group 1")
.setGroup("group1")
.setOngoing(true)
+ .setColor(Color.WHITE)
.setColorized(true)
.build();
mNM.notify(6002, n);
@@ -1160,12 +1156,12 @@ public class NotificationTestList extends TestActivity
private PendingIntent makeIntent() {
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_HOME);
- return PendingIntent.getActivity(this, 0, intent, 0);
+ return PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_MUTABLE_UNAUDITED);
}
private PendingIntent makeIntent2() {
Intent intent = new Intent(this, StatusBarTest.class);
- return PendingIntent.getActivity(this, 0, intent, 0);
+ return PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_MUTABLE_UNAUDITED);
}
diff --git a/tests/StatusBar/src/com/android/statusbartest/StatusBarTest.java b/tests/StatusBar/src/com/android/statusbartest/StatusBarTest.java
index 3d72ee67a227..6bcfebc752f1 100644
--- a/tests/StatusBar/src/com/android/statusbartest/StatusBarTest.java
+++ b/tests/StatusBar/src/com/android/statusbartest/StatusBarTest.java
@@ -160,7 +160,7 @@ public class StatusBarTest extends TestActivity
StatusBarTest.this,
0,
fullScreenIntent,
- PendingIntent.FLAG_CANCEL_CURRENT);
+ PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_MUTABLE_UNAUDITED);
Notification not = new Notification.Builder(StatusBarTest.this)
.setSmallIcon(R.drawable.stat_sys_phone)
.setWhen(System.currentTimeMillis() - (1000 * 60 * 60 * 24))
diff --git a/tests/SurfaceComposition/AndroidManifest.xml b/tests/SurfaceComposition/AndroidManifest.xml
index 4c0a9b61fd8f..46c8f88626c3 100644
--- a/tests/SurfaceComposition/AndroidManifest.xml
+++ b/tests/SurfaceComposition/AndroidManifest.xml
@@ -16,21 +16,22 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="android.surfacecomposition">
- <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+ package="android.surfacecomposition">
+ <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<application android:theme="@style/noeffects">
- <uses-library android:name="android.test.runner" />
- <activity android:name="android.surfacecomposition.SurfaceCompositionMeasuringActivity" >
+ <uses-library android:name="android.test.runner"/>
+ <activity android:name="android.surfacecomposition.SurfaceCompositionMeasuringActivity"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <uses-library android:name="android.test.runner" />
+ <uses-library android:name="android.test.runner"/>
</application>
<!-- self-instrumenting test package. -->
<instrumentation android:name="android.test.InstrumentationTestRunner"
- android:targetPackage="android.surfacecomposition">
+ android:targetPackage="android.surfacecomposition">
</instrumentation>
</manifest>
diff --git a/tests/SurfaceControlViewHostTest/AndroidManifest.xml b/tests/SurfaceControlViewHostTest/AndroidManifest.xml
index ee95763453f7..7e9a04dfa82c 100644
--- a/tests/SurfaceControlViewHostTest/AndroidManifest.xml
+++ b/tests/SurfaceControlViewHostTest/AndroidManifest.xml
@@ -13,10 +13,12 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.test.viewembed">
+ package="com.android.test.viewembed">
<application>
- <activity android:name="SurfaceControlViewHostTest" android:label="View Embedding Test">
+ <activity android:name="SurfaceControlViewHostTest"
+ android:label="View Embedding Test"
+ android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
diff --git a/tests/SurfaceControlViewHostTest/src/com/android/test/viewembed/SurfaceControlViewHostTest.java b/tests/SurfaceControlViewHostTest/src/com/android/test/viewembed/SurfaceControlViewHostTest.java
index 3bc530975580..73e01634709e 100644
--- a/tests/SurfaceControlViewHostTest/src/com/android/test/viewembed/SurfaceControlViewHostTest.java
+++ b/tests/SurfaceControlViewHostTest/src/com/android/test/viewembed/SurfaceControlViewHostTest.java
@@ -22,12 +22,11 @@ import android.graphics.Color;
import android.graphics.PixelFormat;
import android.os.Bundle;
import android.view.Gravity;
-import android.view.SurfaceControl;
+import android.view.SurfaceControlViewHost;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.WindowManager;
-import android.view.SurfaceControlViewHost;
import android.widget.Button;
import android.widget.FrameLayout;
@@ -46,8 +45,6 @@ public class SurfaceControlViewHostTest extends Activity implements SurfaceHolde
mView.setZOrderOnTop(true);
mView.getHolder().addCallback(this);
-
- addEmbeddedView();
}
void addEmbeddedView() {
@@ -63,6 +60,8 @@ public class SurfaceControlViewHostTest extends Activity implements SurfaceHolde
v.setBackgroundColor(Color.RED);
}
});
+ v.getViewTreeObserver().addOnWindowFocusChangeListener(focused ->
+ v.setBackgroundColor(focused ? Color.MAGENTA : Color.DKGRAY));
WindowManager.LayoutParams lp =
new WindowManager.LayoutParams(500, 500, WindowManager.LayoutParams.TYPE_APPLICATION,
0, PixelFormat.OPAQUE);
@@ -71,6 +70,7 @@ public class SurfaceControlViewHostTest extends Activity implements SurfaceHolde
@Override
public void surfaceCreated(SurfaceHolder holder) {
+ addEmbeddedView();
}
@Override
diff --git a/tests/SurfaceViewBufferTests/Android.bp b/tests/SurfaceViewBufferTests/Android.bp
new file mode 100644
index 000000000000..dc75f00e7cdc
--- /dev/null
+++ b/tests/SurfaceViewBufferTests/Android.bp
@@ -0,0 +1,70 @@
+// Copyright (C) 2020 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 {
+ // 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"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+android_test {
+ name: "SurfaceViewBufferTests",
+ srcs: ["**/*.java","**/*.kt"],
+ manifest: "AndroidManifest.xml",
+ test_config: "AndroidTest.xml",
+ platform_apis: true,
+ certificate: "platform",
+ use_embedded_native_libs: true,
+ jni_libs: [
+ "libsurface_jni",
+ ],
+
+ static_libs: [
+ "androidx.appcompat_appcompat",
+ "androidx.test.rules",
+ "androidx.test.runner",
+ "androidx.test.ext.junit",
+ "kotlin-stdlib",
+ "kotlinx-coroutines-android",
+ "flickerlib",
+ "truth-prebuilt",
+ "cts-wm-util",
+ "CtsSurfaceValidatorLib",
+ ],
+}
+
+cc_library_shared {
+ name: "libsurface_jni",
+ srcs: [
+ "cpp/SurfaceProxy.cpp",
+ ],
+ shared_libs: [
+ "libutils",
+ "libui",
+ "libgui",
+ "liblog",
+ "libandroid",
+ ],
+ include_dirs: [
+ "system/core/include"
+ ],
+ stl: "libc++_static",
+ cflags: [
+ "-Werror",
+ "-Wall",
+ ],
+}
diff --git a/tests/SurfaceViewBufferTests/AndroidManifest.xml b/tests/SurfaceViewBufferTests/AndroidManifest.xml
new file mode 100644
index 000000000000..c910ecdac1b3
--- /dev/null
+++ b/tests/SurfaceViewBufferTests/AndroidManifest.xml
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.test">
+
+ <uses-sdk android:minSdkVersion="29"
+ android:targetSdkVersion="29"/>
+ <!-- Enable / Disable tracing !-->
+ <uses-permission android:name="android.permission.DUMP" />
+ <!-- Enable / Disable sv blast adapter !-->
+ <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
+ <!-- Readback virtual display output !-->
+ <uses-permission android:name="android.permission.CAPTURE_VIDEO_OUTPUT"/>
+ <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
+ <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
+ <!-- Save failed test bitmap images !-->
+ <uses-permission android:name="android.Manifest.permission.WRITE_EXTERNAL_STORAGE"/>
+
+ <application android:allowBackup="false"
+ android:supportsRtl="true">
+ <activity android:name=".MainActivity"
+ android:taskAffinity="com.android.test.MainActivity"
+ android:theme="@style/AppTheme"
+ android:configChanges="orientation|screenSize"
+ android:label="SurfaceViewBufferTestApp"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
+ </intent-filter>
+ </activity>
+ <service android:name="android.view.cts.surfacevalidator.LocalMediaProjectionService"
+ android:foregroundServiceType="mediaProjection"
+ android:enabled="true">
+ </service>
+ <uses-library android:name="android.test.runner"/>
+ </application>
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.test"
+ android:label="SurfaceViewBufferTests">
+ </instrumentation>
+</manifest>
diff --git a/tests/SurfaceViewBufferTests/AndroidTest.xml b/tests/SurfaceViewBufferTests/AndroidTest.xml
new file mode 100644
index 000000000000..b73fe4853ecf
--- /dev/null
+++ b/tests/SurfaceViewBufferTests/AndroidTest.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 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.
+-->
+<configuration description="Runs SurfaceView Buffer Tests">
+ <option name="test-tag" value="SurfaceViewBufferTests" />
+ <target_preparer class="com.android.tradefed.targetprep.DeviceSetup">
+ <!-- keeps the screen on during tests -->
+ <option name="screen-always-on" value="on" />
+ <!-- prevents the phone from restarting -->
+ <option name="force-skip-system-props" value="true" />
+ </target_preparer>
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="false"/>
+ <option name="test-file-name" value="SurfaceViewBufferTests.apk"/>
+ </target_preparer>
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest">
+ <option name="package" value="com.android.test"/>
+ <option name="exclude-annotation" value="androidx.test.filters.FlakyTest" />
+ <option name="shell-timeout" value="6600s" />
+ <option name="test-timeout" value="6000s" />
+ <option name="hidden-api-checks" value="false" />
+ </test>
+</configuration>
diff --git a/tests/SurfaceViewBufferTests/OWNERS b/tests/SurfaceViewBufferTests/OWNERS
new file mode 100644
index 000000000000..d50528c237ff
--- /dev/null
+++ b/tests/SurfaceViewBufferTests/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/wm/OWNERS \ No newline at end of file
diff --git a/tests/SurfaceViewBufferTests/cpp/SurfaceProxy.cpp b/tests/SurfaceViewBufferTests/cpp/SurfaceProxy.cpp
new file mode 100644
index 000000000000..926ff4d5793c
--- /dev/null
+++ b/tests/SurfaceViewBufferTests/cpp/SurfaceProxy.cpp
@@ -0,0 +1,248 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#include <android/log.h>
+#include <android/native_window.h>
+#include <android/native_window_jni.h>
+#include <android/window.h>
+#include <gui/Surface.h>
+#include <jni.h>
+#include <system/window.h>
+#include <utils/RefBase.h>
+#include <cassert>
+#include <chrono>
+#include <thread>
+
+#define TAG "SurfaceViewBufferTests"
+#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__)
+
+extern "C" {
+int i = 0;
+static ANativeWindow* sAnw;
+static std::map<uint32_t /* slot */, ANativeWindowBuffer*> sBuffers;
+
+JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_setSurface(JNIEnv* env, jclass,
+ jobject surfaceObject) {
+ sAnw = ANativeWindow_fromSurface(env, surfaceObject);
+ assert(sAnw);
+ android::sp<android::Surface> surface = static_cast<android::Surface*>(sAnw);
+ surface->enableFrameTimestamps(true);
+ surface->connect(NATIVE_WINDOW_API_CPU, nullptr, false);
+ native_window_set_usage(sAnw, GRALLOC_USAGE_SW_WRITE_OFTEN);
+ native_window_set_buffers_format(sAnw, HAL_PIXEL_FORMAT_RGBA_8888);
+ return 0;
+}
+
+JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_waitUntilBufferDisplayed(
+ JNIEnv*, jclass, jlong jFrameNumber, jint timeoutMs) {
+ using namespace std::chrono_literals;
+ assert(sAnw);
+ android::sp<android::Surface> surface = static_cast<android::Surface*>(sAnw);
+
+ uint64_t frameNumber = static_cast<uint64_t>(jFrameNumber);
+ nsecs_t outRequestedPresentTime, outAcquireTime, outLatchTime, outFirstRefreshStartTime;
+ nsecs_t outLastRefreshStartTime, outGlCompositionDoneTime, outDequeueReadyTime;
+ nsecs_t outDisplayPresentTime = -1;
+ nsecs_t outReleaseTime;
+
+ auto start = std::chrono::steady_clock::now();
+ while (outDisplayPresentTime < 0) {
+ std::this_thread::sleep_for(8ms);
+ surface->getFrameTimestamps(frameNumber, &outRequestedPresentTime, &outAcquireTime,
+ &outLatchTime, &outFirstRefreshStartTime,
+ &outLastRefreshStartTime, &outGlCompositionDoneTime,
+ &outDisplayPresentTime, &outDequeueReadyTime, &outReleaseTime);
+ if (outDisplayPresentTime < 0) {
+ auto end = std::chrono::steady_clock::now();
+ if (std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() >
+ timeoutMs) {
+ return -1;
+ }
+ }
+ }
+ return 0;
+}
+
+JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_draw(JNIEnv*, jclass) {
+ assert(sAnw);
+ ANativeWindow_Buffer outBuffer;
+ ANativeWindow_lock(sAnw, &outBuffer, nullptr);
+ return 0;
+}
+
+JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_ANativeWindowLock(JNIEnv*, jclass) {
+ assert(sAnw);
+ ANativeWindow_Buffer outBuffer;
+ ANativeWindow_lock(sAnw, &outBuffer, nullptr);
+ return 0;
+}
+
+JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_ANativeWindowUnlockAndPost(JNIEnv*,
+ jclass) {
+ assert(sAnw);
+ ANativeWindow_unlockAndPost(sAnw);
+ return 0;
+}
+
+JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_ANativeWindowSetBuffersGeometry(
+ JNIEnv* /* env */, jclass /* clazz */, jobject /* surfaceObject */, jint w, jint h,
+ jint format) {
+ assert(sAnw);
+ return ANativeWindow_setBuffersGeometry(sAnw, w, h, format);
+}
+
+JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_ANativeWindowSetBuffersTransform(
+ JNIEnv* /* env */, jclass /* clazz */, jint transform) {
+ assert(sAnw);
+ return native_window_set_buffers_transform(sAnw, transform);
+}
+
+JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_SurfaceSetScalingMode(JNIEnv* /* env */,
+ jclass /* clazz */,
+ jint scalingMode) {
+ assert(sAnw);
+ android::sp<android::Surface> surface = static_cast<android::Surface*>(sAnw);
+ return surface->setScalingMode(scalingMode);
+}
+
+JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_SurfaceDequeueBuffer(JNIEnv* /* env */,
+ jclass /* clazz */,
+ jint slot,
+ jint timeoutMs) {
+ assert(sAnw);
+ ANativeWindowBuffer* anb;
+ int fenceFd;
+ int result = sAnw->dequeueBuffer(sAnw, &anb, &fenceFd);
+ if (result != android::OK) {
+ return result;
+ }
+ sBuffers[slot] = anb;
+ if (timeoutMs == 0) {
+ return android::OK;
+ }
+ android::sp<android::Fence> fence(new android::Fence(fenceFd));
+ int waitResult = fence->wait(timeoutMs);
+ if (waitResult != android::OK) {
+ sAnw->cancelBuffer(sAnw, sBuffers[slot], -1);
+ sBuffers[slot] = nullptr;
+ return waitResult;
+ }
+ return 0;
+}
+
+JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_SurfaceCancelBuffer(JNIEnv* /* env */,
+ jclass /* clazz */,
+ jint slot) {
+ assert(sAnw);
+ assert(sBuffers[slot]);
+ int result = sAnw->cancelBuffer(sAnw, sBuffers[slot], -1);
+ sBuffers[slot] = nullptr;
+ return result;
+}
+
+JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_drawBuffer(JNIEnv* env,
+ jclass /* clazz */, jint slot,
+ jintArray jintArrayColor) {
+ assert(sAnw);
+ assert(sBuffers[slot]);
+
+ int* color = env->GetIntArrayElements(jintArrayColor, nullptr);
+
+ ANativeWindowBuffer* buffer = sBuffers[slot];
+ android::sp<android::GraphicBuffer> graphicBuffer(static_cast<android::GraphicBuffer*>(buffer));
+ const android::Rect bounds(buffer->width, buffer->height);
+ android::Region newDirtyRegion;
+ newDirtyRegion.set(bounds);
+
+ void* vaddr;
+ int fenceFd = -1;
+ graphicBuffer->lockAsync(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
+ newDirtyRegion.bounds(), &vaddr, fenceFd);
+
+ for (int32_t row = 0; row < buffer->height; row++) {
+ uint8_t* dst = static_cast<uint8_t*>(vaddr) + (buffer->stride * row) * 4;
+ for (int32_t column = 0; column < buffer->width; column++) {
+ dst[0] = color[0];
+ dst[1] = color[1];
+ dst[2] = color[2];
+ dst[3] = color[3];
+ dst += 4;
+ }
+ }
+ graphicBuffer->unlockAsync(&fenceFd);
+ env->ReleaseIntArrayElements(jintArrayColor, color, JNI_ABORT);
+ return 0;
+}
+
+JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_SurfaceQueueBuffer(JNIEnv* /* env */,
+ jclass /* clazz */,
+ jint slot,
+ jboolean freeSlot) {
+ assert(sAnw);
+ assert(sBuffers[slot]);
+ int result = sAnw->queueBuffer(sAnw, sBuffers[slot], -1);
+ if (freeSlot) {
+ sBuffers[slot] = nullptr;
+ }
+ return result;
+}
+
+JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_SurfaceSetAsyncMode(JNIEnv* /* env */,
+ jclass /* clazz */,
+ jboolean async) {
+ assert(sAnw);
+ android::sp<android::Surface> surface = static_cast<android::Surface*>(sAnw);
+ return surface->setAsyncMode(async);
+}
+
+JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_SurfaceSetDequeueTimeout(
+ JNIEnv* /* env */, jclass /* clazz */, jlong timeoutMs) {
+ assert(sAnw);
+ android::sp<android::Surface> surface = static_cast<android::Surface*>(sAnw);
+ return surface->setDequeueTimeout(timeoutMs);
+}
+
+JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_SurfaceSetMaxDequeuedBufferCount(
+ JNIEnv* /* env */, jclass /* clazz */, jint maxDequeuedBuffers) {
+ assert(sAnw);
+ android::sp<android::Surface> surface = static_cast<android::Surface*>(sAnw);
+ return surface->setMaxDequeuedBufferCount(maxDequeuedBuffers);
+}
+
+JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_NativeWindowSetBufferCount(
+ JNIEnv* /* env */, jclass /* clazz */, jint count) {
+ assert(sAnw);
+ android::sp<android::Surface> surface = static_cast<android::Surface*>(sAnw);
+ int result = native_window_set_buffer_count(sAnw, count);
+ return result;
+}
+
+JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_NativeWindowSetSharedBufferMode(
+ JNIEnv* /* env */, jclass /* clazz */, jboolean shared) {
+ assert(sAnw);
+ android::sp<android::Surface> surface = static_cast<android::Surface*>(sAnw);
+ int result = native_window_set_shared_buffer_mode(sAnw, shared);
+ return result;
+}
+
+JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_NativeWindowSetAutoRefresh(
+ JNIEnv* /* env */, jclass /* clazz */, jboolean autoRefresh) {
+ assert(sAnw);
+ android::sp<android::Surface> surface = static_cast<android::Surface*>(sAnw);
+ int result = native_window_set_auto_refresh(sAnw, autoRefresh);
+ return result;
+}
+} \ No newline at end of file
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_pip.xml b/tests/SurfaceViewBufferTests/res/values/styles.xml
index 2c58d91e34fe..8b50738a06de 100644
--- a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_pip.xml
+++ b/tests/SurfaceViewBufferTests/res/values/styles.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- Copyright 2018 The Android Open Source Project
+ Copyright 2020 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.
@@ -14,13 +14,12 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="@android:color/holo_blue_bright">
- <Button android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:id="@+id/enter_pip"
- android:text="Enter PIP"/>
-</LinearLayout>
+<resources>
+<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
+ <item name="windowNoTitle">true</item>
+ <item name="windowActionBar">false</item>
+ <item name="android:windowFullscreen">true</item>
+ <item name="android:windowContentOverlay">@null</item>
+ <item name="android:windowDisablePreview">true</item>
+</style>
+</resources>
diff --git a/tests/SurfaceViewBufferTests/src/com/android/test/BufferPresentationTests.kt b/tests/SurfaceViewBufferTests/src/com/android/test/BufferPresentationTests.kt
new file mode 100644
index 000000000000..b67dc380efab
--- /dev/null
+++ b/tests/SurfaceViewBufferTests/src/com/android/test/BufferPresentationTests.kt
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2020 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.test
+
+import com.android.server.wm.flicker.traces.layers.LayersTraceSubject.Companion.assertThat
+import junit.framework.Assert.assertEquals
+import junit.framework.Assert.assertTrue
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+
+@RunWith(Parameterized::class)
+class BufferPresentationTests(useBlastAdapter: Boolean) : SurfaceTracingTestBase(useBlastAdapter) {
+ /** Submit buffers as fast as possible and make sure they are presented on display */
+ @Test
+ fun testQueueBuffers() {
+ val numFrames = 100L
+ val trace = withTrace { activity ->
+ for (i in 1..numFrames) {
+ activity.mSurfaceProxy.ANativeWindowLock()
+ activity.mSurfaceProxy.ANativeWindowUnlockAndPost()
+ }
+ assertEquals(0, activity.mSurfaceProxy.waitUntilBufferDisplayed(numFrames,
+ 1000 /* ms */))
+ }
+
+ assertThat(trace).hasFrameSequence("SurfaceView", 1..numFrames)
+ }
+
+ @Test
+ fun testSetBufferScalingMode_outOfOrderQueueBuffer() {
+ val trace = withTrace { activity ->
+ assertEquals(0, activity.mSurfaceProxy.SurfaceDequeueBuffer(0, 1000 /* ms */))
+ assertEquals(0, activity.mSurfaceProxy.SurfaceDequeueBuffer(1, 1000 /* ms */))
+
+ activity.mSurfaceProxy.SurfaceQueueBuffer(1)
+ activity.mSurfaceProxy.SurfaceQueueBuffer(0)
+ assertEquals(0, activity.mSurfaceProxy.waitUntilBufferDisplayed(2, 5000 /* ms */))
+ }
+
+ assertThat(trace).hasFrameSequence("SurfaceView", 1..2L)
+ }
+
+ @Test
+ fun testSetBufferScalingMode_multipleDequeueBuffer() {
+ val numFrames = 20L
+ val trace = withTrace { activity ->
+ for (count in 1..(numFrames / 2)) {
+ assertEquals(0, activity.mSurfaceProxy.SurfaceDequeueBuffer(0, 1000 /* ms */))
+ assertEquals(0, activity.mSurfaceProxy.SurfaceDequeueBuffer(1, 1000 /* ms */))
+
+ activity.mSurfaceProxy.SurfaceQueueBuffer(0)
+ activity.mSurfaceProxy.SurfaceQueueBuffer(1)
+ }
+ assertEquals(0, activity.mSurfaceProxy.waitUntilBufferDisplayed(numFrames,
+ 5000 /* ms */))
+ }
+
+ assertThat(trace).hasFrameSequence("SurfaceView", 1..numFrames)
+ }
+
+ @Test
+ fun testSetBufferCount_queueMaxBufferCountMinusOne() {
+ val numBufferCount = 8
+ val numFrames = numBufferCount * 5L
+ val trace = withTrace { activity ->
+ assertEquals(0, activity.mSurfaceProxy.NativeWindowSetBufferCount(numBufferCount + 1))
+ for (i in 1..numFrames / numBufferCount) {
+ for (bufferSlot in 0..numBufferCount - 1) {
+ assertEquals(0,
+ activity.mSurfaceProxy.SurfaceDequeueBuffer(bufferSlot, 1000 /* ms */))
+ }
+
+ for (bufferSlot in 0..numBufferCount - 1) {
+ activity.mSurfaceProxy.SurfaceQueueBuffer(bufferSlot)
+ }
+ }
+ assertEquals(0, activity.mSurfaceProxy.waitUntilBufferDisplayed(numFrames,
+ 5000 /* ms */))
+ }
+
+ assertThat(trace).hasFrameSequence("SurfaceView", 1..numFrames)
+ }
+
+ @Test
+ // Leave IGBP in sync mode, try to dequeue and queue as fast as possible. Check that we
+ // occasionally get timeout errors.
+ fun testSyncMode_dequeueWithoutBlockingFails() {
+ val numFrames = 1000L
+ runOnUiThread { activity ->
+ assertEquals(0, activity.mSurfaceProxy.SurfaceSetDequeueTimeout(3L))
+ var failures = false
+ for (i in 1..numFrames) {
+ if (activity.mSurfaceProxy.SurfaceDequeueBuffer(0, 0 /* ms */) != 0) {
+ failures = true
+ break
+ }
+ activity.mSurfaceProxy.SurfaceQueueBuffer(0)
+ }
+ assertTrue(failures)
+ }
+ }
+
+ @Test
+ // Set IGBP to be in async mode, try to dequeue and queue as fast as possible. Client should be
+ // able to dequeue and queue buffers without being blocked.
+ fun testAsyncMode_dequeueWithoutBlocking() {
+ val numFrames = 1000L
+ runOnUiThread { activity ->
+ assertEquals(0, activity.mSurfaceProxy.SurfaceSetDequeueTimeout(3L))
+ assertEquals(0, activity.mSurfaceProxy.SurfaceSetAsyncMode(async = true))
+ for (i in 1..numFrames) {
+ assertEquals(0, activity.mSurfaceProxy.SurfaceDequeueBuffer(0, 0 /* ms */))
+ activity.mSurfaceProxy.SurfaceQueueBuffer(0)
+ }
+ }
+ }
+
+ @Test
+ // Disable triple buffering in the system and leave IGBP in sync mode. Check that we
+ // occasionally get timeout errors.
+ fun testSyncModeWithDisabledTripleBuffering_dequeueWithoutBlockingFails() {
+ val numFrames = 1000L
+ runOnUiThread { activity ->
+ assertEquals(0, activity.mSurfaceProxy.SurfaceSetMaxDequeuedBufferCount(1))
+ assertEquals(0, activity.mSurfaceProxy.SurfaceSetDequeueTimeout(3L))
+ var failures = false
+ for (i in 1..numFrames) {
+ if (activity.mSurfaceProxy.SurfaceDequeueBuffer(0, 0 /* ms */) != 0) {
+ failures = true
+ break
+ }
+ activity.mSurfaceProxy.SurfaceQueueBuffer(0)
+ }
+ assertTrue(failures)
+ }
+ }
+
+ @Test
+ // Disable triple buffering in the system and set IGBP to be in async mode. Try to dequeue and
+ // queue as fast as possible. Without triple buffering, the client does not have an extra buffer
+ // to dequeue and will not be able to dequeue and queue buffers without being blocked.
+ fun testAsyncModeWithDisabledTripleBuffering_dequeueWithoutBlockingFails() {
+ val numFrames = 1000L
+ runOnUiThread { activity ->
+ assertEquals(0, activity.mSurfaceProxy.SurfaceSetMaxDequeuedBufferCount(1))
+ assertEquals(0, activity.mSurfaceProxy.SurfaceSetDequeueTimeout(3L))
+ assertEquals(0, activity.mSurfaceProxy.SurfaceSetAsyncMode(async = true))
+ var failures = false
+ for (i in 1..numFrames) {
+ if (activity.mSurfaceProxy.SurfaceDequeueBuffer(0, 0 /* ms */) != 0) {
+ failures = true
+ break
+ }
+ activity.mSurfaceProxy.SurfaceQueueBuffer(0)
+ }
+ assertTrue(failures)
+ }
+ }
+} \ No newline at end of file
diff --git a/tests/SurfaceViewBufferTests/src/com/android/test/BufferRejectionTests.kt b/tests/SurfaceViewBufferTests/src/com/android/test/BufferRejectionTests.kt
new file mode 100644
index 000000000000..e9e0246a207d
--- /dev/null
+++ b/tests/SurfaceViewBufferTests/src/com/android/test/BufferRejectionTests.kt
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2020 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.test
+
+import android.graphics.Point
+import com.android.server.wm.flicker.traces.layers.LayersTraceSubject.Companion.assertThat
+import com.android.test.SurfaceViewBufferTestBase.Companion.ScalingMode
+import com.android.test.SurfaceViewBufferTestBase.Companion.Transform
+import junit.framework.Assert.assertEquals
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+
+@RunWith(Parameterized::class)
+class BufferRejectionTests(useBlastAdapter: Boolean) : SurfaceTracingTestBase(useBlastAdapter) {
+ @Test
+ fun testSetBuffersGeometry_0x0_rejectsBuffer() {
+ val trace = withTrace { activity ->
+ activity.mSurfaceProxy.ANativeWindowSetBuffersGeometry(activity.surface!!, 100, 100,
+ R8G8B8A8_UNORM)
+ activity.mSurfaceProxy.ANativeWindowLock()
+ activity.mSurfaceProxy.ANativeWindowUnlockAndPost()
+ activity.mSurfaceProxy.ANativeWindowLock()
+ activity.mSurfaceProxy.ANativeWindowSetBuffersGeometry(activity.surface!!, 0, 0,
+ R8G8B8A8_UNORM)
+ // Submit buffer one with a different size which should be rejected
+ activity.mSurfaceProxy.ANativeWindowUnlockAndPost()
+
+ // submit a buffer with the default buffer size
+ activity.mSurfaceProxy.ANativeWindowLock()
+ activity.mSurfaceProxy.ANativeWindowUnlockAndPost()
+ activity.mSurfaceProxy.waitUntilBufferDisplayed(3, 500 /* ms */)
+ }
+ // Verify we reject buffers since scaling mode == NATIVE_WINDOW_SCALING_MODE_FREEZE
+ assertThat(trace).layer("SurfaceView", 2).doesNotExist()
+
+ // Verify the next buffer is submitted with the correct size
+ assertThat(trace).layer("SurfaceView", 3).also {
+ it.hasBufferSize(defaultBufferSize)
+ // scaling mode is not passed down to the layer for blast
+ if (useBlastAdapter) {
+ it.hasScalingMode(ScalingMode.SCALE_TO_WINDOW.ordinal)
+ } else {
+ it.hasScalingMode(ScalingMode.FREEZE.ordinal)
+ }
+ }
+ }
+
+ @Test
+ fun testSetBufferScalingMode_freeze() {
+ val bufferSize = Point(300, 200)
+ val trace = withTrace { activity ->
+ activity.drawFrame()
+ assertEquals(activity.mSurfaceProxy.waitUntilBufferDisplayed(1, 500 /* ms */), 0)
+ activity.mSurfaceProxy.ANativeWindowSetBuffersGeometry(activity.surface!!, bufferSize,
+ R8G8B8A8_UNORM)
+ assertEquals(0, activity.mSurfaceProxy.SurfaceDequeueBuffer(0, 1000 /* ms */))
+ assertEquals(0, activity.mSurfaceProxy.SurfaceDequeueBuffer(1, 1000 /* ms */))
+ // Change buffer size and set scaling mode to freeze
+ activity.mSurfaceProxy.ANativeWindowSetBuffersGeometry(activity.surface!!, Point(0, 0),
+ R8G8B8A8_UNORM)
+
+ // first dequeued buffer does not have the new size so it should be rejected.
+ activity.mSurfaceProxy.SurfaceQueueBuffer(0)
+ activity.mSurfaceProxy.SurfaceSetScalingMode(ScalingMode.SCALE_TO_WINDOW)
+ activity.mSurfaceProxy.SurfaceQueueBuffer(1)
+ assertEquals(activity.mSurfaceProxy.waitUntilBufferDisplayed(3, 500 /* ms */), 0)
+ }
+
+ // verify buffer size is reset to default buffer size
+ assertThat(trace).layer("SurfaceView", 1).hasBufferSize(defaultBufferSize)
+ assertThat(trace).layer("SurfaceView", 2).doesNotExist()
+ assertThat(trace).layer("SurfaceView", 3).hasBufferSize(bufferSize)
+ }
+
+ @Test
+ fun testSetBufferScalingMode_freeze_withBufferRotation() {
+ val rotatedBufferSize = Point(defaultBufferSize.y, defaultBufferSize.x)
+ val trace = withTrace { activity ->
+ activity.drawFrame()
+ assertEquals(activity.mSurfaceProxy.waitUntilBufferDisplayed(1, 500 /* ms */), 0)
+ activity.mSurfaceProxy.ANativeWindowSetBuffersGeometry(activity.surface!!,
+ rotatedBufferSize, R8G8B8A8_UNORM)
+ assertEquals(0, activity.mSurfaceProxy.SurfaceDequeueBuffer(0, 1000 /* ms */))
+ assertEquals(0, activity.mSurfaceProxy.SurfaceDequeueBuffer(1, 1000 /* ms */))
+ // Change buffer size and set scaling mode to freeze
+ activity.mSurfaceProxy.ANativeWindowSetBuffersGeometry(activity.surface!!, Point(0, 0),
+ R8G8B8A8_UNORM)
+
+ // first dequeued buffer does not have the new size so it should be rejected.
+ activity.mSurfaceProxy.SurfaceQueueBuffer(0)
+ // add a buffer transform so the buffer size is correct.
+ activity.mSurfaceProxy.ANativeWindowSetBuffersTransform(Transform.ROT_90)
+ activity.mSurfaceProxy.SurfaceQueueBuffer(1)
+ assertEquals(activity.mSurfaceProxy.waitUntilBufferDisplayed(3, 500 /* ms */), 0)
+ }
+
+ // verify buffer size is reset to default buffer size
+ assertThat(trace).layer("SurfaceView", 1).hasBufferSize(defaultBufferSize)
+ assertThat(trace).layer("SurfaceView", 2).doesNotExist()
+ assertThat(trace).layer("SurfaceView", 3).hasBufferSize(rotatedBufferSize)
+ assertThat(trace).layer("SurfaceView", 3).hasBufferOrientation(Transform.ROT_90.value)
+ }
+
+ @Test
+ fun testRejectedBuffersAreReleased() {
+ val bufferSize = Point(300, 200)
+ val trace = withTrace { activity ->
+ for (count in 0 until 5) {
+ activity.drawFrame()
+ assertEquals(activity.mSurfaceProxy.waitUntilBufferDisplayed((count * 3) + 1L,
+ 500 /* ms */), 0)
+ activity.mSurfaceProxy.ANativeWindowSetBuffersGeometry(activity.surface!!,
+ bufferSize, R8G8B8A8_UNORM)
+ assertEquals(0, activity.mSurfaceProxy.SurfaceDequeueBuffer(0, 1000 /* ms */))
+ assertEquals(0, activity.mSurfaceProxy.SurfaceDequeueBuffer(1, 1000 /* ms */))
+ // Change buffer size and set scaling mode to freeze
+ activity.mSurfaceProxy.ANativeWindowSetBuffersGeometry(activity.surface!!,
+ Point(0, 0), R8G8B8A8_UNORM)
+
+ // first dequeued buffer does not have the new size so it should be rejected.
+ activity.mSurfaceProxy.SurfaceQueueBuffer(0)
+ activity.mSurfaceProxy.SurfaceSetScalingMode(ScalingMode.SCALE_TO_WINDOW)
+ activity.mSurfaceProxy.SurfaceQueueBuffer(1)
+ assertEquals(activity.mSurfaceProxy.waitUntilBufferDisplayed((count * 3) + 3L,
+ 500 /* ms */), 0)
+ }
+ }
+
+ for (count in 0 until 5) {
+ assertThat(trace).layer("SurfaceView", (count * 3) + 1L)
+ .hasBufferSize(defaultBufferSize)
+ assertThat(trace).layer("SurfaceView", (count * 3) + 2L)
+ .doesNotExist()
+ assertThat(trace).layer("SurfaceView", (count * 3) + 3L)
+ .hasBufferSize(bufferSize)
+ }
+ }
+} \ No newline at end of file
diff --git a/tests/SurfaceViewBufferTests/src/com/android/test/GeometryTests.kt b/tests/SurfaceViewBufferTests/src/com/android/test/GeometryTests.kt
new file mode 100644
index 000000000000..0802990beeab
--- /dev/null
+++ b/tests/SurfaceViewBufferTests/src/com/android/test/GeometryTests.kt
@@ -0,0 +1,224 @@
+/*
+ * Copyright (C) 2020 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.test
+
+import android.graphics.Color
+import android.graphics.Point
+import android.graphics.Rect
+import android.os.SystemClock
+import com.android.server.wm.flicker.traces.layers.LayersTraceSubject.Companion.assertThat
+import com.android.test.SurfaceViewBufferTestBase.Companion.ScalingMode
+import com.android.test.SurfaceViewBufferTestBase.Companion.Transform
+import junit.framework.Assert.assertEquals
+import junit.framework.Assert.assertTrue
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+import java.util.concurrent.CountDownLatch
+import java.util.concurrent.TimeUnit
+
+@RunWith(Parameterized::class)
+class GeometryTests(useBlastAdapter: Boolean) : SurfaceTracingTestBase(useBlastAdapter) {
+ @Test
+ fun testSetBuffersGeometry_0x0_resetsBufferSize() {
+ val trace = withTrace { activity ->
+ activity.mSurfaceProxy.ANativeWindowSetBuffersGeometry(activity.surface!!, 0, 0,
+ R8G8B8A8_UNORM)
+ activity.mSurfaceProxy.ANativeWindowLock()
+ activity.mSurfaceProxy.ANativeWindowUnlockAndPost()
+ activity.mSurfaceProxy.waitUntilBufferDisplayed(1, 500 /* ms */)
+ }
+
+ // verify buffer size is reset to default buffer size
+ assertThat(trace).layer("SurfaceView", 1).hasBufferSize(defaultBufferSize)
+ }
+
+ @Test
+ fun testSetBuffersGeometry_smallerThanBuffer() {
+ val bufferSize = Point(300, 200)
+ val trace = withTrace { activity ->
+ activity.mSurfaceProxy.ANativeWindowSetBuffersGeometry(activity.surface!!, bufferSize,
+ R8G8B8A8_UNORM)
+ activity.drawFrame()
+ activity.mSurfaceProxy.waitUntilBufferDisplayed(1, 500 /* ms */)
+ }
+
+ assertThat(trace).layer("SurfaceView", 1).also {
+ it.hasBufferSize(bufferSize)
+ it.hasLayerSize(defaultBufferSize)
+ it.hasScalingMode(ScalingMode.SCALE_TO_WINDOW.ordinal)
+ }
+ }
+
+ @Test
+ fun testSetBuffersGeometry_largerThanBuffer() {
+ val bufferSize = Point(3000, 2000)
+ val trace = withTrace { activity ->
+ activity.mSurfaceProxy.ANativeWindowSetBuffersGeometry(activity.surface!!, bufferSize,
+ R8G8B8A8_UNORM)
+ activity.drawFrame()
+ activity.mSurfaceProxy.waitUntilBufferDisplayed(1, 500 /* ms */)
+ }
+
+ assertThat(trace).layer("SurfaceView", 1).also {
+ it.hasBufferSize(bufferSize)
+ it.hasLayerSize(defaultBufferSize)
+ it.hasScalingMode(ScalingMode.SCALE_TO_WINDOW.ordinal)
+ }
+ }
+
+ @Test
+ fun testSetBufferScalingMode_freeze() {
+ val bufferSize = Point(300, 200)
+ val trace = withTrace { activity ->
+ activity.drawFrame()
+ assertEquals(activity.mSurfaceProxy.waitUntilBufferDisplayed(1, 500 /* ms */), 0)
+ activity.mSurfaceProxy.ANativeWindowSetBuffersGeometry(activity.surface!!, bufferSize,
+ R8G8B8A8_UNORM)
+ assertEquals(0, activity.mSurfaceProxy.SurfaceDequeueBuffer(0, 1000 /* ms */))
+ assertEquals(0, activity.mSurfaceProxy.SurfaceDequeueBuffer(1, 1000 /* ms */))
+ // Change buffer size and set scaling mode to freeze
+ activity.mSurfaceProxy.ANativeWindowSetBuffersGeometry(activity.surface!!, Point(0, 0),
+ R8G8B8A8_UNORM)
+
+ // first dequeued buffer does not have the new size so it should be rejected.
+ activity.mSurfaceProxy.SurfaceQueueBuffer(0)
+ activity.mSurfaceProxy.SurfaceSetScalingMode(ScalingMode.SCALE_TO_WINDOW)
+ activity.mSurfaceProxy.SurfaceQueueBuffer(1)
+ assertEquals(activity.mSurfaceProxy.waitUntilBufferDisplayed(3, 500 /* ms */), 0)
+ }
+
+ // verify buffer size is reset to default buffer size
+ assertThat(trace).layer("SurfaceView", 1).hasBufferSize(defaultBufferSize)
+ assertThat(trace).layer("SurfaceView", 2).doesNotExist()
+ assertThat(trace).layer("SurfaceView", 3).hasBufferSize(bufferSize)
+ }
+
+ @Test
+ fun testSetBuffersTransform_FLIP() {
+ val transforms = arrayOf(Transform.FLIP_H, Transform.FLIP_V, Transform.ROT_180).withIndex()
+ for ((index, transform) in transforms) {
+ val trace = withTrace { activity ->
+ activity.mSurfaceProxy.ANativeWindowSetBuffersTransform(transform)
+ activity.mSurfaceProxy.ANativeWindowLock()
+ activity.mSurfaceProxy.ANativeWindowUnlockAndPost()
+ activity.mSurfaceProxy.waitUntilBufferDisplayed(index + 1L, 500 /* ms */)
+ }
+
+ assertThat(trace).layer("SurfaceView", index + 1L).also {
+ it.hasBufferSize(defaultBufferSize)
+ it.hasLayerSize(defaultBufferSize)
+ it.hasBufferOrientation(transform.value)
+ }
+ }
+ }
+
+ @Test
+ fun testSurfaceViewResizeImmediatelyWithNonFreezeScaling() {
+ val surfaceViewPosition = Rect()
+ var trace = withTrace { activity ->
+ activity.mSurfaceProxy.SurfaceSetScalingMode(ScalingMode.SCALE_TO_WINDOW)
+ assertEquals(0, activity.mSurfaceProxy.SurfaceDequeueBuffer(0, 1 /* ms */))
+ activity.mSurfaceProxy.drawBuffer(0, Color.BLUE)
+ activity.mSurfaceProxy.SurfaceQueueBuffer(0)
+ activity.mSurfaceProxy.waitUntilBufferDisplayed(1, 500 /* ms */)
+ activity.mSurfaceView!!.getBoundsOnScreen(surfaceViewPosition)
+ }
+
+ runOnUiThread {
+ val svBounds = Rect(0, 0, defaultBufferSize.x, defaultBufferSize.y)
+ svBounds.offsetTo(surfaceViewPosition.left, surfaceViewPosition.top)
+ checkPixels(svBounds, Color.BLUE)
+ }
+
+ // check that the layer and buffer starts with the default size
+ assertThat(trace).layer("SurfaceView", 1).also {
+ it.hasBufferSize(defaultBufferSize)
+ it.hasLayerSize(defaultBufferSize)
+ }
+ val newSize = Point(1280, 960)
+ lateinit var resizeCountDownLatch: CountDownLatch
+ runOnUiThread {
+ resizeCountDownLatch = it.resizeSurfaceView(newSize)
+ }
+ assertTrue(resizeCountDownLatch.await(1000, TimeUnit.MILLISECONDS))
+ // wait for sf to handle the resize transaction request
+ SystemClock.sleep(500)
+ trace = withTrace { _ ->
+ // take a trace with the new size
+ }
+
+ // check that the layer size has changed and the buffer is now streched to the new layer
+ // size
+ runOnUiThread {
+ val svBounds = Rect(0, 0, newSize.x, newSize.y)
+ svBounds.offsetTo(surfaceViewPosition.left, surfaceViewPosition.top)
+ checkPixels(svBounds, Color.BLUE)
+ }
+
+ assertThat(trace).layer("SurfaceView", 1).also {
+ it.hasLayerSize(newSize)
+ it.hasBufferSize(defaultBufferSize)
+ }
+ }
+
+ @Test
+ fun testSurfaceViewDoesNotResizeWithDefaultScaling() {
+ val surfaceViewPosition = Rect()
+ var trace = withTrace { activity ->
+ assertEquals(0, activity.mSurfaceProxy.SurfaceDequeueBuffer(0, 1 /* ms */))
+ activity.mSurfaceProxy.drawBuffer(0, Color.BLUE)
+ activity.mSurfaceProxy.SurfaceQueueBuffer(0)
+ activity.mSurfaceProxy.waitUntilBufferDisplayed(1, 500 /* ms */)
+ activity.mSurfaceView!!.getBoundsOnScreen(surfaceViewPosition)
+ }
+
+ runOnUiThread {
+ val svBounds = Rect(0, 0, defaultBufferSize.x, defaultBufferSize.y)
+ svBounds.offsetTo(surfaceViewPosition.left, surfaceViewPosition.top)
+ checkPixels(svBounds, Color.BLUE)
+ }
+
+ // check that the layer and buffer starts with the default size
+ assertThat(trace).layer("SurfaceView", 1).also {
+ it.hasBufferSize(defaultBufferSize)
+ it.hasLayerSize(defaultBufferSize)
+ }
+ val newSize = Point(1280, 960)
+ lateinit var resizeCountDownLatch: CountDownLatch
+ runOnUiThread {
+ resizeCountDownLatch = it.resizeSurfaceView(newSize)
+ }
+ assertTrue(resizeCountDownLatch.await(1000, TimeUnit.MILLISECONDS))
+ // wait for sf to handle the resize transaction request
+ SystemClock.sleep(500)
+ trace = withTrace { _ ->
+ // take a trace after the size change
+ }
+
+ // check the layer and buffer remains the same size
+ runOnUiThread {
+ val svBounds = Rect(0, 0, defaultBufferSize.x, defaultBufferSize.y)
+ svBounds.offsetTo(surfaceViewPosition.left, surfaceViewPosition.top)
+ checkPixels(svBounds, Color.BLUE)
+ }
+
+ assertThat(trace).layer("SurfaceView", 1).also {
+ it.hasLayerSize(defaultBufferSize)
+ it.hasBufferSize(defaultBufferSize)
+ }
+ }
+} \ No newline at end of file
diff --git a/tests/SurfaceViewBufferTests/src/com/android/test/InverseDisplayTransformTests.kt b/tests/SurfaceViewBufferTests/src/com/android/test/InverseDisplayTransformTests.kt
new file mode 100644
index 000000000000..69012bdd7d7c
--- /dev/null
+++ b/tests/SurfaceViewBufferTests/src/com/android/test/InverseDisplayTransformTests.kt
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2020 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.test
+
+import android.graphics.Point
+import com.android.server.wm.flicker.traces.layers.LayersTraceSubject.Companion.assertThat
+import com.android.test.SurfaceViewBufferTestBase.Companion.Transform
+import junit.framework.Assert.assertEquals
+import org.junit.Assume.assumeFalse
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+
+@RunWith(Parameterized::class)
+class InverseDisplayTransformTests(useBlastAdapter: Boolean) :
+ SurfaceTracingTestBase(useBlastAdapter) {
+ @Before
+ override fun setup() {
+ scenarioRule.getScenario().onActivity {
+ it.rotate90()
+ }
+ instrumentation.waitForIdleSync()
+ super.setup()
+ }
+
+ @Test
+ fun testSetBufferScalingMode_freeze_withInvDisplayTransform() {
+ assumeFalse("Blast does not support buffer rejection with Inv display " +
+ "transform since the only user for this hidden api is camera which does not use" +
+ "fixed scaling mode.", useBlastAdapter)
+
+ val rotatedBufferSize = Point(defaultBufferSize.y, defaultBufferSize.x)
+ val trace = withTrace { activity ->
+ // Inverse display transforms are sticky AND they are only consumed by the sf after
+ // a valid buffer has been acquired.
+ activity.mSurfaceProxy.ANativeWindowSetBuffersTransform(Transform.INVERSE_DISPLAY.value)
+ assertEquals(0, activity.mSurfaceProxy.SurfaceDequeueBuffer(0, 1000 /* ms */))
+ activity.mSurfaceProxy.SurfaceQueueBuffer(0)
+
+ assertEquals(activity.mSurfaceProxy.waitUntilBufferDisplayed(1, 500 /* ms */), 0)
+ activity.mSurfaceProxy.ANativeWindowSetBuffersGeometry(activity.surface!!,
+ rotatedBufferSize, R8G8B8A8_UNORM)
+ assertEquals(0, activity.mSurfaceProxy.SurfaceDequeueBuffer(0, 1000 /* ms */))
+ assertEquals(0, activity.mSurfaceProxy.SurfaceDequeueBuffer(1, 1000 /* ms */))
+ // Change buffer size and set scaling mode to freeze
+ activity.mSurfaceProxy.ANativeWindowSetBuffersGeometry(activity.surface!!, Point(0, 0),
+ R8G8B8A8_UNORM)
+
+ // first dequeued buffer does not have the new size so it should be rejected.
+ activity.mSurfaceProxy.ANativeWindowSetBuffersTransform(Transform.ROT_90.value)
+ activity.mSurfaceProxy.SurfaceQueueBuffer(0)
+ activity.mSurfaceProxy.ANativeWindowSetBuffersTransform(0)
+ activity.mSurfaceProxy.SurfaceQueueBuffer(1)
+ assertEquals(activity.mSurfaceProxy.waitUntilBufferDisplayed(3, 500 /* ms */), 0)
+ }
+
+ // verify buffer size is reset to default buffer size
+ assertThat(trace).layer("SurfaceView", 1).hasBufferSize(defaultBufferSize)
+ assertThat(trace).layer("SurfaceView", 2).doesNotExist()
+ assertThat(trace).layer("SurfaceView", 3).hasBufferSize(rotatedBufferSize)
+ }
+} \ No newline at end of file
diff --git a/tests/SurfaceViewBufferTests/src/com/android/test/MainActivity.kt b/tests/SurfaceViewBufferTests/src/com/android/test/MainActivity.kt
new file mode 100644
index 000000000000..5f398f380b01
--- /dev/null
+++ b/tests/SurfaceViewBufferTests/src/com/android/test/MainActivity.kt
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2020 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.test
+
+import android.content.Context
+import android.content.pm.ActivityInfo
+import android.content.res.Configuration.ORIENTATION_LANDSCAPE
+import android.graphics.Color
+import android.graphics.Paint
+import android.graphics.Point
+import android.graphics.Rect
+import android.os.Bundle
+import android.view.Gravity
+import android.view.Surface
+import android.view.SurfaceHolder
+import android.view.SurfaceView
+import android.view.View
+import android.view.WindowManager
+import android.view.cts.surfacevalidator.CapturedActivity
+import android.widget.FrameLayout
+import java.util.concurrent.CountDownLatch
+import java.util.concurrent.locks.ReentrantLock
+import kotlin.concurrent.withLock
+
+class MainActivity : CapturedActivity() {
+ val mSurfaceProxy = SurfaceProxy()
+ private var mSurfaceHolder: SurfaceHolder? = null
+ private val mDrawLock = ReentrantLock()
+ var mSurfaceView: SurfaceView? = null
+ private var mCountDownLatch: CountDownLatch? = null
+
+ val surface: Surface? get() = mSurfaceHolder?.surface
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ window.decorView.apply {
+ systemUiVisibility =
+ View.SYSTEM_UI_FLAG_HIDE_NAVIGATION or View.SYSTEM_UI_FLAG_FULLSCREEN
+ }
+ }
+
+ override fun getCaptureDurationMs(): Long {
+ return 30000
+ }
+
+ fun addSurfaceView(size: Point): CountDownLatch {
+ val layout = findViewById<FrameLayout>(android.R.id.content)
+ val surfaceReadyLatch = CountDownLatch(1)
+ mSurfaceView = createSurfaceView(applicationContext, size, surfaceReadyLatch)
+ layout!!.addView(mSurfaceView!!,
+ FrameLayout.LayoutParams(size.x, size.y, Gravity.TOP or Gravity.LEFT)
+ .also { it.setMargins(100, 100, 0, 0) })
+
+ return surfaceReadyLatch
+ }
+
+ fun resizeSurfaceView(size: Point): CountDownLatch {
+ mCountDownLatch = CountDownLatch(1)
+ mSurfaceView!!.layoutParams.also {
+ it.width = size.x
+ it.height = size.y
+ }
+ mSurfaceView!!.requestLayout()
+ return mCountDownLatch!!
+ }
+
+ fun enableSeamlessRotation() {
+ val p: WindowManager.LayoutParams = window.attributes
+ p.rotationAnimation = WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS
+ window.attributes = p
+ }
+
+ fun rotate90() {
+ if (getResources().getConfiguration().orientation == ORIENTATION_LANDSCAPE) {
+ setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT)
+ } else {
+ setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE)
+ }
+ }
+
+ private fun createSurfaceView(
+ context: Context,
+ size: Point,
+ surfaceReadyLatch: CountDownLatch
+ ): SurfaceView {
+ val surfaceView = SurfaceView(context)
+ surfaceView.setWillNotDraw(false)
+ surfaceView.holder.addCallback(object : SurfaceHolder.Callback {
+ override fun surfaceCreated(holder: SurfaceHolder) {
+ mDrawLock.withLock {
+ mSurfaceHolder = holder
+ mSurfaceProxy.setSurface(holder.surface)
+ }
+ surfaceReadyLatch.countDown()
+ }
+
+ override fun surfaceChanged(
+ holder: SurfaceHolder,
+ format: Int,
+ width: Int,
+ height: Int
+ ) {
+ mCountDownLatch?.countDown()
+ }
+
+ override fun surfaceDestroyed(holder: SurfaceHolder) {
+ mDrawLock.withLock {
+ mSurfaceHolder = null
+ }
+ }
+ })
+ return surfaceView
+ }
+
+ fun drawFrame(): Rect {
+ mDrawLock.withLock {
+ val holder = mSurfaceHolder ?: return Rect()
+ val canvas = holder.lockCanvas()
+ val canvasSize = Rect(0, 0, canvas.width, canvas.height)
+ canvas.drawColor(Color.GREEN)
+ val p = Paint()
+ p.color = Color.RED
+ canvas.drawRect(canvasSize, p)
+ holder.unlockCanvasAndPost(canvas)
+ return canvasSize
+ }
+ }
+} \ No newline at end of file
diff --git a/tests/SurfaceViewBufferTests/src/com/android/test/ScreenRecordTestBase.kt b/tests/SurfaceViewBufferTests/src/com/android/test/ScreenRecordTestBase.kt
new file mode 100644
index 000000000000..df3d30e13908
--- /dev/null
+++ b/tests/SurfaceViewBufferTests/src/com/android/test/ScreenRecordTestBase.kt
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2020 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.test
+
+import android.annotation.ColorInt
+import android.content.Context
+import android.content.Intent
+import android.graphics.Rect
+import android.server.wm.WindowManagerState.getLogicalDisplaySize
+import android.view.cts.surfacevalidator.CapturedActivity
+import android.view.cts.surfacevalidator.ISurfaceValidatorTestCase
+import android.view.cts.surfacevalidator.PixelChecker
+import android.view.cts.surfacevalidator.RectChecker
+import android.widget.FrameLayout
+import androidx.test.rule.ActivityTestRule
+import org.junit.After
+import org.junit.Before
+import org.junit.Rule
+import java.util.concurrent.CountDownLatch
+
+open class ScreenRecordTestBase(useBlastAdapter: Boolean) :
+ SurfaceViewBufferTestBase(useBlastAdapter) {
+ @get:Rule
+ var mActivityRule = ActivityTestRule(MainActivity::class.java)
+
+ private lateinit var mActivity: MainActivity
+
+ @Before
+ override fun setup() {
+ super.setup()
+ mActivity = mActivityRule.launchActivity(Intent())
+ lateinit var surfaceReadyLatch: CountDownLatch
+ runOnUiThread {
+ it.dismissPermissionDialog()
+ it.setLogicalDisplaySize(getLogicalDisplaySize())
+ surfaceReadyLatch = it.addSurfaceView(defaultBufferSize)
+ }
+ surfaceReadyLatch.await()
+ // sleep to finish animations
+ instrumentation.waitForIdleSync()
+ }
+
+ @After
+ override fun teardown() {
+ super.teardown()
+ mActivityRule.finishActivity()
+ }
+
+ fun runOnUiThread(predicate: (it: MainActivity) -> Unit) {
+ mActivityRule.runOnUiThread {
+ predicate(mActivity)
+ }
+ }
+
+ fun withScreenRecording(
+ boundsToCheck: Rect,
+ @ColorInt color: Int,
+ predicate: (it: MainActivity) -> Unit
+ ): CapturedActivity.TestResult {
+ val testCase = object : ISurfaceValidatorTestCase {
+ override fun getChecker(): PixelChecker = RectChecker(boundsToCheck, color)
+ override fun start(context: Context, parent: FrameLayout) {
+ predicate(mActivity)
+ }
+ override fun end() { /* do nothing */ }
+ }
+
+ return mActivity.runTest(testCase)
+ }
+} \ No newline at end of file
diff --git a/tests/SurfaceViewBufferTests/src/com/android/test/SharedBufferModeScreenRecordTests.kt b/tests/SurfaceViewBufferTests/src/com/android/test/SharedBufferModeScreenRecordTests.kt
new file mode 100644
index 000000000000..996a1d3d79da
--- /dev/null
+++ b/tests/SurfaceViewBufferTests/src/com/android/test/SharedBufferModeScreenRecordTests.kt
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2020 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.test
+
+import android.graphics.Color
+import android.graphics.Rect
+import android.os.SystemClock
+import android.view.cts.surfacevalidator.PixelColor
+import junit.framework.Assert.assertEquals
+import org.junit.Assert.assertTrue
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+
+@RunWith(Parameterized::class)
+class SharedBufferModeScreenRecordTests(useBlastAdapter: Boolean) :
+ ScreenRecordTestBase(useBlastAdapter) {
+
+ /** When auto refresh is set, surface flinger will wake up and refresh the display presenting
+ * the latest content in the buffer.
+ */
+ @Test
+ fun testAutoRefresh() {
+ var svBounds = Rect()
+ runOnUiThread {
+ assertEquals(0, it.mSurfaceProxy.NativeWindowSetSharedBufferMode(true))
+ assertEquals(0, it.mSurfaceProxy.NativeWindowSetAutoRefresh(true))
+ assertEquals(0, it.mSurfaceProxy.SurfaceDequeueBuffer(0, 1 /* ms */))
+ it.mSurfaceProxy.SurfaceQueueBuffer(0, false /* freeSlot */)
+ assertEquals(0,
+ it.mSurfaceProxy.waitUntilBufferDisplayed(1, 5000 /* ms */))
+
+ svBounds = Rect(0, 0, it.mSurfaceView!!.width, it.mSurfaceView!!.height)
+ val position = Rect()
+ it.mSurfaceView!!.getBoundsOnScreen(position)
+ svBounds.offsetTo(position.left, position.top)
+
+ // wait for buffers from other layers to be latched and transactions to be processed before
+ // updating the buffer
+ SystemClock.sleep(4000)
+ }
+
+ val result = withScreenRecording(svBounds, PixelColor.RED) {
+ it.mSurfaceProxy.drawBuffer(0, Color.RED)
+ }
+ val failRatio = 1.0f * result.failFrames / (result.failFrames + result.passFrames)
+
+ assertTrue("Error: " + result.failFrames +
+ " incorrect frames observed (out of " + (result.failFrames + result.passFrames) +
+ " frames)", failRatio < 0.05)
+ assertTrue("Error: Did not receive sufficient frame updates expected: >1000 actual:" +
+ result.passFrames, result.passFrames > 1000)
+ }
+} \ No newline at end of file
diff --git a/tests/SurfaceViewBufferTests/src/com/android/test/SharedBufferModeTests.kt b/tests/SurfaceViewBufferTests/src/com/android/test/SharedBufferModeTests.kt
new file mode 100644
index 000000000000..ee41d7941470
--- /dev/null
+++ b/tests/SurfaceViewBufferTests/src/com/android/test/SharedBufferModeTests.kt
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2020 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.test
+
+import android.graphics.Color
+import android.graphics.Rect
+import com.android.server.wm.flicker.traces.layers.LayersTraceSubject.Companion.assertThat
+import junit.framework.Assert.assertEquals
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+
+@RunWith(Parameterized::class)
+class SharedBufferModeTests(useBlastAdapter: Boolean) : SurfaceTracingTestBase(useBlastAdapter) {
+ /** Sanity test to check each buffer is presented if its submitted with enough delay
+ * for SF to present the buffers. */
+ @Test
+ fun testCanPresentBuffers() {
+ val numFrames = 15L
+ val trace = withTrace { activity ->
+ assertEquals(0, activity.mSurfaceProxy.NativeWindowSetSharedBufferMode(true))
+ for (i in 1..numFrames) {
+ assertEquals(0, activity.mSurfaceProxy.SurfaceDequeueBuffer(0, 1 /* ms */))
+ activity.mSurfaceProxy.SurfaceQueueBuffer(0)
+ assertEquals(0, activity.mSurfaceProxy.waitUntilBufferDisplayed(i, 5000 /* ms */))
+ }
+ }
+
+ assertThat(trace).hasFrameSequence("SurfaceView", 1..numFrames)
+ }
+
+ /** Submit buffers as fast as possible testing that we are not blocked when dequeuing the buffer
+ * by setting the dequeue timeout to 1ms and checking that we present the newest buffer. */
+ @Test
+ fun testFastQueueBuffers() {
+ val numFrames = 15L
+ val trace = withTrace { activity ->
+ assertEquals(0, activity.mSurfaceProxy.NativeWindowSetSharedBufferMode(true))
+ for (i in 1..numFrames) {
+ assertEquals(0, activity.mSurfaceProxy.SurfaceDequeueBuffer(0, 1 /* ms */))
+ activity.mSurfaceProxy.SurfaceQueueBuffer(0)
+ }
+ assertEquals(0, activity.mSurfaceProxy.waitUntilBufferDisplayed(numFrames,
+ 5000 /* ms */))
+ }
+
+ assertThat(trace).hasFrameSequence("SurfaceView", numFrames..numFrames)
+ }
+
+ /** Keep overwriting the buffer without queuing buffers and check that we present the latest
+ * buffer content. */
+ @Test
+ fun testAutoRefresh() {
+ var svBounds = Rect()
+ runOnUiThread {
+ assertEquals(0, it.mSurfaceProxy.NativeWindowSetSharedBufferMode(true))
+ assertEquals(0, it.mSurfaceProxy.NativeWindowSetAutoRefresh(true))
+ assertEquals(0, it.mSurfaceProxy.SurfaceDequeueBuffer(0, 1 /* ms */))
+ it.mSurfaceProxy.SurfaceQueueBuffer(0, false /* freeSlot */)
+ assertEquals(0, it.mSurfaceProxy.waitUntilBufferDisplayed(1, 5000 /* ms */))
+
+ svBounds = Rect(0, 0, it.mSurfaceView!!.width, it.mSurfaceView!!.height)
+ val position = Rect()
+ it.mSurfaceView!!.getBoundsOnScreen(position)
+ svBounds.offsetTo(position.left, position.top)
+ }
+
+ runOnUiThread {
+ it.mSurfaceProxy.drawBuffer(0, Color.RED)
+ checkPixels(svBounds, Color.RED)
+ it.mSurfaceProxy.drawBuffer(0, Color.GREEN)
+ checkPixels(svBounds, Color.GREEN)
+ it.mSurfaceProxy.drawBuffer(0, Color.BLUE)
+ checkPixels(svBounds, Color.BLUE)
+ }
+ }
+} \ No newline at end of file
diff --git a/tests/SurfaceViewBufferTests/src/com/android/test/SurfaceProxy.kt b/tests/SurfaceViewBufferTests/src/com/android/test/SurfaceProxy.kt
new file mode 100644
index 000000000000..45a70944204c
--- /dev/null
+++ b/tests/SurfaceViewBufferTests/src/com/android/test/SurfaceProxy.kt
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2020 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.test
+
+import android.annotation.ColorInt
+import android.graphics.Color
+import android.graphics.Point
+import com.android.test.SurfaceViewBufferTestBase.Companion.ScalingMode
+import com.android.test.SurfaceViewBufferTestBase.Companion.Transform
+
+class SurfaceProxy {
+ init {
+ System.loadLibrary("surface_jni")
+ }
+
+ external fun setSurface(surface: Any)
+ external fun waitUntilBufferDisplayed(frameNumber: Long, timeoutMs: Int): Int
+ external fun draw()
+ fun drawBuffer(slot: Int, @ColorInt c: Int) {
+ drawBuffer(slot, intArrayOf(Color.red(c), Color.green(c), Color.blue(c), Color.alpha(c)))
+ }
+ external fun drawBuffer(slot: Int, color: IntArray)
+
+ // android/native_window.h functions
+ external fun ANativeWindowLock()
+ external fun ANativeWindowUnlockAndPost()
+ fun ANativeWindowSetBuffersGeometry(surface: Any, size: Point, format: Int) {
+ ANativeWindowSetBuffersGeometry(surface, size.x, size.y, format)
+ }
+ external fun ANativeWindowSetBuffersGeometry(surface: Any, width: Int, height: Int, format: Int)
+ fun ANativeWindowSetBuffersTransform(transform: Transform) {
+ ANativeWindowSetBuffersTransform(transform.value)
+ }
+ external fun ANativeWindowSetBuffersTransform(transform: Int)
+
+ // gui/Surface.h functions
+ fun SurfaceSetScalingMode(scalingMode: ScalingMode) {
+ SurfaceSetScalingMode(scalingMode.ordinal)
+ }
+ external fun SurfaceSetScalingMode(scalingMode: Int)
+ external fun SurfaceDequeueBuffer(slot: Int, timeoutMs: Int): Int
+ external fun SurfaceCancelBuffer(slot: Int)
+ external fun SurfaceQueueBuffer(slot: Int, freeSlot: Boolean = true): Int
+ external fun SurfaceSetAsyncMode(async: Boolean): Int
+ external fun SurfaceSetDequeueTimeout(timeout: Long): Int
+ external fun SurfaceQuery(what: Int): Int
+ external fun SurfaceSetMaxDequeuedBufferCount(maxDequeuedBuffers: Int): Int
+
+ // system/native_window.h functions
+ external fun NativeWindowSetBufferCount(count: Int): Int
+ external fun NativeWindowSetSharedBufferMode(shared: Boolean): Int
+ external fun NativeWindowSetAutoRefresh(autoRefresh: Boolean): Int
+}
diff --git a/tests/SurfaceViewBufferTests/src/com/android/test/SurfaceTracingTestBase.kt b/tests/SurfaceViewBufferTests/src/com/android/test/SurfaceTracingTestBase.kt
new file mode 100644
index 000000000000..6383da5a0a98
--- /dev/null
+++ b/tests/SurfaceViewBufferTests/src/com/android/test/SurfaceTracingTestBase.kt
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2020 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.test
+
+import android.annotation.ColorInt
+import android.graphics.Bitmap
+import android.graphics.Color
+import android.graphics.Rect
+import android.util.Log
+import androidx.test.ext.junit.rules.ActivityScenarioRule
+import com.android.server.wm.flicker.monitor.LayersTraceMonitor
+import com.android.server.wm.flicker.monitor.withSFTracing
+import com.android.server.wm.traces.common.layers.LayersTrace
+import junit.framework.Assert
+import org.junit.After
+import org.junit.Before
+import org.junit.Rule
+import java.io.FileOutputStream
+import java.io.IOException
+import java.util.concurrent.CountDownLatch
+
+open class SurfaceTracingTestBase(useBlastAdapter: Boolean) :
+ SurfaceViewBufferTestBase(useBlastAdapter) {
+ @get:Rule
+ var scenarioRule: ActivityScenarioRule<MainActivity> =
+ ActivityScenarioRule<MainActivity>(MainActivity::class.java)
+
+ @Before
+ override fun setup() {
+ super.setup()
+ stopLayerTrace()
+ addSurfaceView()
+ }
+
+ @After
+ override fun teardown() {
+ super.teardown()
+ scenarioRule.getScenario().close()
+ }
+
+ fun withTrace(predicate: (it: MainActivity) -> Unit): LayersTrace {
+ return withSFTracing(TRACE_FLAGS,
+ outputDir = instrumentation.targetContext.dataDir.toPath()) {
+ scenarioRule.getScenario().onActivity {
+ predicate(it)
+ }
+ }
+ }
+
+ fun withTrace(predicate: () -> Unit): LayersTrace {
+ return withSFTracing(TRACE_FLAGS,
+ outputDir = instrumentation.targetContext.dataDir.toPath()) {
+ predicate()
+ }
+ }
+
+ fun runOnUiThread(predicate: (it: MainActivity) -> Unit) {
+ scenarioRule.getScenario().onActivity {
+ predicate(it)
+ }
+ }
+
+ private fun addSurfaceView() {
+ lateinit var surfaceReadyLatch: CountDownLatch
+ scenarioRule.getScenario().onActivity {
+ surfaceReadyLatch = it.addSurfaceView(defaultBufferSize)
+ }
+ surfaceReadyLatch.await()
+ // sleep to finish animations
+ instrumentation.waitForIdleSync()
+ }
+
+ private fun stopLayerTrace() {
+ val tmpDir = instrumentation.targetContext.dataDir.toPath()
+ LayersTraceMonitor(tmpDir).stop()
+ }
+
+ fun checkPixels(bounds: Rect, @ColorInt color: Int) {
+ val screenshot = instrumentation.getUiAutomation().takeScreenshot()
+ val pixels = IntArray(screenshot.width * screenshot.height)
+ screenshot.getPixels(pixels, 0, screenshot.width, 0, 0, screenshot.width, screenshot.height)
+ for (i in bounds.left + 10..bounds.right - 10) {
+ for (j in bounds.top + 10..bounds.bottom - 10) {
+ val actualColor = pixels[j * screenshot.width + i]
+ if (actualColor != color) {
+ val screenshotPath = instrumentation.targetContext
+ .getExternalFilesDir(null)?.resolve("screenshot.png")
+ try {
+ FileOutputStream(screenshotPath).use { out ->
+ screenshot.compress(Bitmap.CompressFormat.PNG, 100, out)
+ }
+ Log.e("SurfaceViewBufferTests", "Bitmap written to $screenshotPath")
+ } catch (e: IOException) {
+ Log.e("SurfaceViewBufferTests", "Error writing bitmap to file", e)
+ }
+ }
+ Assert.assertEquals("Checking $bounds found mismatch $i,$j",
+ Color.valueOf(color), Color.valueOf(actualColor))
+ }
+ }
+ }
+
+ private companion object {
+ private const val TRACE_FLAGS =
+ (1 shl 0) or (1 shl 5) or (1 shl 6) // TRACE_CRITICAL | TRACE_BUFFERS | TRACE_SYNC
+ }
+} \ No newline at end of file
diff --git a/tests/SurfaceViewBufferTests/src/com/android/test/SurfaceViewBufferTestBase.kt b/tests/SurfaceViewBufferTests/src/com/android/test/SurfaceViewBufferTestBase.kt
new file mode 100644
index 000000000000..093c3125f253
--- /dev/null
+++ b/tests/SurfaceViewBufferTests/src/com/android/test/SurfaceViewBufferTestBase.kt
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2020 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.test
+
+import android.app.Instrumentation
+import android.graphics.Point
+import android.provider.Settings
+import androidx.test.InstrumentationRegistry
+import org.junit.After
+import org.junit.Before
+import org.junit.Rule
+import org.junit.rules.TestName
+import org.junit.runners.Parameterized
+import kotlin.properties.Delegates
+
+open class SurfaceViewBufferTestBase(val useBlastAdapter: Boolean) {
+ private var mInitialBlastConfig by Delegates.notNull<Boolean>()
+
+ val instrumentation: Instrumentation
+ get() = InstrumentationRegistry.getInstrumentation()
+
+ @get:Rule
+ var mName = TestName()
+
+ @Before
+ open fun setup() {
+ mInitialBlastConfig = getBlastAdapterSvEnabled()
+ setBlastAdapterSvEnabled(useBlastAdapter)
+ }
+
+ @After
+ open fun teardown() {
+ setBlastAdapterSvEnabled(mInitialBlastConfig)
+ }
+
+ private fun getBlastAdapterSvEnabled(): Boolean {
+ return Settings.Global.getInt(instrumentation.context.contentResolver,
+ "use_blast_adapter_sv", 0) != 0
+ }
+
+ private fun setBlastAdapterSvEnabled(enable: Boolean) {
+ Settings.Global.putInt(instrumentation.context.contentResolver, "use_blast_adapter_sv",
+ if (enable) 1 else 0)
+ }
+
+ companion object {
+ @JvmStatic
+ @Parameterized.Parameters(name = "blast={0}")
+ fun data(): Collection<Array<Any>> {
+ return listOf(
+ arrayOf(false), // First test: submit buffers via bufferqueue
+ arrayOf(true) // Second test: submit buffers via blast adapter
+ )
+ }
+
+ const val R8G8B8A8_UNORM = 1
+ val defaultBufferSize = Point(640, 480)
+
+ // system/window.h definitions
+ enum class ScalingMode() {
+ FREEZE, // = 0
+ SCALE_TO_WINDOW, // =1
+ SCALE_CROP, // = 2
+ NO_SCALE_CROP // = 3
+ }
+
+ // system/window.h definitions
+ enum class Transform(val value: Int) {
+ /* flip source image horizontally */
+ FLIP_H(1),
+ /* flip source image vertically */
+ FLIP_V(2),
+ /* rotate source image 90 degrees clock-wise, and is applied after TRANSFORM_FLIP_{H|V} */
+ ROT_90(4),
+ /* rotate source image 180 degrees */
+ ROT_180(3),
+ /* rotate source image 270 degrees clock-wise */
+ ROT_270(7),
+ /* transforms source by the inverse transform of the screen it is displayed onto. This
+ * transform is applied last */
+ INVERSE_DISPLAY(0x08)
+ }
+ }
+} \ No newline at end of file
diff --git a/tests/SystemUIDemoModeController/AndroidManifest.xml b/tests/SystemUIDemoModeController/AndroidManifest.xml
index 2e97932df525..5feb4acf259d 100644
--- a/tests/SystemUIDemoModeController/AndroidManifest.xml
+++ b/tests/SystemUIDemoModeController/AndroidManifest.xml
@@ -15,23 +15,21 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.example.android.demomodecontroller"
- android:versionCode="1"
- android:versionName="0.1" >
+ package="com.example.android.demomodecontroller"
+ android:versionCode="1"
+ android:versionName="0.1">
- <uses-sdk
- android:minSdkVersion="19"
- android:targetSdkVersion="19" />
+ <uses-sdk android:minSdkVersion="19"
+ android:targetSdkVersion="19"/>
- <application
- android:allowBackup="false"
- android:label="@string/app_name" >
- <activity
- android:name=".DemoModeController" >
+ <application android:allowBackup="false"
+ android:label="@string/app_name">
+ <activity android:name=".DemoModeController"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
diff --git a/tests/TaskOrganizerTest/Android.bp b/tests/TaskOrganizerTest/Android.bp
index 56d569548006..9b72d359aae6 100644
--- a/tests/TaskOrganizerTest/Android.bp
+++ b/tests/TaskOrganizerTest/Android.bp
@@ -25,7 +25,20 @@ package {
android_test {
name: "TaskOrganizerTest",
- srcs: ["**/*.java"],
+ srcs: ["**/*.java","**/*.kt"],
+ manifest: "AndroidManifest.xml",
+ test_config: "AndroidTest.xml",
platform_apis: true,
certificate: "platform",
-}
+
+ static_libs: [
+ "androidx.appcompat_appcompat",
+ "androidx.test.rules",
+ "androidx.test.runner",
+ "androidx.test.ext.junit",
+ "kotlin-stdlib",
+ "kotlinx-coroutines-android",
+ "flickerlib",
+ "truth-prebuilt",
+ ],
+} \ No newline at end of file
diff --git a/tests/TaskOrganizerTest/AndroidManifest.xml b/tests/TaskOrganizerTest/AndroidManifest.xml
index a77d7ee80242..1f1bd3ef7d81 100644
--- a/tests/TaskOrganizerTest/AndroidManifest.xml
+++ b/tests/TaskOrganizerTest/AndroidManifest.xml
@@ -10,20 +10,47 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.test.taskembed">
- <uses-permission android:name="android.permission.CHANGE_CONFIGURATION" />
- <uses-permission android:name="android.permission.MANAGE_ACTIVITY_STACKS" />
- <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
+ package="com.android.test.taskembed">
+ <uses-permission android:name="android.permission.CHANGE_CONFIGURATION"/>
+ <uses-permission android:name="android.permission.MANAGE_ACTIVITY_TASKS"/>
+ <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL"/>
+ <!-- Enable / Disable tracing !-->
+ <uses-permission android:name="android.permission.DUMP" />
<application>
- <service android:name=".TaskOrganizerPipTest"
- android:exported="true">
- </service>
- <activity android:name="TaskOrganizerMultiWindowTest" android:label="TaskOrganizer MW Test">
+ <activity android:name="TaskOrganizerMultiWindowTest"
+ android:label="TaskOrganizer MW Test"
+ android:exported="true"
+ android:excludeFromRecents="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
+ <activity android:name="TaskOrganizerMultiWindowTest$TestActivity1"
+ android:label="Test Activity 1"
+ android:exported="false"
+ android:theme="@android:style/Theme.Holo.NoActionBar.Fullscreen"
+ android:taskAffinity="com.android.test.taskembed.task1"
+ android:excludeFromRecents="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ </intent-filter>
+ </activity>
+ <activity android:name="TaskOrganizerMultiWindowTest$TestActivity2"
+ android:label="Test Activity 2"
+ android:exported="false"
+ android:theme="@android:style/Theme.Holo.NoActionBar.Fullscreen"
+ android:taskAffinity="com.android.test.taskembed.task2"
+ android:excludeFromRecents="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ </intent-filter>
+ </activity>
</application>
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.test.taskembed"
+ android:label="TaskOrganizerTest">
+ </instrumentation>
</manifest>
diff --git a/tests/TaskOrganizerTest/AndroidTest.xml b/tests/TaskOrganizerTest/AndroidTest.xml
new file mode 100644
index 000000000000..45fd8b0a6e3a
--- /dev/null
+++ b/tests/TaskOrganizerTest/AndroidTest.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 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.
+-->
+<configuration description="Runs TaskOrganizer Test">
+ <option name="test-tag" value="TaskOrganizerTest" />
+ <target_preparer class="com.android.tradefed.targetprep.DeviceSetup">
+ <!-- keeps the screen on during tests -->
+ <option name="screen-always-on" value="on" />
+ <!-- prevents the phone from restarting -->
+ <option name="force-skip-system-props" value="true" />
+ </target_preparer>
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="false"/>
+ <option name="test-file-name" value="TaskOrganizerTest.apk"/>
+ </target_preparer>
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest">
+ <option name="package" value="com.android.test.taskembed"/>
+ <option name="exclude-annotation" value="androidx.test.filters.FlakyTest" />
+ <option name="shell-timeout" value="6600s" />
+ <option name="test-timeout" value="6000s" />
+ <option name="hidden-api-checks" value="false" />
+ </test>
+</configuration>
diff --git a/tests/TaskOrganizerTest/src/com/android/test/taskembed/ResizeTasksSyncTest.kt b/tests/TaskOrganizerTest/src/com/android/test/taskembed/ResizeTasksSyncTest.kt
new file mode 100644
index 000000000000..03b43cc5b18c
--- /dev/null
+++ b/tests/TaskOrganizerTest/src/com/android/test/taskembed/ResizeTasksSyncTest.kt
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2020 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.test.taskembed
+
+import android.app.Instrumentation
+import android.graphics.Point
+import android.graphics.Rect
+import androidx.test.ext.junit.rules.ActivityScenarioRule
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.runner.AndroidJUnit4
+import com.android.server.wm.flicker.monitor.LayersTraceMonitor
+import com.android.server.wm.flicker.monitor.withSFTracing
+import com.android.server.wm.flicker.traces.layers.LayersTraceSubject.Companion.assertThat
+import org.junit.After
+import org.junit.Before
+import org.junit.FixMethodOrder
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import java.util.concurrent.CountDownLatch
+import org.junit.Assert.assertNotEquals
+
+@RunWith(AndroidJUnit4::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+class ResizeTasksSyncTest {
+ @get:Rule
+ var scenarioRule: ActivityScenarioRule<TaskOrganizerMultiWindowTest> =
+ ActivityScenarioRule<TaskOrganizerMultiWindowTest>(
+ TaskOrganizerMultiWindowTest::class.java)
+
+ protected val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+
+ @Before
+ fun setup() {
+ val tmpDir = instrumentation.targetContext.dataDir.toPath()
+ LayersTraceMonitor(tmpDir).stop()
+ val firstTaskBounds = Rect(0, 0, 1080, 1000)
+ val secondTaskBounds = Rect(0, 1000, 1080, 2000)
+
+ lateinit var surfaceReadyLatch: CountDownLatch
+ scenarioRule.getScenario().onActivity {
+ surfaceReadyLatch = it.openTaskView(firstTaskBounds, secondTaskBounds)
+ }
+ surfaceReadyLatch.await()
+ }
+
+ @After
+ fun teardown() {
+ scenarioRule.getScenario().close()
+ }
+
+ @Test
+ fun testResizeTwoTaskSync() {
+ val firstBounds = Rect(0, 0, 1080, 800)
+ val secondBounds = Rect(0, 1000, 1080, 1800)
+
+ val trace = withSFTracing(TRACE_FLAGS,
+ outputDir = instrumentation.targetContext.dataDir.toPath()) {
+ lateinit var resizeReadyLatch: CountDownLatch
+ scenarioRule.getScenario().onActivity {
+ resizeReadyLatch = it.resizeTaskView(firstBounds, secondBounds)
+ }
+ resizeReadyLatch.await()
+ }
+
+ // find the frame which match resized buffer size.
+ val frame = trace.entries.flatMap { it.flattenedLayers.toList() }
+ .firstOrNull { layer ->
+ !layer.isActiveBufferEmpty &&
+ layer.activeBuffer?.width == firstBounds.width() &&
+ layer.activeBuffer?.height == firstBounds.height()
+ }?.currFrame ?: -1
+
+ assertNotEquals(-1, frame)
+ // layer bounds should be related to parent surfaceview.
+ secondBounds.offsetTo(0, 0)
+
+ // verify buffer size should be changed to expected values.
+ assertThat(trace).layer(FIRST_ACTIVITY, frame.toLong()).also {
+ val firstTaskSize = Point(firstBounds.width(), firstBounds.height())
+ it.hasLayerSize(firstTaskSize)
+ it.hasBufferSize(firstTaskSize)
+ }
+
+ assertThat(trace).layer(SECOND_ACTIVITY, frame.toLong()).also {
+ val secondTaskSize = Point(secondBounds.width(), secondBounds.height())
+ it.hasLayerSize(secondTaskSize)
+ it.hasBufferSize(secondTaskSize)
+ }
+ }
+
+ companion object {
+ private const val TRACE_FLAGS = 0x1 // TRACE_CRITICAL
+ private const val FIRST_ACTIVITY = "Activity1"
+ private const val SECOND_ACTIVITY = "Activity2"
+ }
+} \ No newline at end of file
diff --git a/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerMultiWindowTest.java b/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerMultiWindowTest.java
index 073ae30aaf1a..0cf5a41de82a 100644
--- a/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerMultiWindowTest.java
+++ b/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerMultiWindowTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2020 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.
@@ -16,189 +16,182 @@
package com.android.test.taskembed;
-import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
+import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
import android.app.Activity;
import android.app.ActivityManager;
-import android.app.ActivityOptions;
import android.content.Context;
import android.content.Intent;
+import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Rect;
import android.os.Bundle;
import android.view.Gravity;
-import android.view.MotionEvent;
import android.view.SurfaceControl;
-import android.view.SurfaceHolder;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.LinearLayout;
+import android.widget.FrameLayout;
+import android.widget.TextView;
import android.window.TaskOrganizer;
-import android.window.WindowContainerTransaction;
import android.window.WindowContainerTransactionCallback;
-public class TaskOrganizerMultiWindowTest extends Activity {
- static class SplitLayout extends LinearLayout implements View.OnTouchListener {
- View mView1;
- View mView2;
- View mDividerView;
-
- public boolean onTouch(View v, MotionEvent e) {
- if (e.getAction() != MotionEvent.ACTION_UP) {
- return true;
- }
-
- float x = e.getRawX(0);
- float ratio = (float) x / (float) getWidth() ;
- ratio = 1-ratio;
-
- LinearLayout.LayoutParams lp1 =
- new LinearLayout.LayoutParams(0,
- ViewGroup.LayoutParams.WRAP_CONTENT, ratio-0.02f);
- LinearLayout.LayoutParams lp2 =
- new LinearLayout.LayoutParams(0,
- ViewGroup.LayoutParams.WRAP_CONTENT, 1-ratio-0.02f);
- updateViewLayout(mView1, lp2);
- updateViewLayout(mView2, lp1);
- return true;
- }
-
- SplitLayout(Context c, View v1, View v2) {
- super(c);
- LinearLayout.LayoutParams lp1 =
- new LinearLayout.LayoutParams(0,
- ViewGroup.LayoutParams.WRAP_CONTENT, 0.48f);
- LinearLayout.LayoutParams lp3 =
- new LinearLayout.LayoutParams(0,
- ViewGroup.LayoutParams.WRAP_CONTENT, 0.48f);
- LinearLayout.LayoutParams lp2 =
- new LinearLayout.LayoutParams(0,
- ViewGroup.LayoutParams.FILL_PARENT, 0.04f);
- lp2.gravity = Gravity.CENTER;
-
- setWeightSum(1);
-
- mView1 = v1;
- mView2 = v2;
- addView(mView1, lp1);
-
- mDividerView = new View(getContext());
- mDividerView.setBackgroundColor(Color.BLACK);
- addView(mDividerView, lp2);
- mDividerView.setOnTouchListener(this);
-
- addView(mView2, lp3);
- }
- }
-
- class ResizingTaskView extends TaskView {
- final Intent mIntent;
- boolean launched = false;
- ResizingTaskView(Context c, Intent i) {
- super(c);
- mIntent = i;
- }
+import java.util.concurrent.CountDownLatch;
- @Override
- public void surfaceChanged(SurfaceHolder h, int format, int width, int height) {
- if (!launched) {
- launchOrganizedActivity(mIntent, width, height);
- launched = true;
- } else {
- resizeTask(width, height);
- }
- }
-
- void resizeTask(int width, int height) {
- final WindowContainerTransaction wct = new WindowContainerTransaction();
- wct.setBounds(mWc, new Rect(0, 0, width, height));
- try {
- mOrganizer.applySyncTransaction(wct, mOrganizer.mTransactionCallback);
- } catch (Exception e) {
- // Oh well
- }
- }
- }
-
- private TaskView mTaskView1;
- private TaskView mTaskView2;
- private boolean mGotFirstTask = false;
+public class TaskOrganizerMultiWindowTest extends Activity {
+ private CountDownLatch mTasksReadyLatch;
+ private CountDownLatch mTasksResizeLatch;
class Organizer extends TaskOrganizer {
- private int receivedTransactions = 0;
- SurfaceControl.Transaction mergedTransaction = new SurfaceControl.Transaction();
+ private int mReceivedTransactions = 0;
+ private SurfaceControl.Transaction mMergedTransaction = new SurfaceControl.Transaction();
WindowContainerTransactionCallback mTransactionCallback =
new WindowContainerTransactionCallback() {
@Override
public void onTransactionReady(int id, SurfaceControl.Transaction t) {
- mergedTransaction.merge(t);
- receivedTransactions++;
- if (receivedTransactions == 2) {
- mergedTransaction.apply();
- receivedTransactions = 0;
+ mMergedTransaction.merge(t);
+ mReceivedTransactions++;
+ if (mReceivedTransactions == 2) {
+ mReceivedTransactions = 0;
+ mMergedTransaction.apply(true);
+ if (mTasksResizeLatch != null) {
+ mTasksResizeLatch.countDown();
+ }
}
}
};
@Override
public void onTaskAppeared(ActivityManager.RunningTaskInfo ti, SurfaceControl leash) {
- if (!mGotFirstTask) {
+ if (ti.baseActivity == null) {
+ return;
+ }
+
+ final String clsName = ti.baseActivity.getClassName();
+ if (clsName.contentEquals(TestActivity1.class.getName())) {
mTaskView1.reparentTask(ti.token, leash);
- mGotFirstTask = true;
- } else {
+ mOrganizer.setInterceptBackPressedOnTaskRoot(ti.token, true);
+ mTasksReadyLatch.countDown();
+ } else if (clsName.contentEquals(TestActivity2.class.getName())) {
mTaskView2.reparentTask(ti.token, leash);
+ mOrganizer.setInterceptBackPressedOnTaskRoot(ti.token, true);
+ mTasksReadyLatch.countDown();
}
}
+
+ @Override
+ public void onBackPressedOnTaskRoot(ActivityManager.RunningTaskInfo taskInfo) {
+ getMainThreadHandler().post(() -> {
+ finish();
+ });
+ }
}
private Organizer mOrganizer = new Organizer();
-
+ private FrameLayout mTasksLayout;
+ private TaskView mTaskView1;
+ private TaskView mTaskView2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ getWindow().getAttributes().layoutInDisplayCutoutMode =
+ LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
- mOrganizer.registerOrganizer(WINDOWING_MODE_MULTI_WINDOW);
-
- mTaskView1 = new ResizingTaskView(this, makeSettingsIntent());
- mTaskView2 = new ResizingTaskView(this, makeContactsIntent());
- View splitView = new SplitLayout(this, mTaskView1, mTaskView2);
+ mTasksLayout = new FrameLayout(this);
+ setContentView(mTasksLayout);
- setContentView(splitView);
+ mOrganizer.registerOrganizer();
}
@Override
protected void onDestroy() {
super.onDestroy();
mOrganizer.unregisterOrganizer();
+ mTasksLayout.removeAllViews();
}
- private void addFlags(Intent intent) {
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_NO_ANIMATION);
+ private Intent makeActivityIntent(final Class<?> clazz) {
+ Intent intent = new Intent(this, clazz);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_NO_ANIMATION
+ | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+ return intent;
}
- private Intent makeSettingsIntent() {
- Intent intent = new Intent();
- intent.setAction(android.provider.Settings.ACTION_SETTINGS);
- addFlags(intent);
- return intent;
+ public CountDownLatch openTaskView(Rect firstBounds, Rect secondBounds) {
+ mTasksReadyLatch = new CountDownLatch(2);
+ mTaskView1 = new TaskView(this, mOrganizer, makeActivityIntent(TestActivity1.class));
+ mTaskView1.setBackgroundColor(Color.DKGRAY);
+
+ FrameLayout.LayoutParams viewLayout1 =
+ new FrameLayout.LayoutParams(firstBounds.width(), firstBounds.height(),
+ Gravity.TOP | Gravity.LEFT);
+ viewLayout1.setMargins(firstBounds.left, firstBounds.top, 0, 0);
+ mTasksLayout.addView(mTaskView1, viewLayout1);
+
+ mTaskView2 = new TaskView(this, mOrganizer, makeActivityIntent(TestActivity2.class));
+ mTaskView2.setBackgroundColor(Color.LTGRAY);
+ FrameLayout.LayoutParams viewLayout2 =
+ new FrameLayout.LayoutParams(secondBounds.width(), secondBounds.height(),
+ Gravity.TOP | Gravity.LEFT);
+ viewLayout2.setMargins(secondBounds.left, secondBounds.top, 0, 0);
+ mTasksLayout.addView(mTaskView2, viewLayout2);
+ return mTasksReadyLatch;
}
- private Intent makeContactsIntent() {
- Intent intent = new Intent();
- intent.setAction(Intent.ACTION_MAIN);
- intent.addCategory(Intent.CATEGORY_APP_CONTACTS);
- addFlags(intent);
- return intent;
+ public CountDownLatch resizeTaskView(Rect firstBounds, Rect secondBounds) {
+ mTasksResizeLatch = new CountDownLatch(1);
+
+ mTaskView1.resizeTask(firstBounds.width(), firstBounds.height());
+ mTaskView2.resizeTask(secondBounds.width(), secondBounds.height());
+
+ return mTasksResizeLatch;
}
- private Bundle makeLaunchOptions(int width, int height) {
- ActivityOptions o = ActivityOptions.makeBasic();
- o.setLaunchWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
- o.setLaunchBounds(new Rect(0, 0, width, height));
- return o.toBundle();
+ static class InstrumentedTextView extends TextView {
+ private final boolean mSlowDraw;
+ InstrumentedTextView(Context context, boolean slowDraw) {
+ super(context);
+ mSlowDraw = slowDraw;
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+ if (mSlowDraw) {
+ try {
+ Thread.sleep(20);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ }
}
- private void launchOrganizedActivity(Intent i, int width, int height) {
- startActivity(i, makeLaunchOptions(width, height));
+ public static class TestActivity1 extends Activity {
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ getWindow().getAttributes().layoutInDisplayCutoutMode =
+ LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
+
+ TextView v = new InstrumentedTextView(this, true);
+ v.setText("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"
+ + "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz");
+ v.setBackgroundColor(Color.RED);
+ v.setTextColor(Color.BLACK);
+ setContentView(v);
+ }
+ }
+
+ public static class TestActivity2 extends Activity {
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ getWindow().getAttributes().layoutInDisplayCutoutMode =
+ LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
+ TextView v = new InstrumentedTextView(this, false);
+ v.setText("ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ + "ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ");
+ v.setBackgroundColor(Color.GREEN);
+ v.setTextColor(Color.BLACK);
+ setContentView(v);
+ }
}
}
diff --git a/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerPipTest.java b/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerPipTest.java
deleted file mode 100644
index 8fc5c5d78b60..000000000000
--- a/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerPipTest.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright (C) 2019 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.test.taskembed;
-
-import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
-
-import android.app.ActivityManager;
-import android.app.Service;
-import android.content.Intent;
-import android.graphics.Rect;
-import android.os.IBinder;
-import android.view.SurfaceControl;
-import android.view.ViewGroup;
-import android.view.WindowManager;
-import android.widget.FrameLayout;
-import android.window.TaskOrganizer;
-import android.window.WindowContainerTransaction;
-
-public class TaskOrganizerPipTest extends Service {
- private static final int PIP_WIDTH = 640;
- private static final int PIP_HEIGHT = 360;
-
- private TaskView mTaskView;
-
- class Organizer extends TaskOrganizer {
- public void onTaskAppeared(ActivityManager.RunningTaskInfo ti, SurfaceControl leash) {
- mTaskView.reparentTask(ti.token, leash);
-
- final WindowContainerTransaction wct = new WindowContainerTransaction();
- wct.scheduleFinishEnterPip(ti.token, new Rect(0, 0, PIP_WIDTH, PIP_HEIGHT));
- applyTransaction(wct);
- }
- }
-
- private Organizer mOrganizer = new Organizer();
-
- @Override
- public IBinder onBind(Intent intent) {
- return null;
- }
-
- @Override
- public void onCreate() {
- super.onCreate();
-
- mOrganizer.registerOrganizer(WINDOWING_MODE_PINNED);
-
- final WindowManager.LayoutParams wlp = new WindowManager.LayoutParams();
- wlp.setTitle("TaskOrganizerPipTest");
- wlp.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
- wlp.width = wlp.height = ViewGroup.LayoutParams.WRAP_CONTENT;
-
- FrameLayout layout = new FrameLayout(this);
- ViewGroup.LayoutParams lp =
- new ViewGroup.LayoutParams(PIP_WIDTH, PIP_HEIGHT);
- mTaskView = new TaskView(this);
- layout.addView(mTaskView, lp);
-
- WindowManager wm = getSystemService(WindowManager.class);
- wm.addView(layout, wlp);
- }
-
- @Override
- public void onDestroy() {
- super.onDestroy();
- mOrganizer.unregisterOrganizer();
- }
-}
diff --git a/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskView.java b/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskView.java
index 208018c2543a..4ef91c7807f6 100644
--- a/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskView.java
+++ b/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskView.java
@@ -16,65 +16,113 @@
package com.android.test.taskembed;
+import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+
+import android.app.ActivityOptions;
import android.content.Context;
+import android.content.Intent;
+import android.graphics.Rect;
+import android.os.Bundle;
import android.view.SurfaceControl;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.window.WindowContainerToken;
+import android.window.WindowContainerTransaction;
/**
* Simple SurfaceView wrapper which registers a TaskOrganizer
* after it's Surface is ready.
*/
-class TaskView extends SurfaceView implements SurfaceHolder.Callback {
- WindowContainerToken mWc;
+class TaskView extends SurfaceView {
+ private WindowContainerToken mWc;
+ private Context mContext;
private SurfaceControl mLeash;
+ private TaskOrganizerMultiWindowTest.Organizer mOrganizer;
+ private Intent mIntent;
+ private boolean mLaunched = false;
- private boolean mSurfaceCreated = false;
- private boolean mNeedsReparent;
-
- TaskView(Context c) {
+ TaskView(Context c, TaskOrganizerMultiWindowTest.Organizer organizer,
+ Intent intent) {
super(c);
- getHolder().addCallback(this);
+ mContext = c;
+ mOrganizer = organizer;
+ mIntent = intent;
+ getHolder().addCallback(
+ new SurfaceHolder.Callback() {
+ @Override
+ public void surfaceCreated(SurfaceHolder holder) {}
+
+ @Override
+ public void surfaceChanged(SurfaceHolder holder,
+ int format, int width, int height) {
+ if (!mLaunched) {
+ launchOrganizedActivity(mIntent, width, height);
+ mLaunched = true;
+ } else {
+ resizeTask(width, height);
+ }
+ }
+
+ @Override
+ public void surfaceDestroyed(SurfaceHolder holder) {}
+ }
+ );
setZOrderOnTop(true);
}
- @Override
- public void surfaceCreated(SurfaceHolder holder) {
- mSurfaceCreated = true;
- if (mNeedsReparent) {
- mNeedsReparent = false;
- reparentLeash();
- }
+ private void launchOrganizedActivity(Intent i, int width, int height) {
+ mContext.startActivity(i, makeLaunchOptions(width, height));
}
- @Override
- public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
+ private Bundle makeLaunchOptions(int width, int height) {
+ ActivityOptions o = ActivityOptions.makeBasic();
+ o.setLaunchWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
+ o.setLaunchBounds(new Rect(0, 0, width, height));
+ o.setTaskOverlay(true, true);
+ o.setTaskAlwaysOnTop(true);
+ return o.toBundle();
}
- @Override
- public void surfaceDestroyed(SurfaceHolder holder) {
+ void resizeTask(int width, int height) {
+ final WindowContainerTransaction wct = new WindowContainerTransaction();
+ wct.setBounds(mWc, new Rect(0, 0, width, height)).setHidden(mWc, false);
+ try {
+ mOrganizer.applySyncTransaction(wct, mOrganizer.mTransactionCallback);
+ } catch (Exception e) {
+ // Oh well
+ }
+ }
+
+ void hideTask() {
+ if (mWc == null) {
+ return;
+ }
+ final WindowContainerTransaction wct = new WindowContainerTransaction();
+ wct.setWindowingMode(mWc, WINDOWING_MODE_UNDEFINED).setHidden(mWc, true);
+ try {
+ mOrganizer.applySyncTransaction(wct, mOrganizer.mTransactionCallback);
+ } catch (Exception e) {
+ // Oh well
+ }
+ releaseLeash();
}
void reparentTask(WindowContainerToken wc, SurfaceControl leash) {
mWc = wc;
mLeash = leash;
- if (!mSurfaceCreated) {
- mNeedsReparent = true;
- } else {
- reparentLeash();
- }
+ reparentLeash();
}
- private void reparentLeash() {
+ void reparentLeash() {
SurfaceControl.Transaction t = new SurfaceControl.Transaction();
- if (mLeash == null) {
- return;
- }
-
t.reparent(mLeash, getSurfaceControl())
- .setPosition(mLeash, 0, 0)
.show(mLeash)
.apply();
}
+
+ void releaseLeash() {
+ SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+ t.remove(mLeash).apply();
+ }
}
diff --git a/tests/TelephonyCommonTests/src/com/android/internal/telephony/tests/SmsApplicationTest.java b/tests/TelephonyCommonTests/src/com/android/internal/telephony/tests/SmsApplicationTest.java
index 83fd20803ed8..7ee19fb37244 100644
--- a/tests/TelephonyCommonTests/src/com/android/internal/telephony/tests/SmsApplicationTest.java
+++ b/tests/TelephonyCommonTests/src/com/android/internal/telephony/tests/SmsApplicationTest.java
@@ -46,6 +46,7 @@ import android.content.pm.ServiceInfo;
import android.net.Uri;
import android.os.Handler;
import android.os.UserHandle;
+import android.os.UserManager;
import android.provider.Telephony;
import android.telephony.TelephonyManager;
@@ -103,6 +104,7 @@ public class SmsApplicationTest {
@Mock private TelephonyManager mTelephonyManager;
@Mock private RoleManager mRoleManager;
@Mock private PackageManager mPackageManager;
+ @Mock private UserManager mUserManager;
@Mock private AppOpsManager mAppOpsManager;
@Before
@@ -112,6 +114,7 @@ public class SmsApplicationTest {
when(mContext.getSystemService(Context.ROLE_SERVICE)).thenReturn(mRoleManager);
when(mContext.getPackageManager()).thenReturn(mPackageManager);
when(mContext.getSystemService(RoleManager.class)).thenReturn(mRoleManager);
+ when(mContext.getSystemService(UserManager.class)).thenReturn(mUserManager);
when(mContext.getSystemService(AppOpsManager.class)).thenReturn(mAppOpsManager);
when(mContext.createContextAsUser(isNotNull(), anyInt())).thenReturn(mContext);
@@ -130,8 +133,10 @@ public class SmsApplicationTest {
when(mTelephonyManager.isSmsCapable()).thenReturn(true);
when(mRoleManager.isRoleAvailable(RoleManager.ROLE_SMS)).thenReturn(true);
- when(mRoleManager.getDefaultSmsPackage(anyInt()))
+ when(mRoleManager.getSmsRoleHolder(anyInt()))
.thenReturn(TEST_COMPONENT_NAME.getPackageName());
+ when(mUserManager.getUserHandles(true))
+ .thenReturn(Collections.singletonList(UserHandle.SYSTEM));
for (String opStr : APP_OPS_TO_CHECK) {
when(mAppOpsManager.unsafeCheckOp(
diff --git a/tests/TouchLatency/app/src/main/AndroidManifest.xml b/tests/TouchLatency/app/src/main/AndroidManifest.xml
index e4aa4dc6c3f0..98947367bd7b 100644
--- a/tests/TouchLatency/app/src/main/AndroidManifest.xml
+++ b/tests/TouchLatency/app/src/main/AndroidManifest.xml
@@ -15,20 +15,19 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.prefabulated.touchlatency" >
+ package="com.prefabulated.touchlatency">
- <application
- android:allowBackup="true"
- android:icon="@mipmap/ic_launcher"
- android:label="@string/app_name"
- android:theme="@style/AppTheme" >
- <activity
- android:name=".TouchLatencyActivity"
- android:label="@string/app_name" >
+ <application android:allowBackup="true"
+ android:icon="@mipmap/ic_launcher"
+ android:label="@string/app_name"
+ android:theme="@style/AppTheme">
+ <activity android:name=".TouchLatencyActivity"
+ android:label="@string/app_name"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
+ <action android:name="android.intent.action.MAIN"/>
- <category android:name="android.intent.category.LAUNCHER" />
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
diff --git a/tests/TouchLatency/gradle/wrapper/gradle-wrapper.jar b/tests/TouchLatency/gradle/wrapper/gradle-wrapper.jar
index 8c0fb64a8698..758de960ec79 100644
--- a/tests/TouchLatency/gradle/wrapper/gradle-wrapper.jar
+++ b/tests/TouchLatency/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/tests/TouchLatency/gradle/wrapper/gradle-wrapper.properties b/tests/TouchLatency/gradle/wrapper/gradle-wrapper.properties
index 111992a460fa..2d80b69a7665 100644
--- a/tests/TouchLatency/gradle/wrapper/gradle-wrapper.properties
+++ b/tests/TouchLatency/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,5 @@
-#Tue Nov 27 13:37:59 PST 2018
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.8.1-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip
diff --git a/tests/TouchLatency/gradlew b/tests/TouchLatency/gradlew
index 91a7e269e19d..cccdd3d517fc 100755
--- a/tests/TouchLatency/gradlew
+++ b/tests/TouchLatency/gradlew
@@ -1,4 +1,4 @@
-#!/usr/bin/env bash
+#!/usr/bin/env sh
##############################################################################
##
@@ -6,20 +6,38 @@
##
##############################################################################
-# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-DEFAULT_JVM_OPTS=""
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
-warn ( ) {
+warn () {
echo "$*"
}
-die ( ) {
+die () {
echo
echo "$*"
echo
@@ -30,6 +48,7 @@ die ( ) {
cygwin=false
msys=false
darwin=false
+nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
@@ -40,31 +59,11 @@ case "`uname`" in
MINGW* )
msys=true
;;
+ NONSTOP* )
+ nonstop=true
+ ;;
esac
-# For Cygwin, ensure paths are in UNIX format before anything is touched.
-if $cygwin ; then
- [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
-fi
-
-# Attempt to set APP_HOME
-# Resolve links: $0 may be a link
-PRG="$0"
-# Need this for relative symlinks.
-while [ -h "$PRG" ] ; do
- ls=`ls -ld "$PRG"`
- link=`expr "$ls" : '.*-> \(.*\)$'`
- if expr "$link" : '/.*' > /dev/null; then
- PRG="$link"
- else
- PRG=`dirname "$PRG"`"/$link"
- fi
-done
-SAVED="`pwd`"
-cd "`dirname \"$PRG\"`/" >&-
-APP_HOME="`pwd -P`"
-cd "$SAVED" >&-
-
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
@@ -90,7 +89,7 @@ location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
-if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
@@ -114,6 +113,7 @@ fi
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+ JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
@@ -154,11 +154,19 @@ if $cygwin ; then
esac
fi
-# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
-function splitJvmOpts() {
- JVM_OPTS=("$@")
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
}
-eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
-JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
+APP_ARGS=$(save "$@")
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
+if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
+ cd "$(dirname "$0")"
+fi
-exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
+exec "$JAVACMD" "$@"
diff --git a/tests/TouchLatency/gradlew.bat b/tests/TouchLatency/gradlew.bat
index aec99730b4e8..e95643d6a2ca 100644
--- a/tests/TouchLatency/gradlew.bat
+++ b/tests/TouchLatency/gradlew.bat
@@ -8,14 +8,14 @@
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
-@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-set DEFAULT_JVM_OPTS=
-
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
@@ -46,10 +46,9 @@ echo location of your Java installation.
goto fail
:init
-@rem Get command-line arguments, handling Windowz variants
+@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
-if "%@eval[2+2]" == "4" goto 4NT_args
:win9xME_args
@rem Slurp the command line arguments.
@@ -60,11 +59,6 @@ set _SKIP=2
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
-goto execute
-
-:4NT_args
-@rem Get arguments from the 4NT Shell from JP Software
-set CMD_LINE_ARGS=%$
:execute
@rem Setup the command line
diff --git a/tests/TransformTest/AndroidManifest.xml b/tests/TransformTest/AndroidManifest.xml
index 5c9995f25ec6..19854feeabd3 100644
--- a/tests/TransformTest/AndroidManifest.xml
+++ b/tests/TransformTest/AndroidManifest.xml
@@ -15,13 +15,15 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.google.android.test.transform">
- <uses-sdk android:minSdkVersion="7" android:targetSdkVersion="7" />
+ package="com.google.android.test.transform">
+ <uses-sdk android:minSdkVersion="7"
+ android:targetSdkVersion="7"/>
<application android:label="TransformTest">
- <activity android:name="TransformTestActivity">
+ <activity android:name="TransformTestActivity"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
diff --git a/tests/TransitionTests/AndroidManifest.xml b/tests/TransitionTests/AndroidManifest.xml
index 35e7b6979b7e..482261932003 100644
--- a/tests/TransitionTests/AndroidManifest.xml
+++ b/tests/TransitionTests/AndroidManifest.xml
@@ -1,250 +1,284 @@
<?xml version="1.0" encoding="utf-8"?>
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.transitiontests"
- android:versionCode="1"
- android:versionName="1.0">
- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
- <application
- android:icon="@drawable/icon"
- android:label="@string/app_name"
- android:hardwareAccelerated="true"
- android:theme="@style/AppTheme">
+ package="com.android.transitiontests"
+ android:versionCode="1"
+ android:versionName="1.0">
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
+ <application android:icon="@drawable/icon"
+ android:label="@string/app_name"
+ android:hardwareAccelerated="true"
+ android:theme="@style/AppTheme">
<activity android:label="@string/states_test1"
- android:name="ScenesTestv21">
+ android:name="ScenesTestv21"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:label="@string/states_test_auto_targets"
- android:name="ScenesTestAutoTargets">
+ android:name="ScenesTestAutoTargets"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:label="@string/states_test_auto_transition"
- android:name="ScenesTestAutoTransition">
+ android:name="ScenesTestAutoTransition"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:label="@string/states_test_auto_transition2"
- android:name="ScenesTestAutoTransition2">
+ android:name="ScenesTestAutoTransition2"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:label="@string/contacts_expansion"
- android:name="ContactsExpansion">
+ android:name="ContactsExpansion"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:label="Demo0"
- android:name="Demo0">
+ android:name="Demo0"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:label="Demo1"
- android:name="Demo1">
+ android:name="Demo1"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:label="Demo2"
- android:name="Demo2">
+ android:name="Demo2"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:label="Demo3"
- android:name="Demo3">
+ android:name="Demo3"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:label="Demo4"
- android:name="Demo4">
+ android:name="Demo4"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:label="Demo5"
- android:name="Demo5">
+ android:name="Demo5"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:label="LoginActivity"
- android:name="LoginActivity">
+ android:name="LoginActivity"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:label="LoginActivityFromResources"
- android:name="LoginActivityFromResources">
+ android:name="LoginActivityFromResources"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:label="OverlayTest"
- android:name="OverlayTest">
+ android:name="OverlayTest"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:label="ResourceLoadingTest"
- android:name="ResourceLoadingTest">
+ android:name="ResourceLoadingTest"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:label="FadingTest"
- android:name="FadingTest">
+ android:name="FadingTest"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:label="UniqueIds"
- android:name="UniqueIds">
+ android:name="UniqueIds"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:label="HitRectBug"
- android:name="HitRectBug">
+ android:name="HitRectBug"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:label="SequenceTest"
- android:name="SequenceTest">
+ android:name="SequenceTest"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:label="SequenceTestSimple"
- android:name="SequenceTestSimple">
+ android:name="SequenceTestSimple"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:label="ChangingText"
- android:name="ChangingText">
+ android:name="ChangingText"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:label="ClippingText"
- android:name="ClippingText">
+ android:name="ClippingText"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:label="ListViewAddRemove"
- android:name="ListViewAddRemove">
+ android:name="ListViewAddRemove"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:label="ListViewAddRemoveNoTransition"
- android:name="ListViewAddRemoveNoTransition">
+ android:name="ListViewAddRemoveNoTransition"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:label="CrossFadeDemo"
- android:name="CrossFadeDemo">
+ android:name="CrossFadeDemo"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:label="Reparenting"
- android:name="Reparenting">
+ android:name="Reparenting"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:label="SurfaceAndTextureViews"
- android:name="SurfaceAndTextureViews">
+ android:name="SurfaceAndTextureViews"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:label="InstanceTargets"
- android:name="InstanceTargets">
+ android:name="InstanceTargets"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:label="InterruptionTest"
- android:name="InterruptionTest">
+ android:name="InterruptionTest"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:label="DelayedTransition"
- android:name="DelayedTransition">
+ android:name="DelayedTransition"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:label="FadingHierachy"
- android:name=".FadingHierarchy">
+ android:name=".FadingHierarchy"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:label="HierarchicalMove"
- android:name=".HierarchicalMove">
+ android:name=".HierarchicalMove"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:label="CrossfadeImage"
- android:name=".CrossfadeImage">
+ android:name=".CrossfadeImage"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:label="CrossfadeMultiple"
- android:name=".CrossfadeMultiple">
+ android:name=".CrossfadeMultiple"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
diff --git a/tests/TtsTests/AndroidManifest.xml b/tests/TtsTests/AndroidManifest.xml
index b6d51114e399..cf1c1628951d 100644
--- a/tests/TtsTests/AndroidManifest.xml
+++ b/tests/TtsTests/AndroidManifest.xml
@@ -15,29 +15,32 @@ See the License for the specific language governing permissions and
limitations under the License.
-->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.speech.tts">
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.speech.tts">
<application>
- <uses-library android:name="android.test.runner" />
+ <uses-library android:name="android.test.runner"/>
<service android:name=".MockableTextToSpeechService"
- android:label="Mockable Text-to-speech Service">
+ android:label="Mockable Text-to-speech Service"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.TTS_SERVICE" />
- <category android:name="android.intent.category.DEFAULT" />
+ <action android:name="android.intent.action.TTS_SERVICE"/>
+ <category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</service>
<activity android:name=".MockableCheckVoiceData"
- android:theme="@android:style/Theme.NoDisplay">
+ android:theme="@android:style/Theme.NoDisplay"
+ android:exported="true">
<intent-filter>
- <action android:name="android.speech.tts.engine.CHECK_TTS_DATA" />
- <category android:name="android.intent.category.DEFAULT" />
+ <action android:name="android.speech.tts.engine.CHECK_TTS_DATA"/>
+ <category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
</application>
<instrumentation android:name="android.test.InstrumentationTestRunner"
- android:targetPackage="com.android.speech.tts"
- android:label="Tests for android.speech.tts" />
+ android:targetPackage="com.android.speech.tts"
+ android:label="Tests for android.speech.tts"/>
</manifest>
diff --git a/tests/UiBench/AndroidManifest.xml b/tests/UiBench/AndroidManifest.xml
index dd255ef5233b..4fc6ec71f29c 100644
--- a/tests/UiBench/AndroidManifest.xml
+++ b/tests/UiBench/AndroidManifest.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2015 The Android Open Source Project
~
@@ -13,303 +14,304 @@
~ See the License for the specific language governing permissions and
~ limitations under the License
-->
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- package="com.android.test.uibench">
+ xmlns:tools="http://schemas.android.com/tools"
+ package="com.android.test.uibench">
- <application
- android:allowBackup="false"
- android:theme="@style/Theme.AppCompat.Light.DarkActionBar"
- tools:ignore="MissingApplicationIcon">
- <uses-library android:name="android.test.runner" />
+ <application android:allowBackup="false"
+ android:theme="@style/Theme.AppCompat.Light.DarkActionBar"
+ tools:ignore="MissingApplicationIcon">
+ <uses-library android:name="android.test.runner"/>
<!-- Root navigation activity -->
- <activity
- android:name=".MainActivity"
- android:label="UiBench">
+ <activity android:name=".MainActivity"
+ android:label="UiBench"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<!-- General -->
- <activity
- android:name=".DialogListActivity"
- android:label="General/Dialog List" >
+ <activity android:name=".DialogListActivity"
+ android:label="General/Dialog List"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.uibench.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.uibench.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name=".GlTextureViewActivity"
- android:label="General/GL TextureView" >
+ <activity android:name=".GlTextureViewActivity"
+ android:label="General/GL TextureView"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.uibench.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.uibench.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name=".FullscreenOverdrawActivity"
- android:label="General/Fullscreen Overdraw" >
+ <activity android:name=".FullscreenOverdrawActivity"
+ android:label="General/Fullscreen Overdraw"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.uibench.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.uibench.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name=".InvalidateActivity"
- android:label="General/Invalidate" >
+ <activity android:name=".InvalidateActivity"
+ android:label="General/Invalidate"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.uibench.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.uibench.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name=".InvalidateTreeActivity"
- android:label="General/Invalidate Tree" >
+ <activity android:name=".InvalidateTreeActivity"
+ android:label="General/Invalidate Tree"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.uibench.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.uibench.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name=".ResizeHWLayerActivity"
- android:label="General/Resize HW Layer" >
+ <activity android:name=".ResizeHWLayerActivity"
+ android:label="General/Resize HW Layer"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.uibench.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.uibench.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name=".TrivialAnimationActivity"
- android:label="General/Trivial Animation" >
+ <activity android:name=".TrivialAnimationActivity"
+ android:label="General/Trivial Animation"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.uibench.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.uibench.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name=".TrivialAnimationActivityWideGamut"
- android:label="General/Trivial Animation (Wide Gamut)"
- android:colorMode="wideColorGamut">
+ <activity android:name=".TrivialAnimationActivityWideGamut"
+ android:label="General/Trivial Animation (Wide Gamut)"
+ android:colorMode="wideColorGamut"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.uibench.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.uibench.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name=".TrivialListActivity"
- android:label="General/Trivial ListView" >
+ <activity android:name=".TrivialListActivity"
+ android:label="General/Trivial ListView"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.uibench.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.uibench.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name=".FadingEdgeListActivity"
- android:label="General/Fading Edge ListView" >
+ <activity android:name=".FadingEdgeListActivity"
+ android:label="General/Fading Edge ListView"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.uibench.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.uibench.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name=".SaveLayerInterleaveActivity"
- android:label="General/SaveLayer Animation" >
+ <activity android:name=".SaveLayerInterleaveActivity"
+ android:label="General/SaveLayer Animation"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.uibench.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.uibench.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name=".ClippedListActivity"
- android:label="General/Clipped ListView"
- android:theme="@style/NoActionBar">
+ <activity android:name=".ClippedListActivity"
+ android:label="General/Clipped ListView"
+ android:theme="@style/NoActionBar"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.uibench.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.uibench.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name=".TrivialRecyclerViewActivity"
- android:label="General/Trivial RecyclerView" >
+ <activity android:name=".TrivialRecyclerViewActivity"
+ android:label="General/Trivial RecyclerView"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.uibench.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.uibench.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name=".SlowBindRecyclerViewActivity"
- android:label="General/Slow Bind RecyclerView" >
+ <activity android:name=".SlowBindRecyclerViewActivity"
+ android:label="General/Slow Bind RecyclerView"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.uibench.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.uibench.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name=".SlowNestedRecyclerViewActivity"
- android:label="General/Slow Nested RecyclerView" >
+ <activity android:name=".SlowNestedRecyclerViewActivity"
+ android:label="General/Slow Nested RecyclerView"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.uibench.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.uibench.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name=".ActivityTransition"
- android:label="Transitions/Activity Transition" >
+ <activity android:name=".ActivityTransition"
+ android:label="Transitions/Activity Transition"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.uibench.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.uibench.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name=".ActivityTransitionDetails"
- android:label="Transitions/Activity Transition " >
+ <activity android:name=".ActivityTransitionDetails"
+ android:label="Transitions/Activity Transition "
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
+ <action android:name="android.intent.action.MAIN"/>
<!-- Part of ActivityTransition test above, so not in TEST category -->
</intent-filter>
</activity>
<!-- Rendering -->
- <activity
- android:name=".BitmapUploadActivity"
- android:label="Rendering/Bitmap Upload" >
+ <activity android:name=".BitmapUploadActivity"
+ android:label="Rendering/Bitmap Upload"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.uibench.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.uibench.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name=".ShadowGridActivity"
- android:label="Rendering/Shadow Grid" >
+ <activity android:name=".ShadowGridActivity"
+ android:label="Rendering/Shadow Grid"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.uibench.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.uibench.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name=".RenderingJitter"
- android:label="Rendering/Jitter" >
+ <activity android:name=".RenderingJitter"
+ android:label="Rendering/Jitter"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.uibench.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.uibench.TEST"/>
</intent-filter>
</activity>
<!-- Inflation -->
- <activity
- android:name=".InflatingListActivity"
- android:label="Inflation/Inflating ListView" >
+ <activity android:name=".InflatingListActivity"
+ android:label="Inflation/Inflating ListView"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.uibench.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.uibench.TEST"/>
</intent-filter>
</activity>
- <activity-alias
- android:name=".InflatingEmojiListActivity"
- android:label="Inflation/Inflating ListView with Emoji"
- android:targetActivity=".InflatingListActivity">
+ <activity-alias android:name=".InflatingEmojiListActivity"
+ android:label="Inflation/Inflating ListView with Emoji"
+ android:targetActivity=".InflatingListActivity"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.uibench.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.uibench.TEST"/>
</intent-filter>
</activity-alias>
- <activity-alias
- android:name=".InflatingHanListActivity"
- android:label="Inflation/Inflating ListView with Han Characters"
- android:targetActivity=".InflatingListActivity">
+ <activity-alias android:name=".InflatingHanListActivity"
+ android:label="Inflation/Inflating ListView with Han Characters"
+ android:targetActivity=".InflatingListActivity"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.uibench.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.uibench.TEST"/>
</intent-filter>
</activity-alias>
- <activity-alias
- android:name=".InflatingLongStringListActivity"
- android:label="Inflation/Inflating ListView with long string"
- android:targetActivity=".InflatingListActivity">
+ <activity-alias android:name=".InflatingLongStringListActivity"
+ android:label="Inflation/Inflating ListView with long string"
+ android:targetActivity=".InflatingListActivity"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.uibench.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.uibench.TEST"/>
</intent-filter>
</activity-alias>
<!-- Text -->
- <activity
- android:name=".EditTextTypeActivity"
- android:label="Text/EditText Typing" >
+ <activity android:name=".EditTextTypeActivity"
+ android:label="Text/EditText Typing"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.uibench.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.uibench.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name=".TextCacheLowHitrateActivity"
- android:label="Text/Layout Cache Low Hitrate" >
+ <activity android:name=".TextCacheLowHitrateActivity"
+ android:label="Text/Layout Cache Low Hitrate"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.uibench.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.uibench.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name=".TextCacheHighHitrateActivity"
- android:label="Text/Layout Cache High Hitrate" >
+ <activity android:name=".TextCacheHighHitrateActivity"
+ android:label="Text/Layout Cache High Hitrate"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.uibench.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.uibench.TEST"/>
</intent-filter>
</activity>
<!-- WebView -->
- <activity
- android:name=".ScrollableWebViewActivity"
- android:label="WebView/Scrollable WebView" >
+ <activity android:name=".ScrollableWebViewActivity"
+ android:label="WebView/Scrollable WebView"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.uibench.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.uibench.TEST"/>
</intent-filter>
</activity>
<!-- Navigation Drawer -->
- <activity
- android:name=".NavigationDrawerActivity"
- android:label="Navigation Drawer Activity"
- android:theme="@style/NoActionBar">
+ <activity android:name=".NavigationDrawerActivity"
+ android:label="Navigation Drawer Activity"
+ android:theme="@style/NoActionBar"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.uibench.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.uibench.TEST"/>
</intent-filter>
</activity>
<!-- Notification Shade -->
- <activity
- android:name=".NotificationShadeActivity"
- android:label="Notification Shade">
+ <activity android:name=".NotificationShadeActivity"
+ android:label="Notification Shade"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.uibench.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.uibench.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name=".leanback.BrowseActivity"
- android:theme="@style/Theme.Leanback.Browse"
- android:label="Leanback/Browse Fragment" >
+ <activity android:name=".leanback.BrowseActivity"
+ android:theme="@style/Theme.Leanback.Browse"
+ android:label="Leanback/Browse Fragment"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.uibench.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.uibench.TEST"/>
</intent-filter>
</activity>
<activity
android:name="WindowInsetsControllerActivity"
- android:label="WindowInsetsControllerActivity" >
+ android:label="WindowInsetsControllerActivity"
+ android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.android.test.uibench.TEST" />
diff --git a/tests/UiBench/res/layout/recycler_view.xml b/tests/UiBench/res/layout/recycler_view.xml
index 53eab68f7866..c8a85de81710 100644
--- a/tests/UiBench/res/layout/recycler_view.xml
+++ b/tests/UiBench/res/layout/recycler_view.xml
@@ -17,5 +17,6 @@
<androidx.recyclerview.widget.RecyclerView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/recyclerView"
+ android:overScrollMode="never"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
diff --git a/tests/UpdatableSystemFontTest/Android.bp b/tests/UpdatableSystemFontTest/Android.bp
new file mode 100644
index 000000000000..e07fbbf7a1c1
--- /dev/null
+++ b/tests/UpdatableSystemFontTest/Android.bp
@@ -0,0 +1,51 @@
+// 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 {
+ // 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"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+android_test {
+ name: "UpdatableSystemFontTest",
+ srcs: ["src/**/*.java"],
+ libs: ["android.test.runner"],
+ static_libs: [
+ "androidx.test.ext.junit",
+ "androidx.test.uiautomator_uiautomator",
+ "compatibility-device-util-axt",
+ "platform-test-annotations",
+ "truth-prebuilt",
+ ],
+ test_suites: [
+ "general-tests",
+ "vts",
+ ],
+ data: [
+ ":NotoColorEmojiTtf",
+ ":UpdatableSystemFontTestCertDer",
+ ":UpdatableSystemFontTestNotoColorEmojiTtfFsvSig",
+ ":UpdatableSystemFontTestNotoColorEmojiV0Ttf",
+ ":UpdatableSystemFontTestNotoColorEmojiV0TtfFsvSig",
+ ":UpdatableSystemFontTestNotoColorEmojiVPlus1Ttf",
+ ":UpdatableSystemFontTestNotoColorEmojiVPlus1TtfFsvSig",
+ ":UpdatableSystemFontTestNotoColorEmojiVPlus2Ttf",
+ ":UpdatableSystemFontTestNotoColorEmojiVPlus2TtfFsvSig",
+ ],
+ sdk_version: "test_current",
+}
diff --git a/tests/UpdatableSystemFontTest/AndroidManifest.xml b/tests/UpdatableSystemFontTest/AndroidManifest.xml
new file mode 100644
index 000000000000..531ee981a92c
--- /dev/null
+++ b/tests/UpdatableSystemFontTest/AndroidManifest.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.updatablesystemfont">
+
+ <application android:label="UpdatableSystemFontTest">
+ <uses-library android:name="android.test.runner"/>
+ </application>
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:label="UpdatableSystemFontTest"
+ android:targetPackage="com.android.updatablesystemfont">
+ </instrumentation>
+
+</manifest>
diff --git a/tests/UpdatableSystemFontTest/AndroidTest.xml b/tests/UpdatableSystemFontTest/AndroidTest.xml
new file mode 100644
index 000000000000..4f6487e7e953
--- /dev/null
+++ b/tests/UpdatableSystemFontTest/AndroidTest.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<configuration description="Updatable system font integration/regression test">
+ <option name="test-suite-tag" value="apct" />
+
+ <!-- This test requires root to side load fs-verity cert. -->
+ <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer" />
+
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="test-file-name" value="UpdatableSystemFontTest.apk" />
+ <option name="test-file-name" value="EmojiRenderingTestApp.apk" />
+ </target_preparer>
+
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="cleanup" value="true" />
+ <option name="push" value="UpdatableSystemFontTestCert.der->/data/local/tmp/UpdatableSystemFontTestCert.der" />
+ <option name="push" value="NotoColorEmoji.ttf->/data/local/tmp/NotoColorEmoji.ttf" />
+ <option name="push" value="UpdatableSystemFontTestNotoColorEmoji.ttf.fsv_sig->/data/local/tmp/UpdatableSystemFontTestNotoColorEmoji.ttf.fsv_sig" />
+ <option name="push" value="UpdatableSystemFontTestNotoColorEmojiV0.ttf->/data/local/tmp/UpdatableSystemFontTestNotoColorEmojiV0.ttf" />
+ <option name="push" value="UpdatableSystemFontTestNotoColorEmojiV0.ttf.fsv_sig->/data/local/tmp/UpdatableSystemFontTestNotoColorEmojiV0.ttf.fsv_sig" />
+ <option name="push" value="UpdatableSystemFontTestNotoColorEmojiVPlus1.ttf->/data/local/tmp/UpdatableSystemFontTestNotoColorEmojiVPlus1.ttf" />
+ <option name="push" value="UpdatableSystemFontTestNotoColorEmojiVPlus1.ttf.fsv_sig->/data/local/tmp/UpdatableSystemFontTestNotoColorEmojiVPlus1.ttf.fsv_sig" />
+ <option name="push" value="UpdatableSystemFontTestNotoColorEmojiVPlus2.ttf->/data/local/tmp/UpdatableSystemFontTestNotoColorEmojiVPlus2.ttf" />
+ <option name="push" value="UpdatableSystemFontTestNotoColorEmojiVPlus2.ttf.fsv_sig->/data/local/tmp/UpdatableSystemFontTestNotoColorEmojiVPlus2.ttf.fsv_sig" />
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest">
+ <option name="package" value="com.android.updatablesystemfont" />
+ </test>
+</configuration>
diff --git a/tests/UpdatableSystemFontTest/EmojiRenderingTestApp/Android.bp b/tests/UpdatableSystemFontTest/EmojiRenderingTestApp/Android.bp
new file mode 100644
index 000000000000..ed34fa9fc1d0
--- /dev/null
+++ b/tests/UpdatableSystemFontTest/EmojiRenderingTestApp/Android.bp
@@ -0,0 +1,32 @@
+// 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 {
+ // 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"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+android_test_helper_app {
+ name: "EmojiRenderingTestApp",
+ manifest: "AndroidManifest.xml",
+ srcs: ["src/**/*.java"],
+ test_suites: [
+ "general-tests",
+ "vts",
+ ],
+}
diff --git a/tests/UpdatableSystemFontTest/EmojiRenderingTestApp/AndroidManifest.xml b/tests/UpdatableSystemFontTest/EmojiRenderingTestApp/AndroidManifest.xml
new file mode 100644
index 000000000000..8c3d87698e17
--- /dev/null
+++ b/tests/UpdatableSystemFontTest/EmojiRenderingTestApp/AndroidManifest.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * 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.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.emojirenderingtestapp">
+ <application>
+ <activity android:name=".EmojiRenderingTestActivity"/>
+ <activity android:name=".GetAvailableFontsTestActivity"/>
+ </application>
+</manifest>
diff --git a/tests/UpdatableSystemFontTest/EmojiRenderingTestApp/src/com/android/emojirenderingtestapp/EmojiRenderingTestActivity.java b/tests/UpdatableSystemFontTest/EmojiRenderingTestApp/src/com/android/emojirenderingtestapp/EmojiRenderingTestActivity.java
new file mode 100644
index 000000000000..947e9c2ff56a
--- /dev/null
+++ b/tests/UpdatableSystemFontTest/EmojiRenderingTestApp/src/com/android/emojirenderingtestapp/EmojiRenderingTestActivity.java
@@ -0,0 +1,40 @@
+/*
+ * 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.emojirenderingtestapp;
+
+import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
+import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+/** Test app to render an emoji. */
+public class EmojiRenderingTestActivity extends Activity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ LinearLayout container = new LinearLayout(this);
+ container.setOrientation(LinearLayout.VERTICAL);
+ TextView textView = new TextView(this);
+ textView.setText("\uD83E\uDD72"); // 🥲
+ container.addView(textView, new LinearLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT));
+ setContentView(container);
+ }
+}
diff --git a/tests/UpdatableSystemFontTest/EmojiRenderingTestApp/src/com/android/emojirenderingtestapp/GetAvailableFontsTestActivity.java b/tests/UpdatableSystemFontTest/EmojiRenderingTestApp/src/com/android/emojirenderingtestapp/GetAvailableFontsTestActivity.java
new file mode 100644
index 000000000000..b9a91490f517
--- /dev/null
+++ b/tests/UpdatableSystemFontTest/EmojiRenderingTestApp/src/com/android/emojirenderingtestapp/GetAvailableFontsTestActivity.java
@@ -0,0 +1,53 @@
+/*
+ * 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.emojirenderingtestapp;
+
+import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
+import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
+
+import android.app.Activity;
+import android.graphics.fonts.Font;
+import android.graphics.fonts.SystemFonts;
+import android.os.Bundle;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+public class GetAvailableFontsTestActivity extends Activity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ String emojiFontPath = "<Not found>";
+ for (Font font : SystemFonts.getAvailableFonts()) {
+ // Calls font attribute getters to make sure that they don't open font files.
+ font.getAxes();
+ font.getFile();
+ font.getLocaleList();
+ font.getStyle();
+ font.getTtcIndex();
+ if ("NotoColorEmoji.ttf".equals(font.getFile().getName())) {
+ emojiFontPath = font.getFile().getAbsolutePath();
+ }
+ }
+ LinearLayout container = new LinearLayout(this);
+ container.setOrientation(LinearLayout.VERTICAL);
+ TextView textView = new TextView(this);
+ textView.setText(emojiFontPath);
+ container.addView(textView, new LinearLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT));
+ setContentView(container);
+ }
+}
diff --git a/tests/UpdatableSystemFontTest/TEST_MAPPING b/tests/UpdatableSystemFontTest/TEST_MAPPING
new file mode 100644
index 000000000000..7fbf426c71c4
--- /dev/null
+++ b/tests/UpdatableSystemFontTest/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "presubmit": [
+ {
+ "name": "UpdatableSystemFontTest"
+ }
+ ]
+}
diff --git a/tests/UpdatableSystemFontTest/src/com/android/updatablesystemfont/UpdatableSystemFontTest.java b/tests/UpdatableSystemFontTest/src/com/android/updatablesystemfont/UpdatableSystemFontTest.java
new file mode 100644
index 000000000000..6bd07d0a84fd
--- /dev/null
+++ b/tests/UpdatableSystemFontTest/src/com/android/updatablesystemfont/UpdatableSystemFontTest.java
@@ -0,0 +1,451 @@
+/*
+ * 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.updatablesystemfont;
+
+import static android.os.ParcelFileDescriptor.MODE_READ_ONLY;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assume.assumeTrue;
+
+import static java.util.concurrent.TimeUnit.SECONDS;
+
+import android.app.UiAutomation;
+import android.content.Context;
+import android.graphics.fonts.FontFamilyUpdateRequest;
+import android.graphics.fonts.FontFileUpdateRequest;
+import android.graphics.fonts.FontManager;
+import android.os.ParcelFileDescriptor;
+import android.platform.test.annotations.RootPermissionTest;
+import android.security.FileIntegrityManager;
+import android.text.FontConfig;
+import android.util.Log;
+import android.util.Pair;
+
+import androidx.annotation.Nullable;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.uiautomator.By;
+import androidx.test.uiautomator.UiDevice;
+import androidx.test.uiautomator.Until;
+
+import com.android.compatibility.common.util.StreamUtil;
+import com.android.compatibility.common.util.SystemUtil;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.regex.Pattern;
+
+/**
+ * Tests if fonts can be updated by {@link FontManager} API.
+ */
+@RootPermissionTest
+@RunWith(AndroidJUnit4.class)
+public class UpdatableSystemFontTest {
+
+ private static final String TAG = "UpdatableSystemFontTest";
+ private static final String SYSTEM_FONTS_DIR = "/system/fonts/";
+ private static final String DATA_FONTS_DIR = "/data/fonts/files/";
+ private static final String CERT_PATH = "/data/local/tmp/UpdatableSystemFontTestCert.der";
+ private static final String NOTO_COLOR_EMOJI_POSTSCRIPT_NAME = "NotoColorEmoji";
+
+ private static final String ORIGINAL_NOTO_COLOR_EMOJI_TTF =
+ "/data/local/tmp/NotoColorEmoji.ttf";
+ private static final String ORIGINAL_NOTO_COLOR_EMOJI_TTF_FSV_SIG =
+ "/data/local/tmp/UpdatableSystemFontTestNotoColorEmoji.ttf.fsv_sig";
+ // A font with revision == 0.
+ private static final String TEST_NOTO_COLOR_EMOJI_V0_TTF =
+ "/data/local/tmp/UpdatableSystemFontTestNotoColorEmojiV0.ttf";
+ private static final String TEST_NOTO_COLOR_EMOJI_V0_TTF_FSV_SIG =
+ "/data/local/tmp/UpdatableSystemFontTestNotoColorEmojiV0.ttf.fsv_sig";
+ // A font with revision == original + 1
+ private static final String TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF =
+ "/data/local/tmp/UpdatableSystemFontTestNotoColorEmojiVPlus1.ttf";
+ private static final String TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF_FSV_SIG =
+ "/data/local/tmp/UpdatableSystemFontTestNotoColorEmojiVPlus1.ttf.fsv_sig";
+ // A font with revision == original + 2
+ private static final String TEST_NOTO_COLOR_EMOJI_VPLUS2_TTF =
+ "/data/local/tmp/UpdatableSystemFontTestNotoColorEmojiVPlus2.ttf";
+ private static final String TEST_NOTO_COLOR_EMOJI_VPLUS2_TTF_FSV_SIG =
+ "/data/local/tmp/UpdatableSystemFontTestNotoColorEmojiVPlus2.ttf.fsv_sig";
+
+ private static final String EMOJI_RENDERING_TEST_APP_ID = "com.android.emojirenderingtestapp";
+ private static final String EMOJI_RENDERING_TEST_ACTIVITY =
+ EMOJI_RENDERING_TEST_APP_ID + "/.EmojiRenderingTestActivity";
+ private static final long ACTIVITY_TIMEOUT_MILLIS = SECONDS.toMillis(10);
+
+ private static final String GET_AVAILABLE_FONTS_TEST_ACTIVITY =
+ EMOJI_RENDERING_TEST_APP_ID + "/.GetAvailableFontsTestActivity";
+
+ private static final Pattern PATTERN_FONT_FILES = Pattern.compile("\\.(ttf|otf|ttc|otc)$");
+ private static final Pattern PATTERN_TMP_FILES = Pattern.compile("^/data/local/tmp/");
+ private static final Pattern PATTERN_DATA_FONT_FILES = Pattern.compile("^/data/fonts/files/");
+ private static final Pattern PATTERN_SYSTEM_FONT_FILES =
+ Pattern.compile("^/(system|product)/fonts/");
+
+ private String mKeyId;
+ private FontManager mFontManager;
+ private UiDevice mUiDevice;
+
+ @Before
+ public void setUp() throws Exception {
+ Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
+ // Run tests only if updatable system font is enabled.
+ FileIntegrityManager fim = context.getSystemService(FileIntegrityManager.class);
+ assumeTrue(fim != null);
+ assumeTrue(fim.isApkVeritySupported());
+ mKeyId = insertCert(CERT_PATH);
+ mFontManager = context.getSystemService(FontManager.class);
+ expectCommandToSucceed("cmd font clear");
+ mUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ // Ignore errors because this may fail if updatable system font is not enabled.
+ runShellCommand("cmd font clear", null);
+ if (mKeyId != null) {
+ expectCommandToSucceed("mini-keyctl unlink " + mKeyId + " .fs-verity");
+ }
+ }
+
+ @Test
+ public void updateFont() throws Exception {
+ assertThat(updateFontFile(
+ TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF_FSV_SIG))
+ .isEqualTo(FontManager.RESULT_SUCCESS);
+ String fontPath = getFontPath(NOTO_COLOR_EMOJI_POSTSCRIPT_NAME);
+ assertThat(fontPath).startsWith(DATA_FONTS_DIR);
+ // The updated font should be readable and unmodifiable.
+ expectCommandToSucceed("dd status=none if=" + fontPath + " of=/dev/null");
+ expectCommandToFail("dd status=none if=" + CERT_PATH + " of=" + fontPath);
+ }
+
+ @Test
+ public void updateFont_twice() throws Exception {
+ assertThat(updateFontFile(
+ TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF_FSV_SIG))
+ .isEqualTo(FontManager.RESULT_SUCCESS);
+ String fontPath = getFontPath(NOTO_COLOR_EMOJI_POSTSCRIPT_NAME);
+ assertThat(updateFontFile(
+ TEST_NOTO_COLOR_EMOJI_VPLUS2_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS2_TTF_FSV_SIG))
+ .isEqualTo(FontManager.RESULT_SUCCESS);
+ String fontPath2 = getFontPath(NOTO_COLOR_EMOJI_POSTSCRIPT_NAME);
+ assertThat(fontPath2).startsWith(DATA_FONTS_DIR);
+ assertThat(fontPath2).isNotEqualTo(fontPath);
+ // The new file should be readable.
+ expectCommandToSucceed("dd status=none if=" + fontPath2 + " of=/dev/null");
+ // The old file should be still readable.
+ expectCommandToSucceed("dd status=none if=" + fontPath + " of=/dev/null");
+ }
+
+ @Test
+ public void updateFont_allowSameVersion() throws Exception {
+ // Update original font to the same version
+ assertThat(updateFontFile(
+ ORIGINAL_NOTO_COLOR_EMOJI_TTF, ORIGINAL_NOTO_COLOR_EMOJI_TTF_FSV_SIG))
+ .isEqualTo(FontManager.RESULT_SUCCESS);
+ String fontPath = getFontPath(NOTO_COLOR_EMOJI_POSTSCRIPT_NAME);
+ assertThat(updateFontFile(
+ TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF_FSV_SIG))
+ .isEqualTo(FontManager.RESULT_SUCCESS);
+ String fontPath2 = getFontPath(NOTO_COLOR_EMOJI_POSTSCRIPT_NAME);
+ // Update updated font to the same version
+ assertThat(updateFontFile(
+ TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF_FSV_SIG))
+ .isEqualTo(FontManager.RESULT_SUCCESS);
+ String fontPath3 = getFontPath(NOTO_COLOR_EMOJI_POSTSCRIPT_NAME);
+ assertThat(fontPath).startsWith(DATA_FONTS_DIR);
+ assertThat(fontPath2).isNotEqualTo(fontPath);
+ assertThat(fontPath2).startsWith(DATA_FONTS_DIR);
+ assertThat(fontPath3).startsWith(DATA_FONTS_DIR);
+ assertThat(fontPath3).isNotEqualTo(fontPath);
+ }
+
+ @Test
+ public void updateFont_invalidCert() throws Exception {
+ assertThat(updateFontFile(
+ TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS2_TTF_FSV_SIG))
+ .isEqualTo(FontManager.RESULT_ERROR_VERIFICATION_FAILURE);
+ }
+
+ @Test
+ public void updateFont_downgradeFromSystem() throws Exception {
+ assertThat(updateFontFile(
+ TEST_NOTO_COLOR_EMOJI_V0_TTF, TEST_NOTO_COLOR_EMOJI_V0_TTF_FSV_SIG))
+ .isEqualTo(FontManager.RESULT_ERROR_DOWNGRADING);
+ }
+
+ @Test
+ public void updateFont_downgradeFromData() throws Exception {
+ assertThat(updateFontFile(
+ TEST_NOTO_COLOR_EMOJI_VPLUS2_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS2_TTF_FSV_SIG))
+ .isEqualTo(FontManager.RESULT_SUCCESS);
+ assertThat(updateFontFile(
+ TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF_FSV_SIG))
+ .isEqualTo(FontManager.RESULT_ERROR_DOWNGRADING);
+ }
+
+ @Test
+ public void launchApp() throws Exception {
+ String fontPath = getFontPath(NOTO_COLOR_EMOJI_POSTSCRIPT_NAME);
+ assertThat(fontPath).startsWith(SYSTEM_FONTS_DIR);
+ startActivity(EMOJI_RENDERING_TEST_APP_ID, EMOJI_RENDERING_TEST_ACTIVITY);
+ SystemUtil.eventually(
+ () -> assertThat(isFileOpenedBy(fontPath, EMOJI_RENDERING_TEST_APP_ID)).isTrue(),
+ ACTIVITY_TIMEOUT_MILLIS);
+ }
+
+ @Test
+ public void launchApp_afterUpdateFont() throws Exception {
+ String originalFontPath = getFontPath(NOTO_COLOR_EMOJI_POSTSCRIPT_NAME);
+ assertThat(originalFontPath).startsWith(SYSTEM_FONTS_DIR);
+ assertThat(updateFontFile(
+ TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF_FSV_SIG))
+ .isEqualTo(FontManager.RESULT_SUCCESS);
+ String updatedFontPath = getFontPath(NOTO_COLOR_EMOJI_POSTSCRIPT_NAME);
+ assertThat(updatedFontPath).startsWith(DATA_FONTS_DIR);
+ startActivity(EMOJI_RENDERING_TEST_APP_ID, EMOJI_RENDERING_TEST_ACTIVITY);
+ // The original font should NOT be opened by the app.
+ SystemUtil.eventually(() -> {
+ assertThat(isFileOpenedBy(updatedFontPath, EMOJI_RENDERING_TEST_APP_ID)).isTrue();
+ assertThat(isFileOpenedBy(originalFontPath, EMOJI_RENDERING_TEST_APP_ID)).isFalse();
+ }, ACTIVITY_TIMEOUT_MILLIS);
+ }
+
+ @Test
+ public void reboot() throws Exception {
+ expectCommandToSucceed(String.format("cmd font update %s %s",
+ TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF_FSV_SIG));
+ String fontPath = getFontPath(NOTO_COLOR_EMOJI_POSTSCRIPT_NAME);
+ assertThat(fontPath).startsWith(DATA_FONTS_DIR);
+
+ // Emulate reboot by 'cmd font restart'.
+ expectCommandToSucceed("cmd font restart");
+ String fontPathAfterReboot = getFontPath(NOTO_COLOR_EMOJI_POSTSCRIPT_NAME);
+ assertThat(fontPathAfterReboot).isEqualTo(fontPath);
+ }
+
+ @Test
+ public void fdLeakTest() throws Exception {
+ long originalOpenFontCount =
+ countMatch(getOpenFiles("system_server"), PATTERN_FONT_FILES);
+ Pattern patternEmojiVPlus1 =
+ Pattern.compile(Pattern.quote(TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF));
+ for (int i = 0; i < 10; i++) {
+ assertThat(updateFontFile(
+ TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF_FSV_SIG))
+ .isEqualTo(FontManager.RESULT_SUCCESS);
+ List<String> openFiles = getOpenFiles("system_server");
+ for (Pattern p : Arrays.asList(PATTERN_FONT_FILES, PATTERN_SYSTEM_FONT_FILES,
+ PATTERN_DATA_FONT_FILES, PATTERN_TMP_FILES)) {
+ Log.i(TAG, String.format("num of %s: %d", p, countMatch(openFiles, p)));
+ }
+ // system_server should not keep /data/fonts files open.
+ assertThat(countMatch(openFiles, PATTERN_DATA_FONT_FILES)).isEqualTo(0);
+ // system_server should not keep passed FD open.
+ assertThat(countMatch(openFiles, patternEmojiVPlus1)).isEqualTo(0);
+ // The number of open font FD should not increase.
+ assertThat(countMatch(openFiles, PATTERN_FONT_FILES))
+ .isAtMost(originalOpenFontCount);
+ }
+ }
+
+ @Test
+ public void fdLeakTest_withoutPermission() throws Exception {
+ Pattern patternEmojiVPlus1 =
+ Pattern.compile(Pattern.quote(TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF));
+ byte[] signature = Files.readAllBytes(Paths.get(TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF_FSV_SIG));
+ try (ParcelFileDescriptor fd = ParcelFileDescriptor.open(
+ new File(TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF), MODE_READ_ONLY)) {
+ assertThrows(SecurityException.class,
+ () -> updateFontFileWithoutPermission(fd, signature, 0));
+ }
+ List<String> openFiles = getOpenFiles("system_server");
+ assertThat(countMatch(openFiles, patternEmojiVPlus1)).isEqualTo(0);
+ }
+
+ @Test
+ public void getAvailableFonts() throws Exception {
+ String fontPath = getFontPath(NOTO_COLOR_EMOJI_POSTSCRIPT_NAME);
+ startActivity(EMOJI_RENDERING_TEST_APP_ID, GET_AVAILABLE_FONTS_TEST_ACTIVITY);
+ // GET_AVAILABLE_FONTS_TEST_ACTIVITY shows the NotoColorEmoji path it got.
+ mUiDevice.wait(
+ Until.findObject(By.pkg(EMOJI_RENDERING_TEST_APP_ID).text(fontPath)),
+ ACTIVITY_TIMEOUT_MILLIS);
+ // The font file should not be opened just by querying the path using
+ // SystemFont.getAvailableFonts().
+ assertThat(isFileOpenedBy(fontPath, EMOJI_RENDERING_TEST_APP_ID)).isFalse();
+ }
+
+ private static String insertCert(String certPath) throws Exception {
+ Pair<String, String> result;
+ try (InputStream is = new FileInputStream(certPath)) {
+ result = runShellCommand("mini-keyctl padd asymmetric fsv_test .fs-verity", is);
+ }
+ // Assert that there are no errors.
+ assertThat(result.second).isEmpty();
+ String keyId = result.first.trim();
+ assertThat(keyId).matches("^\\d+$");
+ return keyId;
+ }
+
+ private int updateFontFile(String fontPath, String signaturePath) throws IOException {
+ byte[] signature = Files.readAllBytes(Paths.get(signaturePath));
+ try (ParcelFileDescriptor fd =
+ ParcelFileDescriptor.open(new File(fontPath), MODE_READ_ONLY)) {
+ return SystemUtil.runWithShellPermissionIdentity(() -> {
+ int configVersion = mFontManager.getFontConfig().getConfigVersion();
+ return updateFontFileWithoutPermission(fd, signature, configVersion);
+ });
+ }
+ }
+
+ private int updateFontFileWithoutPermission(ParcelFileDescriptor fd, byte[] signature,
+ int configVersion) {
+ return mFontManager.updateFontFamily(
+ new FontFamilyUpdateRequest.Builder()
+ .addFontFileUpdateRequest(new FontFileUpdateRequest(fd, signature))
+ .build(),
+ configVersion);
+ }
+
+ private String getFontPath(String psName) {
+ return SystemUtil.runWithShellPermissionIdentity(() -> {
+ FontConfig fontConfig = mFontManager.getFontConfig();
+ for (FontConfig.FontFamily family : fontConfig.getFontFamilies()) {
+ for (FontConfig.Font font : family.getFontList()) {
+ if (psName.equals(font.getPostScriptName())) {
+ return font.getFile().getAbsolutePath();
+ }
+ }
+ }
+ throw new AssertionError("Font not found: " + psName);
+ });
+ }
+
+ private static void startActivity(String appId, String activityId) throws Exception {
+ expectCommandToSucceed("am force-stop " + appId);
+ expectCommandToSucceed("am start-activity -n " + activityId);
+ }
+
+ private static String expectCommandToSucceed(String cmd) throws IOException {
+ Pair<String, String> result = runShellCommand(cmd, null);
+ // UiAutomation.runShellCommand() does not return exit code.
+ // Assume that the command fails if stderr is not empty.
+ assertThat(result.second.trim()).isEmpty();
+ return result.first;
+ }
+
+ private static void expectCommandToFail(String cmd) throws IOException {
+ Pair<String, String> result = runShellCommand(cmd, null);
+ // UiAutomation.runShellCommand() does not return exit code.
+ // Assume that the command fails if stderr is not empty.
+ assertThat(result.second.trim()).isNotEmpty();
+ }
+
+ /** Runs a command and returns (stdout, stderr). */
+ private static Pair<String, String> runShellCommand(String cmd, @Nullable InputStream input)
+ throws IOException {
+ Log.i(TAG, "runShellCommand: " + cmd);
+ UiAutomation automation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
+ ParcelFileDescriptor[] rwe = automation.executeShellCommandRwe(cmd);
+ // executeShellCommandRwe returns [stdout, stdin, stderr].
+ try (ParcelFileDescriptor outFd = rwe[0];
+ ParcelFileDescriptor inFd = rwe[1];
+ ParcelFileDescriptor errFd = rwe[2]) {
+ if (input != null) {
+ try (OutputStream os = new FileOutputStream(inFd.getFileDescriptor())) {
+ StreamUtil.copyStreams(input, os);
+ }
+ }
+ // We have to close stdin before reading stdout and stderr.
+ // It's safe to close ParcelFileDescriptor multiple times.
+ inFd.close();
+ String stdout;
+ try (InputStream is = new FileInputStream(outFd.getFileDescriptor())) {
+ stdout = StreamUtil.readInputStream(is);
+ }
+ Log.i(TAG, "stdout = " + stdout);
+ String stderr;
+ try (InputStream is = new FileInputStream(errFd.getFileDescriptor())) {
+ stderr = StreamUtil.readInputStream(is);
+ }
+ Log.i(TAG, "stderr = " + stderr);
+ return new Pair<>(stdout, stderr);
+ }
+ }
+
+ private static boolean isFileOpenedBy(String path, String appId) throws Exception {
+ String pid = pidOf(appId);
+ if (pid.isEmpty()) {
+ return false;
+ }
+ String cmd = String.format("lsof -t -p %s %s", pid, path);
+ return !expectCommandToSucceed(cmd).trim().isEmpty();
+ }
+
+ private static List<String> getOpenFiles(String appId) throws Exception {
+ String pid = pidOf(appId);
+ if (pid.isEmpty()) {
+ return Collections.emptyList();
+ }
+ String cmd = String.format("lsof -p %s", pid);
+ String out = expectCommandToSucceed(cmd);
+ List<String> paths = new ArrayList<>();
+ boolean first = true;
+ for (String line : out.split("\n")) {
+ // Skip the header.
+ if (first) {
+ first = false;
+ continue;
+ }
+ String[] records = line.split(" ");
+ if (records.length > 0) {
+ paths.add(records[records.length - 1]);
+ }
+ }
+ return paths;
+ }
+
+ private static String pidOf(String appId) throws Exception {
+ return expectCommandToSucceed("pidof " + appId).trim();
+ }
+
+ private static long countMatch(List<String> paths, Pattern pattern) {
+ // Note: asPredicate() returns true for partial matching.
+ return paths.stream()
+ .filter(pattern.asPredicate())
+ .count();
+ }
+}
diff --git a/tests/UpdatableSystemFontTest/testdata/Android.bp b/tests/UpdatableSystemFontTest/testdata/Android.bp
new file mode 100644
index 000000000000..426464ea574e
--- /dev/null
+++ b/tests/UpdatableSystemFontTest/testdata/Android.bp
@@ -0,0 +1,122 @@
+// 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 {
+ // 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"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+// An existing module name is reused to avoid merge conflicts.
+// TODO: fix the font and module name.
+filegroup {
+ name: "NotoColorEmojiTtf",
+ srcs: ["NotoColorEmoji.ttf"],
+}
+
+filegroup {
+ name: "UpdatableSystemFontTestKeyPem",
+ srcs: ["UpdatableSystemFontTestKey.pem"],
+}
+
+filegroup {
+ name: "UpdatableSystemFontTestCertPem",
+ srcs: ["UpdatableSystemFontTestCert.pem"],
+}
+
+filegroup {
+ name: "UpdatableSystemFontTestCertDer",
+ srcs: ["UpdatableSystemFontTestCert.der"],
+}
+
+genrule_defaults {
+ name: "updatable_system_font_increment_font_revision_default",
+}
+
+genrule {
+ name: "UpdatableSystemFontTestNotoColorEmojiV0Ttf",
+ srcs: [":NotoColorEmojiTtf"],
+ out: ["UpdatableSystemFontTestNotoColorEmojiV0.ttf"],
+ tools: ["update_font_metadata"],
+ cmd: "$(location update_font_metadata) " +
+ "--input=$(in) " +
+ "--output=$(out) " +
+ "--revision=0",
+}
+
+genrule {
+ name: "UpdatableSystemFontTestNotoColorEmojiVPlus1Ttf",
+ srcs: [":NotoColorEmojiTtf"],
+ out: ["UpdatableSystemFontTestNotoColorEmojiVPlus1.ttf"],
+ tools: ["update_font_metadata"],
+ cmd: "$(location update_font_metadata) " +
+ "--input=$(in) " +
+ "--output=$(out) " +
+ "--revision=+1",
+}
+
+genrule {
+ name: "UpdatableSystemFontTestNotoColorEmojiVPlus2Ttf",
+ srcs: [":NotoColorEmojiTtf"],
+ out: ["UpdatableSystemFontTestNotoColorEmojiVPlus2.ttf"],
+ tools: ["update_font_metadata"],
+ cmd: "$(location update_font_metadata) " +
+ "--input=$(in) " +
+ "--output=$(out) " +
+ "--revision=+2",
+}
+
+genrule_defaults {
+ name: "updatable_system_font_sig_gen_default",
+ tools: ["fsverity"],
+ tool_files: [
+ ":UpdatableSystemFontTestKeyPem",
+ ":UpdatableSystemFontTestCertPem",
+ ],
+ cmd: "$(location fsverity) sign $(in) $(out) " +
+ "--key=$(location :UpdatableSystemFontTestKeyPem) " +
+ "--cert=$(location :UpdatableSystemFontTestCertPem) " +
+ "> /dev/null",
+}
+
+genrule {
+ name: "UpdatableSystemFontTestNotoColorEmojiTtfFsvSig",
+ defaults: ["updatable_system_font_sig_gen_default"],
+ srcs: [":NotoColorEmojiTtf"],
+ out: ["UpdatableSystemFontTestNotoColorEmoji.ttf.fsv_sig"],
+}
+
+genrule {
+ name: "UpdatableSystemFontTestNotoColorEmojiV0TtfFsvSig",
+ defaults: ["updatable_system_font_sig_gen_default"],
+ srcs: [":UpdatableSystemFontTestNotoColorEmojiV0Ttf"],
+ out: ["UpdatableSystemFontTestNotoColorEmojiV0.ttf.fsv_sig"],
+}
+
+genrule {
+ name: "UpdatableSystemFontTestNotoColorEmojiVPlus1TtfFsvSig",
+ defaults: ["updatable_system_font_sig_gen_default"],
+ srcs: [":UpdatableSystemFontTestNotoColorEmojiVPlus1Ttf"],
+ out: ["UpdatableSystemFontTestNotoColorEmojiVPlus1.ttf.fsv_sig"],
+}
+
+genrule {
+ name: "UpdatableSystemFontTestNotoColorEmojiVPlus2TtfFsvSig",
+ defaults: ["updatable_system_font_sig_gen_default"],
+ srcs: [":UpdatableSystemFontTestNotoColorEmojiVPlus2Ttf"],
+ out: ["UpdatableSystemFontTestNotoColorEmojiVPlus2.ttf.fsv_sig"],
+}
diff --git a/tests/UpdatableSystemFontTest/testdata/NotoColorEmoji.ttf b/tests/UpdatableSystemFontTest/testdata/NotoColorEmoji.ttf
new file mode 100644
index 000000000000..f71f52cbaa2b
--- /dev/null
+++ b/tests/UpdatableSystemFontTest/testdata/NotoColorEmoji.ttf
Binary files differ
diff --git a/tests/UpdatableSystemFontTest/testdata/NotoColorEmoji.ttx b/tests/UpdatableSystemFontTest/testdata/NotoColorEmoji.ttx
new file mode 100644
index 000000000000..6540c5898ec5
--- /dev/null
+++ b/tests/UpdatableSystemFontTest/testdata/NotoColorEmoji.ttx
@@ -0,0 +1,208 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+-->
+<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="3.0">
+
+ <GlyphOrder>
+ <GlyphID id="0" name=".notdef"/>
+ <GlyphID id="1" name="a"/>
+ <GlyphID id="2" name="u1F972"/>
+ </GlyphOrder>
+
+ <head>
+ <tableVersion value="1.0"/>
+ <!-- Currently NotoColorEmoji.ttf's fontRevision is 2.xxx.
+ 100.0 will be sufficiently larger than that. -->
+ <fontRevision value="100.0"/>
+ <checkSumAdjustment value="0x640cdb2f"/>
+ <magicNumber value="0x5f0f3cf5"/>
+ <flags value="00000000 00000011"/>
+ <unitsPerEm value="1000"/>
+ <created value="Fri Jun 25 12:00:00 2021"/>
+ <macStyle value="00000000 00000000"/>
+ <lowestRecPPEM value="7"/>
+ <fontDirectionHint value="2"/>
+ <glyphDataFormat value="0"/>
+ </head>
+
+ <hhea>
+ <tableVersion value="0x00010000"/>
+ <ascent value="1000"/>
+ <descent value="-200"/>
+ <lineGap value="0"/>
+ <caretSlopeRise value="1"/>
+ <caretSlopeRun value="0"/>
+ <caretOffset value="0"/>
+ <reserved0 value="0"/>
+ <reserved1 value="0"/>
+ <reserved2 value="0"/>
+ <reserved3 value="0"/>
+ <metricDataFormat value="0"/>
+ </hhea>
+
+ <maxp>
+ <tableVersion value="0x10000"/>
+ <maxZones value="0"/>
+ <maxTwilightPoints value="0"/>
+ <maxStorage value="0"/>
+ <maxFunctionDefs value="0"/>
+ <maxInstructionDefs value="0"/>
+ <maxStackElements value="0"/>
+ <maxSizeOfInstructions value="0"/>
+ <maxComponentElements value="0"/>
+ </maxp>
+
+ <OS_2>
+ <!-- The fields 'usFirstCharIndex' and 'usLastCharIndex'
+ will be recalculated by the compiler -->
+ <version value="3"/>
+ <xAvgCharWidth value="594"/>
+ <usWeightClass value="400"/>
+ <usWidthClass value="5"/>
+ <fsType value="00000000 00001000"/>
+ <ySubscriptXSize value="650"/>
+ <ySubscriptYSize value="600"/>
+ <ySubscriptXOffset value="0"/>
+ <ySubscriptYOffset value="75"/>
+ <ySuperscriptXSize value="650"/>
+ <ySuperscriptYSize value="600"/>
+ <ySuperscriptXOffset value="0"/>
+ <ySuperscriptYOffset value="350"/>
+ <yStrikeoutSize value="50"/>
+ <yStrikeoutPosition value="300"/>
+ <sFamilyClass value="0"/>
+ <panose>
+ <bFamilyType value="0"/>
+ <bSerifStyle value="0"/>
+ <bWeight value="5"/>
+ <bProportion value="0"/>
+ <bContrast value="0"/>
+ <bStrokeVariation value="0"/>
+ <bArmStyle value="0"/>
+ <bLetterForm value="0"/>
+ <bMidline value="0"/>
+ <bXHeight value="0"/>
+ </panose>
+ <ulUnicodeRange1 value="00000000 00000000 00000000 00000001"/>
+ <ulUnicodeRange2 value="00000000 00000000 00000000 00000000"/>
+ <ulUnicodeRange3 value="00000000 00000000 00000000 00000000"/>
+ <ulUnicodeRange4 value="00000000 00000000 00000000 00000000"/>
+ <achVendID value="UKWN"/>
+ <fsSelection value="00000000 01000000"/>
+ <usFirstCharIndex value="32"/>
+ <usLastCharIndex value="122"/>
+ <sTypoAscender value="800"/>
+ <sTypoDescender value="-200"/>
+ <sTypoLineGap value="200"/>
+ <usWinAscent value="1000"/>
+ <usWinDescent value="200"/>
+ <ulCodePageRange1 value="00000000 00000000 00000000 00000001"/>
+ <ulCodePageRange2 value="00000000 00000000 00000000 00000000"/>
+ <sxHeight value="500"/>
+ <sCapHeight value="700"/>
+ <usDefaultChar value="0"/>
+ <usBreakChar value="32"/>
+ <usMaxContext value="0"/>
+ </OS_2>
+
+ <hmtx>
+ <mtx name=".notdef" width="500" lsb="93"/>
+ <mtx name="a" width="3000" lsb="93"/> <!-- 3em -->
+ <mtx name="u1F972" width="3000" lsb="93"/> <!-- 3em -->
+ </hmtx>
+
+ <cmap>
+ <tableVersion version="0"/>
+ <!-- length will be calculated by the compiler. -->
+ <cmap_format_12 platformID="3" platEncID="10" format="12" reserved="0" length="0" language="0" nGroups="1">
+ <!-- The font must support at least one of the characters used
+ in OtfFontFileParser to validate the font. -->
+ <map code="0x61" name="a" />
+ <map code="0x1F972" name="u1F972" />
+ </cmap_format_12>
+ </cmap>
+
+ <loca>
+ <!-- The 'loca' table will be calculated by the compiler -->
+ </loca>
+
+ <glyf>
+ <TTGlyph name=".notdef" xMin="0" yMin="0" xMax="0" yMax="0" />
+ <TTGlyph name="a" xMin="0" yMin="0" xMax="300" yMax="300">
+ <contour>
+ <pt x="0" y="0" on="1" />
+ <pt x="0" y="300" on="1" />
+ <pt x="300" y="300" on="1" />
+ <pt x="300" y="0" on="1" />
+ </contour>
+ <instructions />
+ </TTGlyph>
+ <TTGlyph name="u1F972" xMin="0" yMin="0" xMax="300" yMax="300">
+ <contour>
+ <pt x="0" y="0" on="1" />
+ <pt x="0" y="300" on="1" />
+ <pt x="300" y="300" on="1" />
+ <pt x="300" y="0" on="1" />
+ </contour>
+ <instructions />
+ </TTGlyph>
+ </glyf>
+
+ <name>
+ <namerecord nameID="0" platformID="3" platEncID="1" langID="0x409">
+ Copyright (C) 2021 The Android Open Source Project
+ </namerecord>
+ <namerecord nameID="1" platformID="3" platEncID="1" langID="0x409">
+ Sample Font
+ </namerecord>
+ <namerecord nameID="2" platformID="3" platEncID="1" langID="0x409">
+ Regular
+ </namerecord>
+ <namerecord nameID="4" platformID="3" platEncID="1" langID="0x409">
+ Sample Font
+ </namerecord>
+ <namerecord nameID="6" platformID="3" platEncID="1" langID="0x409">
+ <!-- Android identifies the target font to be updated by PostScript name.
+ To test updating NotoColorEmoji.ttf, the PostScript needs to be
+ the same as NotoColorEmoji.ttf here. -->
+ NotoColorEmoji
+ </namerecord>
+ <namerecord nameID="13" platformID="3" platEncID="1" langID="0x409">
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ 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.
+ </namerecord>
+ <namerecord nameID="14" platformID="3" platEncID="1" langID="0x409">
+ http://www.apache.org/licenses/LICENSE-2.0
+ </namerecord>
+ </name>
+
+ <post>
+ <formatType value="3.0"/>
+ <italicAngle value="0.0"/>
+ <underlinePosition value="-75"/>
+ <underlineThickness value="50"/>
+ <isFixedPitch value="0"/>
+ <minMemType42 value="0"/>
+ <maxMemType42 value="0"/>
+ <minMemType1 value="0"/>
+ <maxMemType1 value="0"/>
+ </post>
+
+</ttFont>
diff --git a/tests/UpdatableSystemFontTest/testdata/UpdatableSystemFontTestCert.der b/tests/UpdatableSystemFontTest/testdata/UpdatableSystemFontTestCert.der
new file mode 100644
index 000000000000..f7aa15fdef68
--- /dev/null
+++ b/tests/UpdatableSystemFontTest/testdata/UpdatableSystemFontTestCert.der
Binary files differ
diff --git a/tests/UpdatableSystemFontTest/testdata/UpdatableSystemFontTestCert.pem b/tests/UpdatableSystemFontTest/testdata/UpdatableSystemFontTestCert.pem
new file mode 100644
index 000000000000..0cd1f666f9be
--- /dev/null
+++ b/tests/UpdatableSystemFontTest/testdata/UpdatableSystemFontTestCert.pem
@@ -0,0 +1,30 @@
+-----BEGIN CERTIFICATE-----
+MIIFOTCCAyGgAwIBAgIUFaI1D5NtwkCVM3G4bFZ6sQSb598wDQYJKoZIhvcNAQEL
+BQAwLDELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMRAwDgYDVQQKDAdBbmRyb2lk
+MB4XDTIxMDIwMTA3MzAyNFoXDTIxMDMwMzA3MzAyNFowLDELMAkGA1UEBhMCVVMx
+CzAJBgNVBAgMAkNBMRAwDgYDVQQKDAdBbmRyb2lkMIICIjANBgkqhkiG9w0BAQEF
+AAOCAg8AMIICCgKCAgEA0U1zptc41E65ooeBPD33Mjgp6cYPydyj2Acq80Xy7lP7
+d6/2t6w7nNNl2x3n8dAhOl3de3IxTp6JI2SdoRb7obfcp+hWJoo/cxnHpr3q/u4R
+KED0rmWaOVHpGbajSTFZgN+cTbTKJbgtXm/H65x1QfO18ep/vj5fRiu1xPpJqDv/
+xuvuko2U3eC2+NayxzCWXVFrKPLx8GvzSQ3Utaug17vs7/5GqkRJgq3lk4DvmjNA
+vY8YA4RAkII1sSaceAWFEG6ztENLu2kjcxAI9qHxxBwQZit/NtFVlFGqSN3MEYjS
+M9Fz04RsUxF672QJpAgwCJDZ41rdB3hkHvOUK9PcepBsHdZq9cQ+E64+TX+jsJLu
+VouViKlYr6WYjvhfqZeRhwbj7CoEZ2DyEZKrl27fgWaidUT5LGEQLVxg90ymbimI
+6UwXRUwmRBQJBdRO4RGvngtqxRuamyjAKDDHx5YccXCX4FWLUypyQlz0asojvbJZ
+Og7DFa1qsRdGrGIRoQJ8pYnAjBJfSudr1l0mR7fZSfZc0W9ZmuROWx9Ip7aJWQnQ
+8JLtbNPuFLD2qbmg9Y1lcXJp1FvI9FcM8JsBqZNEANQwwsdTaa8gw+3W6J2SXKQP
+H+yZI/fJWWWRFADtqmpxtvXK9K+Cy1HQmg7D0IIxVPp8rrbz6TGrg+R3/N9FBWMC
+AwEAAaNTMFEwHQYDVR0OBBYEFDS48o2UAstoOyLMcgamHKrZdl3cMB8GA1UdIwQY
+MBaAFDS48o2UAstoOyLMcgamHKrZdl3cMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZI
+hvcNAQELBQADggIBAF7taBYAe20tWZu0pY9d4Z8il4LoJcRrKF4YiA02UizErgCF
+h4iECy6+pcu7DJUfvCh3dCWE7CDG+OnfUWTwEHVG9n8XI/ydetBUG76PZwTadI7B
+gzJ1y7/vWqJo5U6ki+sXNmq3hkgNsNZgza3LpdovkWJYeRdffM6m/bimzwYx9id8
+5mKw2PcbVZcb25r+0dCoLVJsqqCoRjdYUy/MKPutWG2bPzmaIv8KsKFN+mzlwhJH
+lpJ/LR+3NoaHrOCFG7CW/2Ihe501vmdQ2m/VKosyk0igw8WmTsY6xMbw2t77yKkD
+hnJr1NbhKeEV9gAB2BFX8nRWI7NTgp8fG78YLVz1UcbIHmYLgFoc3ezyma+CoR86
+ER20lKd4+TNnz4RtaPdZlBa0Ba3bsMtEneqlrHvcPrZ5tgGsQR9+cy3ZtTZ/LUQX
++Xuj/EoJXuuB3hkhg52zawN5n7WUe8efWHcv1jHqeIj0phcgbZ6u4fFBPsYjzDKe
+VuYHXglNOchmoBQwEaJI/TCiEgI8dcSJXSquLAXrtznVnxzT46ZMEt5LaW1/1NLx
+q//yoPdolCI0lpunh5jvIZJpUl5XMjxVSyaveQDNVqJkITWzWqIxAT5yTLtkCNlW
+c1XyzeHkpMItiJtBruExmnaTmNjlVKsXP8wQFOYbDGgXY5iHIMbgovptRyH/
+-----END CERTIFICATE-----
diff --git a/tests/UpdatableSystemFontTest/testdata/UpdatableSystemFontTestKey.pem b/tests/UpdatableSystemFontTest/testdata/UpdatableSystemFontTestKey.pem
new file mode 100644
index 000000000000..09bb1040f112
--- /dev/null
+++ b/tests/UpdatableSystemFontTest/testdata/UpdatableSystemFontTestKey.pem
@@ -0,0 +1,52 @@
+-----BEGIN PRIVATE KEY-----
+MIIJRAIBADANBgkqhkiG9w0BAQEFAASCCS4wggkqAgEAAoICAQDRTXOm1zjUTrmi
+h4E8PfcyOCnpxg/J3KPYByrzRfLuU/t3r/a3rDuc02XbHefx0CE6Xd17cjFOnokj
+ZJ2hFvuht9yn6FYmij9zGcemver+7hEoQPSuZZo5UekZtqNJMVmA35xNtMoluC1e
+b8frnHVB87Xx6n++Pl9GK7XE+kmoO//G6+6SjZTd4Lb41rLHMJZdUWso8vHwa/NJ
+DdS1q6DXu+zv/kaqREmCreWTgO+aM0C9jxgDhECQgjWxJpx4BYUQbrO0Q0u7aSNz
+EAj2ofHEHBBmK3820VWUUapI3cwRiNIz0XPThGxTEXrvZAmkCDAIkNnjWt0HeGQe
+85Qr09x6kGwd1mr1xD4Trj5Nf6Owku5Wi5WIqVivpZiO+F+pl5GHBuPsKgRnYPIR
+kquXbt+BZqJ1RPksYRAtXGD3TKZuKYjpTBdFTCZEFAkF1E7hEa+eC2rFG5qbKMAo
+MMfHlhxxcJfgVYtTKnJCXPRqyiO9slk6DsMVrWqxF0asYhGhAnylicCMEl9K52vW
+XSZHt9lJ9lzRb1ma5E5bH0intolZCdDwku1s0+4UsPapuaD1jWVxcmnUW8j0Vwzw
+mwGpk0QA1DDCx1NpryDD7dbonZJcpA8f7Jkj98lZZZEUAO2qanG29cr0r4LLUdCa
+DsPQgjFU+nyutvPpMauD5Hf830UFYwIDAQABAoICAQCTVTcFCdl6MdSg4UwK0P/S
+fRCb/A0fJs67Agis6N9h/wI0NUyx7G6mLXU0si+U29KYGH0RKcgltJmKrYf8XoZR
+R3DvTTBfvs99QXd2G5hxTboMIPVcUi8nDE7PB+6XVkLP4hhP5uSpeqWNJZiQdTlh
+bKH2IgE8NQGyDpDMkPcKkvmw2GG/DiTtrwJ91fxRFRWzqN2LHMFMYWEHWtIR9Der
+xSC7q72om5s3fxvtIkUHwe5fwXvA9fbRAqezBR/9qL0LXTHowbpsuUz38SCuJD9g
+sfSlRxcsyly4pGf/FQpSiYKWcWlcSopKSzLDkyLqMc1GKlkGnu6aFJg95W63D1LS
+OaOXuYShHxLkqyhT8uQGRqDCu3E2ivb6fMxAPzJxxs3JrZvumNsqyxbp+HVF0idj
+NijMN/8Kb4KmNHG9I3SHG61tQFYDtxoMMNiHzq3fafBJnVcf6iThQdE5pGLN2OdF
+3rcSTeHI2HxhTrXtuiHmWXNk9aZ2TOhrssNZZjDkFL/KYh6G8guy+tn66YWy77VC
+id+6PBzYXTXsUauo4NWW1rLUfzT/y93IwVGpoXs7GHUUduZ6Q3PxsMTMF9IjBvqR
+JvfP84CUfGXoebVJmWyGhtW6N5ParvQxbonDitA0TPZcRyX3N8yqIGO/mb8MWA9M
+7s/xMZuksOpw5LSCoTAW6QKCAQEA9Z1WM/5XT+5HkwPBvS5aRz0SqMqPxAkZ0dNz
+O06zpXv6e2IPy40UzFWCIkyq3vWKQ5bqU1fnejUdmjvtnP+KhH6fxnQCgiunnrDq
+j1Sk2Y4gb1KyZY/C8IejOexM2qX7sfDTLI8XEvxJxVFCNmvYfnv4AX5QD8VOsjrg
+bvodLAgDSo2FVDP+mkpW7zAIoRV02l6QdZA+YcG940eqxB9sPR3/1KUHe9wUTTbJ
+FV5ahEPuXCyvRJkZ/rD5CPPZoQHfjKHxDlu7yfoatzCSYj10R+RInfqOFGVY4D/C
+2csXjymwTN4CFUnJcP410YhPFn5ekmc/E3xqPKgIDQhQ2+oivwKCAQEA2icN1iEo
+YuBJwB3pX3jrwk+1bpUXASueWhyAhSeNMrTrJ/lSgEAy9FBxJNnK1PjkABRnFhS+
+uxbC2hQdfAkNDS21PQOk6hOhebUVuBdfmKY1CL+P9y4Af0fjV1rgRGHihnZB5lKU
+1R/wFb8c4QgPwduiqDoZ5QP3dgxpZ4R3SCzuoyVelUSlgyWPoslg+yPddcnV8bTf
+BUlEOOyXgVudkSFlRpWZ+/ZAkLTj8rnrtKp8/+GtTQvJvPJHPfuSsDhI+EQVWqab
+HelMhxvIi9xOyN/OCc3Ex6JlEVa+X8EyNhQsV2sAKnld92hdEozW2uxRniIkxvL4
+CuBp/p3fWxEaXQKCAQEAw2j7RYCMnNZZ8Zhiko4HW3g2mT4XpYMMHMlbe4sBGJ8L
+yRBaurqzGmLJl1ph8+NsrpuqMMbWLn+F3sjhIjCZVxKbMbvopwHuaS4eYAya30/Z
+dFhaAL2g/dccQSBEgQzftFGC4YeydvNsCeW9hSjGZNNinGWPcwyqsNhw6Tpq7TYu
+0CjKNBTt8nlEsyYHJ4m3n2jvC+nIB+Spm+LP9Rt+9R0iBl+KFbwiFtCIqUyZPXQC
+dylCBJS+fsj0SXAg7J1d6ziIXcEUJfyrNqYZQLneAriYIcBPO+DqFfgEoVyYkNk9
+H9rd02wSLajCzsLhEWdW/KnSIEGzEDErvpqoIl8kZwKCAQEAjNO3T+sZyjKmCXqF
+xBcogsi4BAoEzsGcuOk7Yjn1Ia2/PI/r3VUUT7l6QOLD2JZPgWmqXovH0LjR0rw3
+iHHDViWSoS+wD1fa3tmyiqO0F7P7+ojHZDbzJTeAIE1PB3X1KP5AbnITGD5E25UD
+DJYKrgeeSmEvhDL6Vd+PT78ozZQL/Y/LLishebcOsXS0wYsWlMpV7XHoot34R5Mb
+/urond7kJRvASvJeHcxYdsHk0j1Y8kp6eIlKk0oICZBU0qOTH4m8C0gQTM/lkjay
+UO9IgM5RkOyfwowoGHhZ7zClvFlrgodVlRXCPkvGAYqfzLXPvnimKzSAQW07n53E
+qWIyFQKCAQAWRNG6hPCOzkNxMJ/RK7dwxZW6b4a1L3PMXTT/xrBKRIS1WNjbpkYO
+/FLIufOqJT6FQN2obM5uso3TI+R7MwH8DnTSnDDy0Hvs3CdHdtn2tapZOViF/UVv
+uCQa+/jMVKFCZ8k7pPFMIG6tB6WBA5MmJrW+8s0ouxLbRF5rZyzqOeyPdVBYYYDb
+68nGNA6GAtTQs9h7xV2tsQ1bXNP+6gqG3BgZYo+76xKITddT6s9aaC++LVBnPOdq
+LHV7gUvoBkVLjIp4L3Fb/DGMCcOVMCxmFlRBn+RBlV7slehvgq+Ywz2GHWLr+O/z
+V2NAtwvCfZE2Do/4f2mpHnamhS6AvrDe
+-----END PRIVATE KEY-----
diff --git a/tests/UsageReportingTest/AndroidManifest.xml b/tests/UsageReportingTest/AndroidManifest.xml
index be0b09e972a5..4a3487f29dc4 100644
--- a/tests/UsageReportingTest/AndroidManifest.xml
+++ b/tests/UsageReportingTest/AndroidManifest.xml
@@ -1,20 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
-
<!--
Note: Add android:sharedUserId="android.uid.system" to the root element to simulate the system UID
caller case.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.tests.usagereporter"
- >
+ package="com.android.tests.usagereporter">
<application android:label="@string/reporter_app">
<activity android:name="UsageReporterActivity"
- android:label="UsageReporter">
+ android:label="UsageReporter"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
diff --git a/tests/UsageStatsTest/AndroidManifest.xml b/tests/UsageStatsTest/AndroidManifest.xml
index fefd99394a87..82e5be1bce3e 100644
--- a/tests/UsageStatsTest/AndroidManifest.xml
+++ b/tests/UsageStatsTest/AndroidManifest.xml
@@ -1,28 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
-
<!--
Note: Add android:sharedUserId="android.uid.system" to the root element to simulate the system UID
caller case.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.tests.usagestats"
- >
+ package="com.android.tests.usagestats">
- <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" />
- <uses-permission android:name="android.permission.OBSERVE_APP_USAGE" />
- <uses-permission android:name="android.permission.SUSPEND_APPS" />
+ <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS"/>
+ <uses-permission android:name="android.permission.OBSERVE_APP_USAGE"/>
+ <uses-permission android:name="android.permission.SUSPEND_APPS"/>
<application android:label="Usage Access Test">
<activity android:name=".UsageStatsActivity"
- android:label="Device Usage History">
+ android:label="Device Usage History"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name=".UsageLogActivity" />
+ <activity android:name=".UsageLogActivity"/>
</application>
</manifest>
diff --git a/tests/UsageStatsTest/src/com/android/tests/usagestats/UsageStatsActivity.java b/tests/UsageStatsTest/src/com/android/tests/usagestats/UsageStatsActivity.java
index bb985d7f8be2..53269efcbf05 100644
--- a/tests/UsageStatsTest/src/com/android/tests/usagestats/UsageStatsActivity.java
+++ b/tests/UsageStatsTest/src/com/android/tests/usagestats/UsageStatsActivity.java
@@ -164,7 +164,7 @@ public class UsageStatsActivity extends ListActivity {
intent.putExtra(EXTRA_KEY_TIMEOUT, true);
mUsageStatsManager.registerAppUsageObserver(1, packages,
60, TimeUnit.SECONDS, PendingIntent.getActivity(UsageStatsActivity.this,
- 1, intent, 0));
+ 1, intent, PendingIntent.FLAG_MUTABLE_UNAUDITED));
}
}
});
@@ -198,7 +198,7 @@ public class UsageStatsActivity extends ListActivity {
intent.putExtra(EXTRA_KEY_TIMEOUT, true);
mUsageStatsManager.registerAppUsageLimitObserver(1, packages,
Duration.ofSeconds(60), Duration.ofSeconds(0),
- PendingIntent.getActivity(UsageStatsActivity.this, 1, intent, 0));
+ PendingIntent.getActivity(UsageStatsActivity.this, 1, intent, PendingIntent.FLAG_MUTABLE_UNAUDITED));
}
}
});
diff --git a/tests/UsbHostExternalManagmentTest/AoapTestDevice/AndroidManifest.xml b/tests/UsbHostExternalManagmentTest/AoapTestDevice/AndroidManifest.xml
index 99bb520ee902..fadd0ea21996 100644
--- a/tests/UsbHostExternalManagmentTest/AoapTestDevice/AndroidManifest.xml
+++ b/tests/UsbHostExternalManagmentTest/AoapTestDevice/AndroidManifest.xml
@@ -13,18 +13,19 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
- package="com.android.hardware.usb.aoapdevicetest" >
- <application android:label="UsbAoapDeviceTestApp" >
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ package="com.android.hardware.usb.aoapdevicetest">
+ <application android:label="UsbAoapDeviceTestApp">
<activity android:name=".UsbAoapDeviceTestActivity"
- android:configChanges="keyboard|keyboardHidden" >
+ android:configChanges="keyboard|keyboardHidden"
+ android:exported="true">
<intent-filter>
- <action android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" />
+ <action android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED"/>
</intent-filter>
- <meta-data
- android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED"
- android:resource="@xml/accessory_filter"/>
+ <meta-data android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED"
+ android:resource="@xml/accessory_filter"/>
</activity>
</application>
</manifest>
diff --git a/tests/UsbHostExternalManagmentTest/AoapTestDevice/src/com/android/hardware/usb/aoapdevicetest/UsbAoapDeviceTestActivity.java b/tests/UsbHostExternalManagmentTest/AoapTestDevice/src/com/android/hardware/usb/aoapdevicetest/UsbAoapDeviceTestActivity.java
index aa4f8caa0b20..ef179e2da26d 100644
--- a/tests/UsbHostExternalManagmentTest/AoapTestDevice/src/com/android/hardware/usb/aoapdevicetest/UsbAoapDeviceTestActivity.java
+++ b/tests/UsbHostExternalManagmentTest/AoapTestDevice/src/com/android/hardware/usb/aoapdevicetest/UsbAoapDeviceTestActivity.java
@@ -99,7 +99,7 @@ public class UsbAoapDeviceTestActivity extends Activity {
Intent intent = new Intent(ACTION_USB_ACCESSORY_PERMISSION);
intent.setPackage(getPackageName());
PendingIntent pendingIntent = PendingIntent.getBroadcast(
- this, 0, intent, PendingIntent.FLAG_ONE_SHOT);
+ this, 0, intent, PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_MUTABLE_UNAUDITED);
mUsbManager.requestPermission(accessory, pendingIntent);
return;
}
diff --git a/tests/UsbHostExternalManagmentTest/AoapTestHost/AndroidManifest.xml b/tests/UsbHostExternalManagmentTest/AoapTestHost/AndroidManifest.xml
index 8cc470eaa85c..9ad17ab64bd0 100644
--- a/tests/UsbHostExternalManagmentTest/AoapTestHost/AndroidManifest.xml
+++ b/tests/UsbHostExternalManagmentTest/AoapTestHost/AndroidManifest.xml
@@ -13,18 +13,19 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
- package="com.android.hardware.usb.aoaphosttest" >
- <application android:label="UsbAoapHostTestApp" >
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ package="com.android.hardware.usb.aoaphosttest">
+ <application android:label="UsbAoapHostTestApp">
<activity android:name=".UsbAoapHostTestActivity"
- android:configChanges="keyboard|keyboardHidden" >
+ android:configChanges="keyboard|keyboardHidden"
+ android:exported="true">
<intent-filter>
- <action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
+ <action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"/>
</intent-filter>
- <meta-data
- android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
- android:resource="@xml/usb_device_filter"/>
+ <meta-data android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
+ android:resource="@xml/usb_device_filter"/>
</activity>
</application>
</manifest>
diff --git a/tests/UsbHostExternalManagmentTest/UsbHostExternalManagmentTestApp/AndroidManifest.xml b/tests/UsbHostExternalManagmentTest/UsbHostExternalManagmentTestApp/AndroidManifest.xml
index 97bbefb5c4af..627e46b6304d 100644
--- a/tests/UsbHostExternalManagmentTest/UsbHostExternalManagmentTestApp/AndroidManifest.xml
+++ b/tests/UsbHostExternalManagmentTest/UsbHostExternalManagmentTestApp/AndroidManifest.xml
@@ -13,19 +13,21 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
- package="com.android.hardware.usb.externalmanagementtest" >
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ package="com.android.hardware.usb.externalmanagementtest">
- <uses-permission android:name="android.permission.MANAGE_USB" />
- <application android:label="UsbHostExternalManagementTestApp" >
+ <uses-permission android:name="android.permission.MANAGE_USB"/>
+ <application android:label="UsbHostExternalManagementTestApp">
<activity android:name=".UsbHostManagementActivity"
- android:configChanges="keyboard|keyboardHidden" >
+ android:configChanges="keyboard|keyboardHidden"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
+ <action android:name="android.intent.action.MAIN"/>
</intent-filter>
<intent-filter>
- <action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
+ <action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"/>
</intent-filter>
</activity>
</application>
diff --git a/tests/UsesFeature2Test/AndroidManifest.xml b/tests/UsesFeature2Test/AndroidManifest.xml
index 8caf4a158867..a0ea45adae19 100644
--- a/tests/UsesFeature2Test/AndroidManifest.xml
+++ b/tests/UsesFeature2Test/AndroidManifest.xml
@@ -22,6 +22,10 @@
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.BLUETOOTH" />
+ <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
+ <uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE"/>
+ <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
+ <uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<uses-feature android:name="android.hardware.sensor.accelerometer" />
<feature-group android:label="@string/minimal">
diff --git a/tests/VectorDrawableTest/AndroidManifest.xml b/tests/VectorDrawableTest/AndroidManifest.xml
index 7b3beb27e0cc..5334dac57ca2 100644
--- a/tests/VectorDrawableTest/AndroidManifest.xml
+++ b/tests/VectorDrawableTest/AndroidManifest.xml
@@ -16,147 +16,146 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.test.dynamic" >
-
- <application
- android:hardwareAccelerated="true"
- android:label="vector"
- android:supportsRtl="true" >
- <activity
- android:name="VectorDrawablePerformance"
- android:label="Vector Performance" >
+ package="com.android.test.dynamic">
+
+ <application android:hardwareAccelerated="true"
+ android:label="vector"
+ android:supportsRtl="true">
+ <activity android:name="VectorDrawablePerformance"
+ android:label="Vector Performance"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
+ <action android:name="android.intent.action.MAIN"/>
- <category android:name="com.android.test.dynamic.TEST" />
+ <category android:name="com.android.test.dynamic.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="BitmapDrawableDupe"
- android:label="Bitmap Performance of clones" >
+ <activity android:name="BitmapDrawableDupe"
+ android:label="Bitmap Performance of clones"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
+ <action android:name="android.intent.action.MAIN"/>
- <category android:name="com.android.test.dynamic.TEST" />
+ <category android:name="com.android.test.dynamic.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="VectorDrawableAnimation"
- android:label="VectorTestAnimation" >
+ <activity android:name="VectorDrawableAnimation"
+ android:label="VectorTestAnimation"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
+ <action android:name="android.intent.action.MAIN"/>
- <category android:name="com.android.test.dynamic.TEST" />
+ <category android:name="com.android.test.dynamic.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="VectorDrawableTest"
- android:label="Vector Icon" >
+ <activity android:name="VectorDrawableTest"
+ android:label="Vector Icon"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
+ <action android:name="android.intent.action.MAIN"/>
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity
- android:name="AnimatedVectorDrawableTest"
- android:label="AnimatedVectorDrawableTest" >
+ <activity android:name="AnimatedVectorDrawableTest"
+ android:label="AnimatedVectorDrawableTest"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
+ <action android:name="android.intent.action.MAIN"/>
- <category android:name="com.android.test.dynamic.TEST" />
+ <category android:name="com.android.test.dynamic.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="AnimatedStateVectorDrawableTest"
- android:label="AnimatedStateList and AnimatedVectorDrawable" >
+ <activity android:name="AnimatedStateVectorDrawableTest"
+ android:label="AnimatedStateList and AnimatedVectorDrawable"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
+ <action android:name="android.intent.action.MAIN"/>
- <category android:name="com.android.test.dynamic.TEST" />
+ <category android:name="com.android.test.dynamic.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="VectorDrawable01"
- android:label="VectorTest1" >
+ <activity android:name="VectorDrawable01"
+ android:label="VectorTest1"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
+ <action android:name="android.intent.action.MAIN"/>
- <category android:name="com.android.test.dynamic.TEST" />
+ <category android:name="com.android.test.dynamic.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="VectorDrawableDupPerf"
- android:label="Vector Performance of clones" >
+ <activity android:name="VectorDrawableDupPerf"
+ android:label="Vector Performance of clones"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
+ <action android:name="android.intent.action.MAIN"/>
- <category android:name="com.android.test.dynamic.TEST" />
+ <category android:name="com.android.test.dynamic.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="AnimatedVectorDrawableDupPerf"
- android:label="Animated Vector Performance of clones" >
+ <activity android:name="AnimatedVectorDrawableDupPerf"
+ android:label="Animated Vector Performance of clones"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
+ <action android:name="android.intent.action.MAIN"/>
- <category android:name="com.android.test.dynamic.TEST" />
+ <category android:name="com.android.test.dynamic.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="VectorDrawableStaticPerf"
- android:label="System icons" >
+ <activity android:name="VectorDrawableStaticPerf"
+ android:label="System icons"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
+ <action android:name="android.intent.action.MAIN"/>
- <category android:name="com.android.test.dynamic.TEST" />
+ <category android:name="com.android.test.dynamic.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="VectorCheckbox"
- android:label="Basic static vector drawables" >
+ <activity android:name="VectorCheckbox"
+ android:label="Basic static vector drawables"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
+ <action android:name="android.intent.action.MAIN"/>
- <category android:name="com.android.test.dynamic.TEST" />
+ <category android:name="com.android.test.dynamic.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="VectorPathChecking"
- android:label="Path Checking graphics" >
+ <activity android:name="VectorPathChecking"
+ android:label="Path Checking graphics"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
+ <action android:name="android.intent.action.MAIN"/>
- <category android:name="com.android.test.dynamic.TEST" />
+ <category android:name="com.android.test.dynamic.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="ScaleDrawableTests"
- android:label="Scale Type Test" >
+ <activity android:name="ScaleDrawableTests"
+ android:label="Scale Type Test"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
+ <action android:name="android.intent.action.MAIN"/>
- <category android:name="com.android.test.dynamic.TEST" />
+ <category android:name="com.android.test.dynamic.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="AnimatedVectorDrawableAttr"
- android:label="AnimatedVectorDrawable Attr Test" >
+ <activity android:name="AnimatedVectorDrawableAttr"
+ android:label="AnimatedVectorDrawable Attr Test"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
+ <action android:name="android.intent.action.MAIN"/>
- <category android:name="com.android.test.dynamic.TEST" />
+ <category android:name="com.android.test.dynamic.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="BoundsCheckTest"
- android:label="SetBound check" >
+ <activity android:name="BoundsCheckTest"
+ android:label="SetBound check"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
+ <action android:name="android.intent.action.MAIN"/>
- <category android:name="com.android.test.dynamic.TEST" />
+ <category android:name="com.android.test.dynamic.TEST"/>
</intent-filter>
</activity>
</application>
diff --git a/tests/VoiceEnrollment/AndroidManifest.xml b/tests/VoiceEnrollment/AndroidManifest.xml
index 46f6ff541b4d..d30f21c1cd57 100644
--- a/tests/VoiceEnrollment/AndroidManifest.xml
+++ b/tests/VoiceEnrollment/AndroidManifest.xml
@@ -1,20 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.test.voiceenrollment">
+ package="com.android.test.voiceenrollment">
- <uses-permission android:name="android.permission.MANAGE_VOICE_KEYPHRASES" />
- <application
- android:permission="android.permission.MANAGE_VOICE_KEYPHRASES">
- <activity
- android:name="TestEnrollmentActivity"
- android:label="Voice Enrollment Application"
- android:theme="@android:style/Theme.Material.Light.Voice">
+ <uses-permission android:name="android.permission.MANAGE_VOICE_KEYPHRASES"/>
+ <application android:permission="android.permission.MANAGE_VOICE_KEYPHRASES">
+ <activity android:name="TestEnrollmentActivity"
+ android:label="Voice Enrollment Application"
+ android:theme="@android:style/Theme.Material.Light.Voice"
+ android:exported="true">
<intent-filter>
- <action android:name="com.android.intent.action.MANAGE_VOICE_KEYPHRASES" />
- <category android:name="android.intent.category.DEFAULT" />
+ <action android:name="com.android.intent.action.MANAGE_VOICE_KEYPHRASES"/>
+ <category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
- <meta-data
- android:name="android.voice_enrollment"
- android:resource="@xml/enrollment_application"/>
+ <meta-data android:name="android.voice_enrollment"
+ android:resource="@xml/enrollment_application"/>
</application>
</manifest>
diff --git a/tests/VoiceInteraction/AndroidManifest.xml b/tests/VoiceInteraction/AndroidManifest.xml
index 5fdf0dd3992c..5d8cea783dd7 100644
--- a/tests/VoiceInteraction/AndroidManifest.xml
+++ b/tests/VoiceInteraction/AndroidManifest.xml
@@ -1,74 +1,88 @@
+<?xml version="1.0" encoding="utf-8"?>
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.test.voiceinteraction">
+ package="com.android.test.voiceinteraction">
- <uses-sdk android:minSdkVersion="23" android:targetSdkVersion="25" />
+ <uses-sdk android:minSdkVersion="23"
+ android:targetSdkVersion="25"/>
- <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" />
- <uses-permission android:name="android.permission.READ_LOGS" />
+ <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS"/>
+ <uses-permission android:name="android.permission.READ_LOGS"/>
<application>
- <activity android:name="VoiceInteractionMain" android:label="Voice Interaction"
- android:theme="@android:style/Theme.Material">
+ <activity android:name="VoiceInteractionMain"
+ android:label="Voice Interaction"
+ android:theme="@android:style/Theme.Material"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:name="AssistProxyActivity"
- android:label="Test Assist Proxy"
- android:theme="@android:style/Theme.NoDisplay"
- android:excludeFromRecents="true"
- android:noHistory="true"
- android:taskAffinity="">
+ android:label="Test Assist Proxy"
+ android:theme="@android:style/Theme.NoDisplay"
+ android:excludeFromRecents="true"
+ android:noHistory="true"
+ android:taskAffinity=""
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.ASSIST" />
- <category android:name="android.intent.category.DEFAULT" />
+ <action android:name="android.intent.action.ASSIST"/>
+ <category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
<activity android:name="SettingsActivity"
- android:label="Voice Interaction Settings">
+ android:label="Voice Interaction Settings"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
<service android:name="MainInteractionService"
- android:label="Test Voice Interaction Service"
- android:permission="android.permission.BIND_VOICE_INTERACTION"
- android:process=":interactor">
+ android:label="Test Voice Interaction Service"
+ android:permission="android.permission.BIND_VOICE_INTERACTION"
+ android:process=":interactor"
+ android:exported="true">
<meta-data android:name="android.voice_interaction"
- android:resource="@xml/interaction_service" />
+ android:resource="@xml/interaction_service"/>
<intent-filter>
- <action android:name="android.service.voice.VoiceInteractionService" />
+ <action android:name="android.service.voice.VoiceInteractionService"/>
</intent-filter>
</service>
<service android:name="MainInteractionSessionService"
- android:permission="android.permission.BIND_VOICE_INTERACTION"
- android:process=":session">
+ android:permission="android.permission.BIND_VOICE_INTERACTION"
+ android:process=":session">
</service>
<service android:name="MainRecognitionService"
- android:label="Test Voice Interaction Service">
+ android:label="Test Voice Interaction Service"
+ android:exported="true">
<intent-filter>
- <action android:name="android.speech.RecognitionService" />
- <category android:name="android.intent.category.DEFAULT" />
+ <action android:name="android.speech.RecognitionService"/>
+ <category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
- <meta-data android:name="android.speech" android:resource="@xml/recognition_service" />
+ <meta-data android:name="android.speech"
+ android:resource="@xml/recognition_service"/>
</service>
- <activity android:name="TestInteractionActivity" android:label="Voice Interaction Target"
- android:theme="@android:style/Theme.Material.Light">
+ <activity android:name="TestInteractionActivity"
+ android:label="Voice Interaction Target"
+ android:theme="@android:style/Theme.Material.Light"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.VOICE" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.VOICE"/>
</intent-filter>
</activity>
- <activity android:name="StartVoiceInteractionActivity" android:label="In-Activity Voice"
- android:theme="@android:style/Theme.Material.Light">
+ <activity android:name="StartVoiceInteractionActivity"
+ android:label="In-Activity Voice"
+ android:theme="@android:style/Theme.Material.Light"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
diff --git a/tests/WallpaperTest/AndroidManifest.xml b/tests/WallpaperTest/AndroidManifest.xml
index 4c914dd5498d..8d7ccb9476ca 100644
--- a/tests/WallpaperTest/AndroidManifest.xml
+++ b/tests/WallpaperTest/AndroidManifest.xml
@@ -1,31 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.example.wallpapertest" >
+ package="com.example.wallpapertest">
- <uses-permission android:name="android.permission.SET_WALLPAPER_HINTS" />
+ <uses-permission android:name="android.permission.SET_WALLPAPER_HINTS"/>
- <application
- android:label="@string/app_name"
- android:theme="@style/AppTheme" >
- <activity
- android:name=".MainActivity"
- android:label="@string/app_name" >
+ <application android:label="@string/app_name"
+ android:theme="@style/AppTheme">
+ <activity android:name=".MainActivity"
+ android:label="@string/app_name"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <service
- android:label="@string/test_wallpaper"
- android:name=".TestWallpaper"
- android:permission="android.permission.BIND_WALLPAPER"
- android:enabled="true">
+ <service android:label="@string/test_wallpaper"
+ android:name=".TestWallpaper"
+ android:permission="android.permission.BIND_WALLPAPER"
+ android:enabled="true"
+ android:exported="true">
<intent-filter>
- <action android:name="android.service.wallpaper.WallpaperService" />
+ <action android:name="android.service.wallpaper.WallpaperService"/>
</intent-filter>
<meta-data android:name="android.service.wallpaper"
- android:resource="@xml/test_wallpaper" />
+ android:resource="@xml/test_wallpaper"/>
</service>
</application>
</manifest>
diff --git a/tests/WindowAnimationJank/AndroidManifest.xml b/tests/WindowAnimationJank/AndroidManifest.xml
index d7aef3348af3..34d24408be1f 100644
--- a/tests/WindowAnimationJank/AndroidManifest.xml
+++ b/tests/WindowAnimationJank/AndroidManifest.xml
@@ -1,5 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
-
<!--
* Copyright (C) 2015 The Android Open Source Project
*
@@ -15,26 +14,28 @@
* See the License for the specific language governing permissions and
* limitations under the License.
-->
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="android.windowanimationjank">
+ package="android.windowanimationjank">
- <uses-permission android:name="android.permission.EXPAND_STATUS_BAR" />
+ <uses-permission android:name="android.permission.EXPAND_STATUS_BAR"/>
<application>
<uses-library android:name="android.test.runner"/>
<activity android:name="ElementLayoutActivity"
- android:label="ElementLayoutActivity"
- android:taskAffinity="android.windowanimationjank.ElementLayoutActivity" >
+ android:label="ElementLayoutActivity"
+ android:taskAffinity="android.windowanimationjank.ElementLayoutActivity"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
<!-- self-instrumenting test package. -->
<instrumentation android:name="android.test.InstrumentationTestRunner"
- android:targetPackage="android.windowanimationjank">
+ android:targetPackage="android.windowanimationjank">
</instrumentation>
</manifest>
diff --git a/tests/WindowInsetsTests/AndroidManifest.xml b/tests/WindowInsetsTests/AndroidManifest.xml
index 0f6282e20b41..61dd9d4cd021 100644
--- a/tests/WindowInsetsTests/AndroidManifest.xml
+++ b/tests/WindowInsetsTests/AndroidManifest.xml
@@ -18,15 +18,22 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.google.android.test.windowinsetstests">
- <application android:label="@string/activity_title">
- <activity android:name=".WindowInsetsActivity"
- android:theme="@style/appTheme"
- android:windowSoftInputMode="adjustResize">
-
+ <application android:label="@string/application_title">
+ <activity android:name=".WindowInsetsTestsMainActivity"
+ android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
+
+ <activity android:name=".ChatActivity"
+ android:label="@string/chat_activity_title"
+ android:theme="@style/chat"
+ android:windowSoftInputMode="adjustResize" />
+
+ <activity android:name=".ControllerActivity"
+ android:label="@string/controller_activity_title"
+ android:theme="@style/controller" />
</application>
</manifest>
diff --git a/tests/WindowInsetsTests/res/layout/window_inset_activity.xml b/tests/WindowInsetsTests/res/layout/chat_activity.xml
index 1b51c4f83fe0..1b51c4f83fe0 100644
--- a/tests/WindowInsetsTests/res/layout/window_inset_activity.xml
+++ b/tests/WindowInsetsTests/res/layout/chat_activity.xml
diff --git a/tests/WindowInsetsTests/res/layout/controller_activity.xml b/tests/WindowInsetsTests/res/layout/controller_activity.xml
new file mode 100644
index 000000000000..d51a4ddd43e8
--- /dev/null
+++ b/tests/WindowInsetsTests/res/layout/controller_activity.xml
@@ -0,0 +1,106 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 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.
+-->
+
+
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <LinearLayout
+ android:id="@+id/content"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <Spinner
+ android:id="@+id/spinnerBehavior"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="10dp"
+ android:layout_marginBottom="20dp" />
+
+ <ToggleButton
+ android:id="@+id/toggleButtonStatus"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:checked="true"
+ android:text="Status Bars Toggle Button"
+ android:textOff="Status Bars Invisible"
+ android:textOn="Status Bars Visible" />
+
+ <SeekBar
+ android:id="@+id/seekBarStatus"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="10dp"
+ android:layout_marginBottom="20dp"
+ android:max="10000"
+ android:progress="10000" />
+
+ <ToggleButton
+ android:id="@+id/toggleButtonNavigation"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:checked="true"
+ android:text="Navigation Bars Toggle Button"
+ android:textOff="Navigation Bars Invisible"
+ android:textOn="Navigation Bars Visible" />
+
+ <SeekBar
+ android:id="@+id/seekBarNavigation"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="10dp"
+ android:layout_marginBottom="20dp"
+ android:max="10000"
+ android:progress="10000" />
+
+ <ToggleButton
+ android:id="@+id/toggleButtonIme"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:checked="true"
+ android:text="IME Toggle Button"
+ android:textOff="IME Invisible"
+ android:textOn="IME Visible" />
+
+ <SeekBar
+ android:id="@+id/seekBarIme"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="10dp"
+ android:layout_marginBottom="20dp"
+ android:max="10000"
+ android:progress="0" />
+
+ <TextView
+ android:id="@+id/textViewControllableInsets"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_margin="5dp" />
+
+ <EditText
+ android:id="@+id/editText"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:ems="10"
+ android:hint="For testing IME..."
+ android:inputType="text"
+ android:text="" />
+
+ </LinearLayout>
+
+</ScrollView> \ No newline at end of file
diff --git a/tests/ActivityViewTest/res/layout/activity_view_main_activity.xml b/tests/WindowInsetsTests/res/layout/main_activity.xml
index efcaef679a9c..621ed89204d1 100644
--- a/tests/ActivityViewTest/res/layout/activity_view_main_activity.xml
+++ b/tests/WindowInsetsTests/res/layout/main_activity.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2018 The Android Open Source Project
+<!-- Copyright (C) 2020 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.
@@ -21,30 +21,17 @@
android:orientation="vertical">
<Button
- android:id="@+id/activity_view_button"
+ android:id="@+id/chat_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:text="Test ActivityView"
+ android:text="@string/chat_activity_title"
android:textAllCaps="false"/>
<Button
- android:id="@+id/scroll_activity_view_button"
+ android:id="@+id/controller_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:text="Test Scroll ActivityView"
+ android:text="@string/controller_activity_title"
android:textAllCaps="false"/>
- <Button
- android:id="@+id/resize_activity_view_button"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="Test Resize ActivityView"
- android:textAllCaps="false"/>
-
- <Button
- android:id="@+id/visibility_activity_view_button"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="Test ActivityView Visibility"
- android:textAllCaps="false"/>
</LinearLayout>
diff --git a/tests/WindowInsetsTests/res/values/strings.xml b/tests/WindowInsetsTests/res/values/strings.xml
index 2b8e5f3da362..d6355f5a0464 100644
--- a/tests/WindowInsetsTests/res/values/strings.xml
+++ b/tests/WindowInsetsTests/res/values/strings.xml
@@ -16,5 +16,14 @@
-->
<resources>
- <string name="activity_title">New Insets Chat</string>
+ <string name="application_title">Window Insets Tests</string>
+ <string name="chat_activity_title">New Insets Chat</string>
+ <string name="controller_activity_title">Window Insets Controller</string>
+
+ <!-- The item positions should match the flag values respectively. -->
+ <string-array name="behaviors">
+ <item>BEHAVIOR_SHOW_BARS_BY_TOUCH</item>
+ <item>BEHAVIOR_DEFAULT</item>
+ <item>BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE</item>
+ </string-array>
</resources>
diff --git a/tests/WindowInsetsTests/res/values/styles.xml b/tests/WindowInsetsTests/res/values/styles.xml
index 220671fb8e71..a84ffbed600d 100644
--- a/tests/WindowInsetsTests/res/values/styles.xml
+++ b/tests/WindowInsetsTests/res/values/styles.xml
@@ -17,7 +17,7 @@
<resources>
- <style name="appTheme" parent="@style/Theme.MaterialComponents.Light">
+ <style name="chat" parent="@style/Theme.MaterialComponents.Light">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
@@ -63,5 +63,11 @@
<dimen name="bubble_padding">8dp</dimen>
<dimen name="bubble_padding_side">16dp</dimen>
+ <style name="controller" parent="android:Theme.Material">
+ <item name="android:colorPrimaryDark">#111111</item>
+ <item name="android:navigationBarColor">#111111</item>
+ <item name="android:colorPrimary">#222222</item>
+ <item name="android:colorAccent">#33ccff</item>
+ </style>
</resources> \ No newline at end of file
diff --git a/tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/WindowInsetsActivity.java b/tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/ChatActivity.java
index 498cb7c1c710..ba12acb2c877 100644
--- a/tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/WindowInsetsActivity.java
+++ b/tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/ChatActivity.java
@@ -30,7 +30,6 @@ import android.content.Context;
import android.graphics.Insets;
import android.os.Bundle;
import android.util.AttributeSet;
-import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
@@ -39,8 +38,6 @@ import android.view.WindowInsetsAnimation;
import android.view.WindowInsetsAnimation.Callback;
import android.view.WindowInsetsAnimationControlListener;
import android.view.WindowInsetsAnimationController;
-import android.view.WindowInsetsController;
-import android.view.WindowInsetsController.OnControllableInsetsChangedListener;
import android.view.animation.LinearInterpolator;
import android.widget.LinearLayout;
@@ -49,7 +46,7 @@ import java.util.List;
import androidx.appcompat.app.AppCompatActivity;
-public class WindowInsetsActivity extends AppCompatActivity {
+public class ChatActivity extends AppCompatActivity {
private View mRoot;
@@ -58,7 +55,7 @@ public class WindowInsetsActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- setContentView(R.layout.window_inset_activity);
+ setContentView(R.layout.chat_activity);
setSupportActionBar(findViewById(R.id.toolbar));
@@ -71,7 +68,7 @@ public class WindowInsetsActivity extends AppCompatActivity {
mRoot.setOnTouchListener(new View.OnTouchListener() {
private final ViewConfiguration mViewConfiguration =
- ViewConfiguration.get(WindowInsetsActivity.this);
+ ViewConfiguration.get(ChatActivity.this);
WindowInsetsAnimationController mAnimationController;
WindowInsetsAnimationControlListener mCurrentRequest;
boolean mRequestedController = false;
diff --git a/tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/ControllerActivity.java b/tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/ControllerActivity.java
new file mode 100644
index 000000000000..95fd959e5587
--- /dev/null
+++ b/tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/ControllerActivity.java
@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) 2020 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.google.android.test.windowinsetstests;
+
+import android.app.Activity;
+import android.graphics.Insets;
+import android.os.Bundle;
+import android.view.View;
+import android.view.WindowInsets;
+import android.view.WindowInsets.Type;
+import android.view.WindowInsetsAnimationControlListener;
+import android.view.WindowInsetsAnimationController;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.CompoundButton;
+import android.widget.SeekBar;
+import android.widget.Spinner;
+import android.widget.TextView;
+import android.widget.ToggleButton;
+
+public class ControllerActivity extends Activity implements View.OnApplyWindowInsetsListener {
+
+ private ToggleButton mToggleStatus;
+ private SeekBar mSeekStatus;
+ private ToggleButton mToggleNavigation;
+ private SeekBar mSeekNavigation;
+ private ToggleButton mToggleIme;
+ private SeekBar mSeekIme;
+ private TextView mTextControllableInsets;
+ private boolean[] mNotFromUser = {false};
+ private WindowInsets mLastInsets;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.controller_activity);
+ final Spinner spinnerBehavior = findViewById(R.id.spinnerBehavior);
+ ArrayAdapter<CharSequence> adapterBehavior = ArrayAdapter.createFromResource(this,
+ R.array.behaviors, android.R.layout.simple_spinner_item);
+ adapterBehavior.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ spinnerBehavior.setAdapter(adapterBehavior);
+ spinnerBehavior.setSelection(
+ spinnerBehavior.getWindowInsetsController().getSystemBarsBehavior());
+ spinnerBehavior.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
+ @Override
+ public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
+ parent.getWindowInsetsController().setSystemBarsBehavior(position);
+ }
+
+ @Override
+ public void onNothingSelected(AdapterView<?> parent) { }
+ });
+ mToggleStatus = findViewById(R.id.toggleButtonStatus);
+ mToggleStatus.setTag(mNotFromUser);
+ mToggleStatus.setOnCheckedChangeListener(new ToggleListener(Type.statusBars()));
+ mSeekStatus = findViewById(R.id.seekBarStatus);
+ mSeekStatus.setOnSeekBarChangeListener(new SeekBarListener(Type.statusBars()));
+ mToggleNavigation = findViewById(R.id.toggleButtonNavigation);
+ mToggleNavigation.setTag(mNotFromUser);
+ mToggleNavigation.setOnCheckedChangeListener(new ToggleListener(Type.navigationBars()));
+ mSeekNavigation = findViewById(R.id.seekBarNavigation);
+ mSeekNavigation.setOnSeekBarChangeListener(new SeekBarListener(Type.navigationBars()));
+ mToggleIme = findViewById(R.id.toggleButtonIme);
+ mToggleIme.setTag(mNotFromUser);
+ mToggleIme.setOnCheckedChangeListener(new ToggleListener(Type.ime()));
+ mSeekIme = findViewById(R.id.seekBarIme);
+ mSeekIme.setOnSeekBarChangeListener(new SeekBarListener(Type.ime()));
+ mTextControllableInsets = findViewById(R.id.textViewControllableInsets);
+ final View contentView = findViewById(R.id.content);
+ contentView.setOnApplyWindowInsetsListener(this);
+ contentView.getWindowInsetsController().addOnControllableInsetsChangedListener(
+ (c, types) -> mTextControllableInsets.setText("ControllableInsetsTypes=" + types));
+ }
+
+ @Override
+ public WindowInsets onApplyWindowInsets(View v, WindowInsets insets) {
+ mNotFromUser[0] = true;
+ updateWidgets(insets, Type.statusBars(), mToggleStatus, mSeekStatus);
+ updateWidgets(insets, Type.navigationBars(), mToggleNavigation, mSeekNavigation);
+ updateWidgets(insets, Type.ime(), mToggleIme, mSeekIme);
+ mLastInsets = insets;
+ mNotFromUser[0] = false;
+
+ // Prevent triggering system gestures while controlling seek bars.
+ final Insets gestureInsets = insets.getInsets(Type.systemGestures());
+ v.setPadding(gestureInsets.left, 0, gestureInsets.right, 0);
+
+ return v.onApplyWindowInsets(insets);
+ }
+
+ private void updateWidgets(WindowInsets insets, int types, ToggleButton toggle, SeekBar seek) {
+ final boolean isVisible = insets.isVisible(types);
+ final boolean wasVisible = mLastInsets != null ? mLastInsets.isVisible(types) : !isVisible;
+ if (isVisible != wasVisible) {
+ toggle.setChecked(isVisible);
+ if (!seek.isPressed()) {
+ seek.setProgress(isVisible ? seek.getMax() : seek.getMin(), true /* animate*/);
+ }
+ }
+
+ }
+
+ private static class ToggleListener implements CompoundButton.OnCheckedChangeListener {
+
+ private final @Type.InsetsType int mTypes;
+
+ ToggleListener(int types) {
+ mTypes = types;
+ }
+
+ @Override
+ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+ if (((boolean[]) buttonView.getTag())[0]) {
+ // not from user
+ return;
+ }
+ if (isChecked) {
+ buttonView.getWindowInsetsController().show(mTypes);
+ } else {
+ buttonView.getWindowInsetsController().hide(mTypes);
+ }
+ }
+ }
+
+ private static class SeekBarListener implements SeekBar.OnSeekBarChangeListener {
+
+ private final @Type.InsetsType int mTypes;
+
+ private WindowInsetsAnimationController mController;
+
+ SeekBarListener(int types) {
+ mTypes = types;
+ }
+
+ @Override
+ public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+ if (mController != null && fromUser) {
+ final int min = seekBar.getMin();
+ final float fraction = (progress - min) / (float) (seekBar.getMax() - min);
+ final Insets shownInsets = mController.getShownStateInsets();
+ final Insets hiddenInsets = mController.getHiddenStateInsets();
+ final Insets currentInsets = Insets.of(
+ (int) (0.5f + fraction * (shownInsets.left - hiddenInsets.left)),
+ (int) (0.5f + fraction * (shownInsets.top - hiddenInsets.top)),
+ (int) (0.5f + fraction * (shownInsets.right - hiddenInsets.right)),
+ (int) (0.5f + fraction * (shownInsets.bottom - hiddenInsets.bottom)));
+ mController.setInsetsAndAlpha(currentInsets, 1f /* alpha */, fraction);
+ }
+ }
+
+ @Override
+ public void onStartTrackingTouch(SeekBar seekBar) {
+ if (mController != null) {
+ return;
+ }
+ seekBar.getWindowInsetsController().controlWindowInsetsAnimation(mTypes,
+ -1 /* durationMs */, null /* interpolator */, null /* cancellationSignal */,
+ new WindowInsetsAnimationControlListener() {
+ @Override
+ public void onReady(WindowInsetsAnimationController controller, int types) {
+ mController = controller;
+ if (!seekBar.isPressed()) {
+ onStopTrackingTouch(seekBar);
+ }
+ }
+
+ @Override
+ public void onFinished(WindowInsetsAnimationController controller) {
+ mController = null;
+ }
+
+ @Override
+ public void onCancelled(WindowInsetsAnimationController controller) {
+ mController = null;
+ }
+ });
+ }
+
+ @Override
+ public void onStopTrackingTouch(SeekBar seekBar) {
+ final int min = seekBar.getMin();
+ final int max = seekBar.getMax();
+ final boolean shown = (seekBar.getProgress() - min) * 2 > max - min;
+ seekBar.setProgress(shown ? max : min);
+ if (mController != null) {
+ mController.finish(shown);
+ }
+ }
+ }
+}
diff --git a/tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/WindowInsetsTestsMainActivity.java b/tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/WindowInsetsTestsMainActivity.java
new file mode 100644
index 000000000000..8b77a78ff51e
--- /dev/null
+++ b/tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/WindowInsetsTestsMainActivity.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2020 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.google.android.test.windowinsetstests;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+
+public class WindowInsetsTestsMainActivity extends Activity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.main_activity);
+
+ findViewById(R.id.chat_button).setOnClickListener(
+ v -> startActivity(new Intent(this, ChatActivity.class)));
+
+ findViewById(R.id.controller_button).setOnClickListener(
+ v -> startActivity(new Intent(this, ControllerActivity.class)));
+ }
+}
diff --git a/tests/appwidgets/AppWidgetHostTest/AndroidManifest.xml b/tests/appwidgets/AppWidgetHostTest/AndroidManifest.xml
index bf6a7cbfacef..3601992d13cc 100644
--- a/tests/appwidgets/AppWidgetHostTest/AndroidManifest.xml
+++ b/tests/appwidgets/AppWidgetHostTest/AndroidManifest.xml
@@ -1,36 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.tests.appwidgethost">
- <uses-permission android:name="android.permission.VIBRATE" />
+ package="com.android.tests.appwidgethost">
+ <uses-permission android:name="android.permission.VIBRATE"/>
<application>
- <activity android:name="AppWidgetHostActivity" android:label="_AppWidgetHost">
+ <activity android:name="AppWidgetHostActivity"
+ android:label="_AppWidgetHost"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="TestAppWidgetConfigure" android:label="Configure TestAppWidgetProvider">
+ <activity android:name="TestAppWidgetConfigure"
+ android:label="Configure TestAppWidgetProvider"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<!-- BEGIN_INCLUDE(AppWidgetProvider) -->
<receiver android:name="TestAppWidgetProvider"
- android:label="@string/oh_hai"
- android:icon="@drawable/oh_hai_icon"
- >
+ android:label="@string/oh_hai"
+ android:icon="@drawable/oh_hai_icon"
+ android:exported="true">
<intent-filter>
- <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
+ <action android:name="android.appwidget.action.APPWIDGET_UPDATE"/>
</intent-filter>
<meta-data android:name="android.appwidget.provider"
- android:resource="@xml/appwidget_info"
- />
+ android:resource="@xml/appwidget_info"/>
</receiver>
<!-- END_INCLUDE(AppWidgetProvider) -->
-
+
</application>
</manifest>
diff --git a/tests/appwidgets/AppWidgetProviderTest/AndroidManifest.xml b/tests/appwidgets/AppWidgetProviderTest/AndroidManifest.xml
index ec4d583ddccb..4f6a81fadd52 100644
--- a/tests/appwidgets/AppWidgetProviderTest/AndroidManifest.xml
+++ b/tests/appwidgets/AppWidgetProviderTest/AndroidManifest.xml
@@ -1,13 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.tests.appwidgetprovider">
- <uses-permission android:name="android.permission.VIBRATE" />
+ package="com.android.tests.appwidgetprovider">
+ <uses-permission android:name="android.permission.VIBRATE"/>
<application>
- <receiver android:name="TestAppWidgetProvider">
+ <receiver android:name="TestAppWidgetProvider"
+ android:exported="true">
<intent-filter>
- <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
+ <action android:name="android.appwidget.action.APPWIDGET_UPDATE"/>
</intent-filter>
- <meta-data android:name="android.appwidget.provider" android:resource="@xml/appwidget_info" />
+ <meta-data android:name="android.appwidget.provider"
+ android:resource="@xml/appwidget_info"/>
</receiver>
</application>
</manifest>
diff --git a/tests/backup/AndroidManifest.xml b/tests/backup/AndroidManifest.xml
index 3778742e105e..f0a3eb2da8ea 100644
--- a/tests/backup/AndroidManifest.xml
+++ b/tests/backup/AndroidManifest.xml
@@ -1,11 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.backuptest">
+ package="com.android.backuptest">
<application android:backupAgent="BackupTestAgent">
- <activity android:name="BackupTestActivity" android:label="_BackupTest">
+ <activity android:name="BackupTestActivity"
+ android:label="_BackupTest"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
diff --git a/tests/benchmarks/internal/Android.bp b/tests/benchmarks/internal/Android.bp
new file mode 100644
index 000000000000..74ed7a34f626
--- /dev/null
+++ b/tests/benchmarks/internal/Android.bp
@@ -0,0 +1,34 @@
+// Copyright (C) 2020 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 {
+ // 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"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+android_test {
+ name: "InternalBenchTests",
+ srcs: ["src/**/*.java"],
+ static_libs: [
+ "androidx.test.rules",
+ "androidx.annotation_annotation",
+ ],
+ test_suites: ["device-tests"],
+ platform_apis: true,
+ certificate: "platform"
+}
diff --git a/tests/benchmarks/internal/AndroidManifest.xml b/tests/benchmarks/internal/AndroidManifest.xml
new file mode 100644
index 000000000000..16023c6f3617
--- /dev/null
+++ b/tests/benchmarks/internal/AndroidManifest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 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.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.internal.bench">
+
+ <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.internal.bench"/>
+</manifest>
+
diff --git a/tests/benchmarks/internal/AndroidTest.xml b/tests/benchmarks/internal/AndroidTest.xml
new file mode 100644
index 000000000000..d776ee681c04
--- /dev/null
+++ b/tests/benchmarks/internal/AndroidTest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 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.
+-->
+<configuration description="Benchmark for internal classes/utilities.">
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="test-file-name" value="InternalBenchTests.apk" />
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="com.android.internal.bench" />
+ <option name="hidden-api-checks" value="false"/>
+ </test>
+
+</configuration>
+
diff --git a/tests/benchmarks/internal/src/com/android/internal/LambdaPerfTest.java b/tests/benchmarks/internal/src/com/android/internal/LambdaPerfTest.java
new file mode 100644
index 000000000000..388548691b77
--- /dev/null
+++ b/tests/benchmarks/internal/src/com/android/internal/LambdaPerfTest.java
@@ -0,0 +1,454 @@
+/*
+ * Copyright (C) 2020 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;
+
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import android.app.Activity;
+import android.graphics.Rect;
+import android.os.Bundle;
+import android.os.Message;
+import android.os.ParcelFileDescriptor;
+import android.os.Process;
+import android.os.SystemClock;
+import android.util.Log;
+
+import androidx.test.filters.LargeTest;
+
+import com.android.internal.util.function.pooled.PooledConsumer;
+import com.android.internal.util.function.pooled.PooledLambda;
+import com.android.internal.util.function.pooled.PooledPredicate;
+
+import org.junit.Assume;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TestRule;
+import org.junit.runners.model.Statement;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.function.Consumer;
+import java.util.function.Predicate;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/** Compares the performance of regular lambda and pooled lambda. */
+@LargeTest
+public class LambdaPerfTest {
+ private static final boolean DEBUG = false;
+ private static final String TAG = LambdaPerfTest.class.getSimpleName();
+
+ private static final String LAMBDA_FORM_REGULAR = "regular";
+ private static final String LAMBDA_FORM_POOLED = "pooled";
+
+ private static final int WARMUP_ITERATIONS = 1000;
+ private static final int TEST_ITERATIONS = 3000000;
+ private static final int TASK_COUNT = 10;
+ private static final long DELAY_AFTER_BENCH_MS = 1000;
+
+ private String mMethodName;
+
+ private final Bundle mTestResults = new Bundle();
+ private final ArrayList<Task> mTasks = new ArrayList<>();
+
+ // The member fields are used to ensure lambda capturing. They don't have the actual meaning.
+ private final Task mTask = new Task();
+ private final Rect mBounds = new Rect();
+ private int mTaskId;
+ private long mTime;
+ private boolean mTop;
+
+ @Rule
+ public final TestRule mRule = (base, description) -> new Statement() {
+ @Override
+ public void evaluate() throws Throwable {
+ mMethodName = description.getMethodName();
+ mTasks.clear();
+ for (int i = 0; i < TASK_COUNT; i++) {
+ final Task t = new Task();
+ mTasks.add(t);
+ }
+ base.evaluate();
+
+ getInstrumentation().sendStatus(Activity.RESULT_OK, mTestResults);
+ }
+ };
+
+ @Test
+ public void test1ParamConsumer() {
+ evaluate(LAMBDA_FORM_REGULAR, () -> forAllTask(t -> t.doSomething(mTask)));
+ evaluate(LAMBDA_FORM_POOLED, () -> {
+ final PooledConsumer c = PooledLambda.obtainConsumer(Task::doSomething,
+ PooledLambda.__(Task.class), mTask);
+ forAllTask(c);
+ c.recycle();
+ });
+ }
+
+ @Test
+ public void test2PrimitiveParamsConsumer() {
+ // Not in Integer#IntegerCache (-128~127) for autoboxing, that will create new object.
+ mTaskId = 12345;
+ mTime = 54321;
+
+ evaluate(LAMBDA_FORM_REGULAR, () -> forAllTask(t -> t.doSomething(mTaskId, mTime)));
+ evaluate(LAMBDA_FORM_POOLED, () -> {
+ final PooledConsumer c = PooledLambda.obtainConsumer(Task::doSomething,
+ PooledLambda.__(Task.class), mTaskId, mTime);
+ forAllTask(c);
+ c.recycle();
+ });
+ }
+
+ @Test
+ public void test3ParamsPredicate() {
+ mTop = true;
+ // In Integer#IntegerCache.
+ mTaskId = 10;
+
+ evaluate(LAMBDA_FORM_REGULAR, () -> handleTask(t -> t.doSomething(mBounds, mTop, mTaskId)));
+ evaluate(LAMBDA_FORM_POOLED, () -> {
+ final PooledPredicate c = PooledLambda.obtainPredicate(Task::doSomething,
+ PooledLambda.__(Task.class), mBounds, mTop, mTaskId);
+ handleTask(c);
+ c.recycle();
+ });
+ }
+
+ @Test
+ public void testMessage() {
+ evaluate(LAMBDA_FORM_REGULAR, () -> {
+ final Message m = Message.obtain().setCallback(() -> mTask.doSomething(mTaskId, mTime));
+ m.getCallback().run();
+ m.recycle();
+ });
+ evaluate(LAMBDA_FORM_POOLED, () -> {
+ final Message m = PooledLambda.obtainMessage(Task::doSomething, mTask, mTaskId, mTime);
+ m.getCallback().run();
+ m.recycle();
+ });
+ }
+
+ @Test
+ public void testRunnable() {
+ evaluate(LAMBDA_FORM_REGULAR, () -> {
+ final Runnable r = mTask::doSomething;
+ r.run();
+ });
+ evaluate(LAMBDA_FORM_POOLED, () -> {
+ final Runnable r = PooledLambda.obtainRunnable(Task::doSomething, mTask).recycleOnUse();
+ r.run();
+ });
+ }
+
+ @Test
+ public void testMultiThread() {
+ final int numThread = 3;
+
+ final Runnable regularAction = () -> forAllTask(t -> t.doSomething(mTask));
+ final Runnable[] regularActions = new Runnable[numThread];
+ Arrays.fill(regularActions, regularAction);
+ evaluateMultiThread(LAMBDA_FORM_REGULAR, regularActions);
+
+ final Runnable pooledAction = () -> {
+ final PooledConsumer c = PooledLambda.obtainConsumer(Task::doSomething,
+ PooledLambda.__(Task.class), mTask);
+ forAllTask(c);
+ c.recycle();
+ };
+ final Runnable[] pooledActions = new Runnable[numThread];
+ Arrays.fill(pooledActions, pooledAction);
+ evaluateMultiThread(LAMBDA_FORM_POOLED, pooledActions);
+ }
+
+ private void forAllTask(Consumer<Task> callback) {
+ for (int i = mTasks.size() - 1; i >= 0; i--) {
+ callback.accept(mTasks.get(i));
+ }
+ }
+
+ private void handleTask(Predicate<Task> callback) {
+ for (int i = mTasks.size() - 1; i >= 0; i--) {
+ final Task task = mTasks.get(i);
+ if (callback.test(task)) {
+ return;
+ }
+ }
+ }
+
+ private void evaluate(String title, Runnable action) {
+ for (int i = 0; i < WARMUP_ITERATIONS; i++) {
+ action.run();
+ }
+ performGc();
+
+ final GcStatus startGcStatus = getGcStatus();
+ final long startTime = SystemClock.elapsedRealtime();
+ for (int i = 0; i < TEST_ITERATIONS; i++) {
+ action.run();
+ }
+ evaluateResult(title, startGcStatus, startTime);
+ }
+
+ private void evaluateMultiThread(String title, Runnable[] actions) {
+ performGc();
+
+ final CountDownLatch latch = new CountDownLatch(actions.length);
+ final GcStatus startGcStatus = getGcStatus();
+ final long startTime = SystemClock.elapsedRealtime();
+ for (Runnable action : actions) {
+ new Thread() {
+ @Override
+ public void run() {
+ for (int i = 0; i < TEST_ITERATIONS; i++) {
+ action.run();
+ }
+ latch.countDown();
+ };
+ }.start();
+ }
+ try {
+ latch.await();
+ } catch (InterruptedException ignored) {
+ }
+ evaluateResult(title, startGcStatus, startTime);
+ }
+
+ private void evaluateResult(String title, GcStatus startStatus, long startTime) {
+ final float elapsed = SystemClock.elapsedRealtime() - startTime;
+ // Sleep a while to see if GC may happen.
+ SystemClock.sleep(DELAY_AFTER_BENCH_MS);
+ final GcStatus endStatus = getGcStatus();
+ final GcInfo info = startStatus.calculateGcTime(endStatus, title, mTestResults);
+ Log.i(TAG, mMethodName + "_" + title + " execution time: "
+ + elapsed + "ms (avg=" + String.format("%.5f", elapsed / TEST_ITERATIONS) + "ms)"
+ + " GC time: " + String.format("%.3f", info.mTotalGcTime) + "ms"
+ + " GC paused time: " + String.format("%.3f", info.mTotalGcPausedTime) + "ms");
+ }
+
+ /** Cleans the test environment. */
+ private static void performGc() {
+ System.gc();
+ System.runFinalization();
+ System.gc();
+ }
+
+ private static GcStatus getGcStatus() {
+ if (DEBUG) {
+ Log.i(TAG, "===== Read GC dump =====");
+ }
+ final GcStatus status = new GcStatus();
+ final List<String> vmDump = getVmDump();
+ Assume.assumeFalse("VM dump is empty", vmDump.isEmpty());
+ for (String line : vmDump) {
+ status.visit(line);
+ if (line.startsWith("DALVIK THREADS")) {
+ break;
+ }
+ }
+ return status;
+ }
+
+ private static List<String> getVmDump() {
+ final int myPid = Process.myPid();
+ // Another approach Debug#dumpJavaBacktraceToFileTimeout requires setenforce 0.
+ Process.sendSignal(myPid, Process.SIGNAL_QUIT);
+ // Give a chance to handle the signal.
+ SystemClock.sleep(100);
+
+ String dump = null;
+ final String pattern = myPid + " written to: ";
+ final List<String> logs = shell("logcat -v brief -d tombstoned:I *:S");
+ for (int i = logs.size() - 1; i >= 0; i--) {
+ final String log = logs.get(i);
+ // Log pattern: Traces for pid 9717 written to: /data/anr/trace_07
+ final int pos = log.indexOf(pattern);
+ if (pos > 0) {
+ dump = log.substring(pattern.length() + pos);
+ break;
+ }
+ }
+
+ Assume.assumeNotNull("Unable to find VM dump", dump);
+ // It requires system or root uid to read the trace.
+ return shell("cat " + dump);
+ }
+
+ private static List<String> shell(String command) {
+ final ParcelFileDescriptor.AutoCloseInputStream stream =
+ new ParcelFileDescriptor.AutoCloseInputStream(
+ getInstrumentation().getUiAutomation().executeShellCommand(command));
+ final ArrayList<String> lines = new ArrayList<>();
+ try (BufferedReader br = new BufferedReader(new InputStreamReader(stream))) {
+ String line;
+ while ((line = br.readLine()) != null) {
+ lines.add(line);
+ }
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ return lines;
+ }
+
+ /** An empty class which provides some methods with different type arguments. */
+ static class Task {
+ void doSomething() {
+ }
+
+ void doSomething(Task t) {
+ }
+
+ void doSomething(int taskId, long time) {
+ }
+
+ boolean doSomething(Rect bounds, boolean top, int taskId) {
+ return false;
+ }
+ }
+
+ static class ValPattern {
+ static final int TYPE_COUNT = 0;
+ static final int TYPE_TIME = 1;
+ static final String PATTERN_COUNT = "(\\d+)";
+ static final String PATTERN_TIME = "(\\d+\\.?\\d+)(\\w+)";
+ final String mRawPattern;
+ final Pattern mPattern;
+ final int mType;
+
+ int mIntValue;
+ float mFloatValue;
+
+ ValPattern(String p, int type) {
+ mRawPattern = p;
+ mPattern = Pattern.compile(
+ p + (type == TYPE_TIME ? PATTERN_TIME : PATTERN_COUNT) + ".*");
+ mType = type;
+ }
+
+ boolean visit(String line) {
+ final Matcher matcher = mPattern.matcher(line);
+ if (!matcher.matches()) {
+ return false;
+ }
+ final String value = matcher.group(1);
+ if (value == null) {
+ return false;
+ }
+ if (mType == TYPE_COUNT) {
+ mIntValue = Integer.parseInt(value);
+ return true;
+ }
+ final float time = Float.parseFloat(value);
+ final String unit = matcher.group(2);
+ if (unit == null) {
+ return false;
+ }
+ // Refer to art/libartbase/base/time_utils.cc
+ switch (unit) {
+ case "s":
+ mFloatValue = time * 1000;
+ break;
+ case "ms":
+ mFloatValue = time;
+ break;
+ case "us":
+ mFloatValue = time / 1000;
+ break;
+ case "ns":
+ mFloatValue = time / 1000 / 1000;
+ break;
+ default:
+ throw new IllegalArgumentException();
+ }
+
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ return mRawPattern + (mType == TYPE_TIME ? (mFloatValue + "ms") : mIntValue);
+ }
+ }
+
+ /** Parses the dump pattern of Heap::DumpGcPerformanceInfo. */
+ private static class GcStatus {
+ private static final int TOTAL_GC_TIME_INDEX = 1;
+ private static final int TOTAL_GC_PAUSED_TIME_INDEX = 5;
+
+ // Refer to art/runtime/gc/heap.cc
+ final ValPattern[] mPatterns = {
+ new ValPattern("Total GC count: ", ValPattern.TYPE_COUNT),
+ new ValPattern("Total GC time: ", ValPattern.TYPE_TIME),
+ new ValPattern("Total time waiting for GC to complete: ", ValPattern.TYPE_TIME),
+ new ValPattern("Total blocking GC count: ", ValPattern.TYPE_COUNT),
+ new ValPattern("Total blocking GC time: ", ValPattern.TYPE_TIME),
+ new ValPattern("Total mutator paused time: ", ValPattern.TYPE_TIME),
+ new ValPattern("Total number of allocations ", ValPattern.TYPE_COUNT),
+ new ValPattern("concurrent copying paused: Sum: ", ValPattern.TYPE_TIME),
+ new ValPattern("concurrent copying total time: ", ValPattern.TYPE_TIME),
+ new ValPattern("concurrent copying freed: ", ValPattern.TYPE_COUNT),
+ new ValPattern("Peak regions allocated ", ValPattern.TYPE_COUNT),
+ };
+
+ void visit(String dumpLine) {
+ for (ValPattern p : mPatterns) {
+ if (p.visit(dumpLine)) {
+ if (DEBUG) {
+ Log.i(TAG, " " + p);
+ }
+ }
+ }
+ }
+
+ GcInfo calculateGcTime(GcStatus newStatus, String title, Bundle result) {
+ Log.i(TAG, "===== GC status of " + title + " =====");
+ final GcInfo info = new GcInfo();
+ for (int i = 0; i < mPatterns.length; i++) {
+ final ValPattern p = mPatterns[i];
+ if (p.mType == ValPattern.TYPE_COUNT) {
+ final int diff = newStatus.mPatterns[i].mIntValue - p.mIntValue;
+ Log.i(TAG, " " + p.mRawPattern + diff);
+ if (diff > 0) {
+ result.putInt("[" + title + "] " + p.mRawPattern, diff);
+ }
+ continue;
+ }
+ final float diff = newStatus.mPatterns[i].mFloatValue - p.mFloatValue;
+ Log.i(TAG, " " + p.mRawPattern + diff + "ms");
+ if (diff > 0) {
+ result.putFloat("[" + title + "] " + p.mRawPattern + "(ms)", diff);
+ }
+ if (i == TOTAL_GC_TIME_INDEX) {
+ info.mTotalGcTime = diff;
+ } else if (i == TOTAL_GC_PAUSED_TIME_INDEX) {
+ info.mTotalGcPausedTime = diff;
+ }
+ }
+ return info;
+ }
+ }
+
+ private static class GcInfo {
+ float mTotalGcTime;
+ float mTotalGcPausedTime;
+ }
+}
diff --git a/tests/net/integration/src/com/android/server/net/integrationtests/TestNetworkStackService.kt b/tests/net/integration/src/com/android/server/net/integrationtests/TestNetworkStackService.kt
deleted file mode 100644
index 649f71d4293f..000000000000
--- a/tests/net/integration/src/com/android/server/net/integrationtests/TestNetworkStackService.kt
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright (C) 2019 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.net.integrationtests
-
-import android.app.Service
-import android.content.Context
-import android.content.Intent
-import android.net.INetworkMonitorCallbacks
-import android.net.Network
-import android.net.metrics.IpConnectivityLog
-import android.net.util.SharedLog
-import android.os.IBinder
-import com.android.networkstack.netlink.TcpSocketTracker
-import com.android.server.NetworkStackService
-import com.android.server.NetworkStackService.NetworkMonitorConnector
-import com.android.server.NetworkStackService.NetworkStackConnector
-import com.android.server.connectivity.NetworkMonitor
-import com.android.server.net.integrationtests.NetworkStackInstrumentationService.InstrumentationConnector
-import org.mockito.Mockito.doReturn
-import org.mockito.Mockito.mock
-import org.mockito.Mockito.spy
-import java.net.HttpURLConnection
-import java.net.URL
-import java.net.URLConnection
-
-private const val TEST_NETID = 42
-
-/**
- * Android service that can return an [android.net.INetworkStackConnector] which can be instrumented
- * through [NetworkStackInstrumentationService].
- * Useful in tests to create test instrumented NetworkStack components that can receive
- * instrumentation commands through [NetworkStackInstrumentationService].
- */
-class TestNetworkStackService : Service() {
- override fun onBind(intent: Intent): IBinder = TestNetworkStackConnector(makeTestContext())
-
- private fun makeTestContext() = spy(applicationContext).also {
- doReturn(mock(IBinder::class.java)).`when`(it).getSystemService(Context.NETD_SERVICE)
- }
-
- private class TestPermissionChecker : NetworkStackService.PermissionChecker() {
- override fun enforceNetworkStackCallingPermission() = Unit
- }
-
- private class NetworkMonitorDeps(private val privateDnsBypassNetwork: Network) :
- NetworkMonitor.Dependencies() {
- override fun getPrivateDnsBypassNetwork(network: Network?) = privateDnsBypassNetwork
- }
-
- private inner class TestNetworkStackConnector(context: Context) : NetworkStackConnector(
- context, TestPermissionChecker(), NetworkStackService.Dependencies()) {
-
- private val network = Network(TEST_NETID)
- private val privateDnsBypassNetwork = TestNetwork(TEST_NETID)
-
- private inner class TestNetwork(netId: Int) : Network(netId) {
- override fun openConnection(url: URL): URLConnection {
- val response = InstrumentationConnector.processRequest(url)
-
- val connection = mock(HttpURLConnection::class.java)
- doReturn(response.responseCode).`when`(connection).responseCode
- doReturn(response.contentLength).`when`(connection).contentLengthLong
- doReturn(response.redirectUrl).`when`(connection).getHeaderField("location")
- return connection
- }
- }
-
- override fun makeNetworkMonitor(
- network: Network,
- name: String?,
- cb: INetworkMonitorCallbacks
- ) {
- val nm = NetworkMonitor(this@TestNetworkStackService, cb,
- this.network,
- mock(IpConnectivityLog::class.java), mock(SharedLog::class.java),
- mock(NetworkStackService.NetworkStackServiceManager::class.java),
- NetworkMonitorDeps(privateDnsBypassNetwork),
- mock(TcpSocketTracker::class.java))
- cb.onNetworkMonitorCreated(NetworkMonitorConnector(nm, TestPermissionChecker()))
- }
- }
-}
diff --git a/tests/permission/Android.bp b/tests/permission/Android.bp
index bbc2358d206e..d06809b209a0 100644
--- a/tests/permission/Android.bp
+++ b/tests/permission/Android.bp
@@ -13,9 +13,14 @@ android_test {
srcs: ["src/**/*.java"],
libs: [
"android.test.runner",
- "telephony-common",
"android.test.base",
+ "telephony-common",
+ ],
+ static_libs: [
+ "androidx.test.runner",
+ "junit",
+ "platform-test-annotations",
],
- static_libs: ["junit"],
platform_apis: true,
+ test_suites: ["device-tests"],
}
diff --git a/tests/permission/AndroidManifest.xml b/tests/permission/AndroidManifest.xml
index b19bf006cfeb..9ff5fb39bc4b 100644
--- a/tests/permission/AndroidManifest.xml
+++ b/tests/permission/AndroidManifest.xml
@@ -24,9 +24,10 @@
<!--
The test declared in this instrumentation can be run via this command
- "adb shell am instrument -w com.android.framework.permission.tests/android.test.InstrumentationTestRunner"
+ $ adb shell am instrument \
+ -w com.android.framework.permission.tests/androidx.test.runner.AndroidJUnitRunner
-->
- <instrumentation android:name="android.test.InstrumentationTestRunner"
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
android:targetPackage="com.android.framework.permission.tests"
android:label="Tests for private API framework permissions"/>
diff --git a/tests/permission/src/com/android/framework/permission/tests/VibratorManagerServicePermissionTest.java b/tests/permission/src/com/android/framework/permission/tests/VibratorManagerServicePermissionTest.java
new file mode 100644
index 000000000000..e0f3f03e9cb7
--- /dev/null
+++ b/tests/permission/src/com/android/framework/permission/tests/VibratorManagerServicePermissionTest.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2009 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.framework.permission.tests;
+
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import static junit.framework.Assert.fail;
+
+import android.Manifest;
+import android.content.Context;
+import android.os.Binder;
+import android.os.CombinedVibration;
+import android.os.IVibratorManagerService;
+import android.os.IVibratorStateListener;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.VibrationAttributes;
+import android.os.VibrationEffect;
+import android.platform.test.annotations.Presubmit;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+
+/**
+ * Verify that Hardware apis cannot be called without required permissions.
+ */
+@Presubmit
+@RunWith(JUnit4.class)
+public class VibratorManagerServicePermissionTest {
+
+ private static final String PACKAGE_NAME = "com.android.framework.permission.tests";
+ private static final CombinedVibration EFFECT =
+ CombinedVibration.createParallel(
+ VibrationEffect.createOneShot(100, VibrationEffect.DEFAULT_AMPLITUDE));
+ private static final VibrationAttributes ATTRS = new VibrationAttributes.Builder()
+ .setUsage(VibrationAttributes.USAGE_ALARM)
+ .build();
+
+ @Rule
+ public ExpectedException exceptionRule = ExpectedException.none();
+
+ private IVibratorManagerService mVibratorService;
+
+ @Before
+ public void setUp() throws Exception {
+ mVibratorService = IVibratorManagerService.Stub.asInterface(
+ ServiceManager.getService(Context.VIBRATOR_MANAGER_SERVICE));
+ }
+
+ @After
+ public void cleanUp() {
+ getInstrumentation().getUiAutomation().dropShellPermissionIdentity();
+ }
+
+ @Test
+ public void testIsVibratingFails() throws RemoteException {
+ expectSecurityException("ACCESS_VIBRATOR_STATE");
+ mVibratorService.isVibrating(1);
+ }
+
+ @Test
+ public void testRegisterVibratorStateListenerFails() throws RemoteException {
+ expectSecurityException("ACCESS_VIBRATOR_STATE");
+ IVibratorStateListener listener = new IVibratorStateListener.Stub() {
+ @Override
+ public void onVibrating(boolean vibrating) {
+ fail("Listener callback was not expected.");
+ }
+ };
+ mVibratorService.registerVibratorStateListener(1, listener);
+ }
+
+ @Test
+ public void testUnregisterVibratorStateListenerFails() throws RemoteException {
+ expectSecurityException("ACCESS_VIBRATOR_STATE");
+ mVibratorService.unregisterVibratorStateListener(1, null);
+ }
+
+ @Test
+ public void testSetAlwaysOnEffectFails() throws RemoteException {
+ expectSecurityException("VIBRATE_ALWAYS_ON");
+ mVibratorService.setAlwaysOnEffect(Process.myUid(), PACKAGE_NAME, 1, EFFECT, ATTRS);
+ }
+
+ @Test
+ public void testVibrateWithoutPermissionFails() throws RemoteException {
+ expectSecurityException("VIBRATE");
+ mVibratorService.vibrate(Process.myUid(), PACKAGE_NAME, EFFECT, ATTRS, "testVibrate",
+ new Binder());
+ }
+
+ @Test
+ public void testVibrateWithVibratePermissionAndSameProcessUidIsAllowed()
+ throws RemoteException {
+ getInstrumentation().getUiAutomation().adoptShellPermissionIdentity(
+ Manifest.permission.VIBRATE);
+ mVibratorService.vibrate(Process.myUid(), PACKAGE_NAME, EFFECT, ATTRS, "testVibrate",
+ new Binder());
+ }
+
+ @Test
+ public void testVibrateWithVibratePermissionAndDifferentUidsFails() throws RemoteException {
+ expectSecurityException("UPDATE_APP_OPS_STATS");
+ getInstrumentation().getUiAutomation().adoptShellPermissionIdentity(
+ Manifest.permission.VIBRATE);
+ mVibratorService.vibrate(Process.SYSTEM_UID, "android", EFFECT, ATTRS, "testVibrate",
+ new Binder());
+ }
+
+ @Test
+ public void testVibrateWithAllPermissionsAndDifferentUidsIsAllowed() throws RemoteException {
+ getInstrumentation().getUiAutomation().adoptShellPermissionIdentity(
+ Manifest.permission.VIBRATE,
+ Manifest.permission.UPDATE_APP_OPS_STATS);
+ mVibratorService.vibrate(Process.SYSTEM_UID, "android", EFFECT, ATTRS, "testVibrate",
+ new Binder());
+ }
+
+ @Test
+ public void testCancelVibrateFails() throws RemoteException {
+ expectSecurityException("VIBRATE");
+ mVibratorService.cancelVibrate(/* usageFilter= */ -1, new Binder());
+ }
+
+ private void expectSecurityException(String expectedPermission) {
+ exceptionRule.expect(SecurityException.class);
+ exceptionRule.expectMessage("permission." + expectedPermission);
+ }
+}
diff --git a/tests/permission/src/com/android/framework/permission/tests/VibratorServicePermissionTest.java b/tests/permission/src/com/android/framework/permission/tests/VibratorServicePermissionTest.java
deleted file mode 100644
index d1d6a26790fd..000000000000
--- a/tests/permission/src/com/android/framework/permission/tests/VibratorServicePermissionTest.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright (C) 2009 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.framework.permission.tests;
-
-import android.os.Binder;
-import android.os.IVibratorService;
-import android.os.Process;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.os.VibrationAttributes;
-import android.os.VibrationEffect;
-import android.test.suitebuilder.annotation.SmallTest;
-
-import junit.framework.TestCase;
-
-
-/**
- * Verify that Hardware apis cannot be called without required permissions.
- */
-@SmallTest
-public class VibratorServicePermissionTest extends TestCase {
-
- private IVibratorService mVibratorService;
-
- @Override
- protected void setUp() throws Exception {
- mVibratorService = IVibratorService.Stub.asInterface(
- ServiceManager.getService("vibrator"));
- }
-
- /**
- * Test that calling {@link android.os.IVibratorService#vibrate(long)} requires permissions.
- * <p>Tests permission:
- * {@link android.Manifest.permission#VIBRATE}
- * @throws RemoteException
- */
- public void testVibrate() throws RemoteException {
- try {
- final VibrationEffect effect =
- VibrationEffect.createOneShot(100, VibrationEffect.DEFAULT_AMPLITUDE);
- final VibrationAttributes attrs = new VibrationAttributes.Builder()
- .setUsage(VibrationAttributes.USAGE_ALARM)
- .build();
- mVibratorService.vibrate(Process.myUid(), null, effect, attrs,
- "testVibrate", new Binder());
- fail("vibrate did not throw SecurityException as expected");
- } catch (SecurityException e) {
- // expected
- }
- }
-
- /**
- * Test that calling {@link android.os.IVibratorService#cancelVibrate()} requires permissions.
- * <p>Tests permission:
- * {@link android.Manifest.permission#VIBRATE}
- * @throws RemoteException
- */
- public void testCancelVibrate() throws RemoteException {
- try {
- mVibratorService.cancelVibrate(new Binder());
- fail("cancelVibrate did not throw SecurityException as expected");
- } catch (SecurityException e) {
- // expected
- }
- }
-}
diff --git a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
index 737665fb97e4..1fe13fe97fbe 100644
--- a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
+++ b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
@@ -28,8 +28,6 @@ import android.view.IWindowManager;
import junit.framework.TestCase;
-import org.junit.Test;
-
/**
* TODO: Remove this. This is only a placeholder, need to implement this.
*/
@@ -56,7 +54,7 @@ public class WindowManagerPermissionTests extends TestCase {
}
try {
- mWm.addWindowToken(null, TYPE_APPLICATION, DEFAULT_DISPLAY);
+ mWm.addWindowToken(null, TYPE_APPLICATION, DEFAULT_DISPLAY, null /* options */);
fail("IWindowManager.addWindowToken did not throw SecurityException as"
+ " expected");
} catch (SecurityException e) {
@@ -64,26 +62,6 @@ public class WindowManagerPermissionTests extends TestCase {
} catch (RemoteException e) {
fail("Unexpected remote exception");
}
-
- try {
- mWm.prepareAppTransition(0, false);
- fail("IWindowManager.prepareAppTransition did not throw SecurityException as"
- + " expected");
- } catch (SecurityException e) {
- // expected
- } catch (RemoteException e) {
- fail("Unexpected remote exception");
- }
-
- try {
- mWm.executeAppTransition();
- fail("IWindowManager.executeAppTransition did not throw SecurityException as"
- + " expected");
- } catch (SecurityException e) {
- // expected
- } catch (RemoteException e) {
- fail("Unexpected remote exception");
- }
}
@SmallTest
@@ -175,29 +153,4 @@ public class WindowManagerPermissionTests extends TestCase {
fail("Unexpected remote exception");
}
}
-
- @Test
- public void testADD_WINDOW_TOKEN_WITH_OPTIONS() {
- // Verify if addWindowTokenWithOptions throw SecurityException for privileged window type.
- try {
- mWm.addWindowTokenWithOptions(null, TYPE_APPLICATION, DEFAULT_DISPLAY, null, "");
- fail("IWindowManager.addWindowTokenWithOptions did not throw SecurityException as"
- + " expected");
- } catch (SecurityException e) {
- // expected
- } catch (RemoteException e) {
- fail("Unexpected remote exception");
- }
-
- // Verify if addWindowTokenWithOptions throw SecurityException for null packageName.
- try {
- mWm.addWindowTokenWithOptions(null, TYPE_APPLICATION, DEFAULT_DISPLAY, null, null);
- fail("IWindowManager.addWindowTokenWithOptions did not throw SecurityException as"
- + " expected");
- } catch (SecurityException e) {
- // expected
- } catch (RemoteException e) {
- fail("Unexpected remote exception");
- }
- }
}
diff --git a/tests/utils/StubIME/AndroidManifest.xml b/tests/utils/StubIME/AndroidManifest.xml
index 04502d331d6a..bc64c671d9be 100644
--- a/tests/utils/StubIME/AndroidManifest.xml
+++ b/tests/utils/StubIME/AndroidManifest.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
<!--
/*
* Copyright 2006, The Android Open Source Project
@@ -17,16 +18,20 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.testing.stubime">
- <application android:label="Stub IME">
- <service android:name="StubIme"
- android:permission="android.permission.BIND_INPUT_METHOD">
+ package="com.android.testing.stubime">
+ <application android:label="Dummy IME">
+ <service android:name="DummyIme"
+ android:permission="android.permission.BIND_INPUT_METHOD"
+ android:exported="true">
<intent-filter>
- <action android:name="android.view.InputMethod" />
+ <action android:name="android.view.InputMethod"/>
</intent-filter>
- <meta-data android:name="android.view.im" android:resource="@xml/method" />
+ <meta-data android:name="android.view.im"
+ android:resource="@xml/method"/>
</service>
- <activity android:name=".ImePreferences" android:label="Stub IME Settings">
+ <activity android:name=".ImePreferences"
+ android:label="Stub IME Settings"
+ android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
</intent-filter>
diff --git a/tests/utils/hostutils/src/com/android/fsverity/AddFsVerityCertRule.java b/tests/utils/hostutils/src/com/android/fsverity/AddFsVerityCertRule.java
new file mode 100644
index 000000000000..5ab4dc60e2ac
--- /dev/null
+++ b/tests/utils/hostutils/src/com/android/fsverity/AddFsVerityCertRule.java
@@ -0,0 +1,77 @@
+/*
+ * 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.fsverity;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import static org.junit.Assume.assumeTrue;
+
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.log.LogUtil;
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
+import com.android.tradefed.util.CommandResult;
+import com.android.tradefed.util.CommandStatus;
+
+import org.junit.rules.ExternalResource;
+
+public final class AddFsVerityCertRule extends ExternalResource {
+
+ private static final String APK_VERITY_STANDARD_MODE = "2";
+
+ private final BaseHostJUnit4Test mHost;
+ private final String mCertPath;
+ private String mKeyId;
+
+ public AddFsVerityCertRule(BaseHostJUnit4Test host, String certPath) {
+ mHost = host;
+ mCertPath = certPath;
+ }
+
+ @Override
+ protected void before() throws Throwable {
+ ITestDevice device = mHost.getDevice();
+ String apkVerityMode = device.getProperty("ro.apk_verity.mode");
+ assumeTrue(device.getLaunchApiLevel() >= 30
+ || APK_VERITY_STANDARD_MODE.equals(apkVerityMode));
+
+ String keyId = executeCommand(
+ "mini-keyctl padd asymmetric fsv_test .fs-verity < " + mCertPath).trim();
+ assertThat(keyId).matches("^\\d+$");
+ mKeyId = keyId;
+ }
+
+ @Override
+ protected void after() {
+ if (mKeyId == null) return;
+ try {
+ executeCommand("mini-keyctl unlink " + mKeyId + " .fs-verity");
+ } catch (DeviceNotAvailableException e) {
+ LogUtil.CLog.e(e);
+ }
+ mKeyId = null;
+ }
+
+ private String executeCommand(String cmd) throws DeviceNotAvailableException {
+ CommandResult result = mHost.getDevice().executeShellV2Command(cmd);
+ assertWithMessage("`" + cmd + "` failed: " + result.getStderr())
+ .that(result.getStatus())
+ .isEqualTo(CommandStatus.SUCCESS);
+ return result.getStdout();
+ }
+}
diff --git a/tests/utils/hostutils/src/com/android/internal/util/test/SystemPreparer.java b/tests/utils/hostutils/src/com/android/internal/util/test/SystemPreparer.java
index 1139fd6b811e..84448333a8c6 100644
--- a/tests/utils/hostutils/src/com/android/internal/util/test/SystemPreparer.java
+++ b/tests/utils/hostutils/src/com/android/internal/util/test/SystemPreparer.java
@@ -35,6 +35,8 @@ import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.nio.file.Path;
+import java.nio.file.Paths;
import java.util.ArrayList;
import javax.annotation.Nullable;
@@ -50,7 +52,7 @@ import javax.annotation.Nullable;
public class SystemPreparer extends ExternalResource {
private static final long OVERLAY_ENABLE_TIMEOUT_MS = 30000;
- // The paths of the files pushed onto the device through this rule.
+ // The paths of the files pushed onto the device through this rule to be removed after.
private ArrayList<String> mPushedFiles = new ArrayList<>();
// The package names of packages installed through this rule.
@@ -61,12 +63,22 @@ public class SystemPreparer extends ExternalResource {
private final RebootStrategy mRebootStrategy;
private final TearDownRule mTearDownRule;
+ // When debugging, it may be useful to run a test case without rebooting the device afterwards,
+ // to manually verify the device state.
+ private boolean mDebugSkipAfterReboot;
+
public SystemPreparer(TemporaryFolder hostTempFolder, DeviceProvider deviceProvider) {
this(hostTempFolder, RebootStrategy.FULL, null, deviceProvider);
}
public SystemPreparer(TemporaryFolder hostTempFolder, RebootStrategy rebootStrategy,
@Nullable TestRuleDelegate testRuleDelegate, DeviceProvider deviceProvider) {
+ this(hostTempFolder, rebootStrategy, testRuleDelegate, false, deviceProvider);
+ }
+
+ public SystemPreparer(TemporaryFolder hostTempFolder, RebootStrategy rebootStrategy,
+ @Nullable TestRuleDelegate testRuleDelegate, boolean debugSkipAfterReboot,
+ DeviceProvider deviceProvider) {
mHostTempFolder = hostTempFolder;
mDeviceProvider = deviceProvider;
mRebootStrategy = rebootStrategy;
@@ -74,6 +86,7 @@ public class SystemPreparer extends ExternalResource {
if (testRuleDelegate != null) {
testRuleDelegate.setDelegate(mTearDownRule);
}
+ mDebugSkipAfterReboot = debugSkipAfterReboot;
}
/** Copies a file within the host test jar to a path on device. */
@@ -82,7 +95,7 @@ public class SystemPreparer extends ExternalResource {
final ITestDevice device = mDeviceProvider.getDevice();
remount();
assertTrue(device.pushFile(copyResourceToTemp(filePath), outputPath));
- mPushedFiles.add(outputPath);
+ addPushedFile(device, outputPath);
return this;
}
@@ -92,10 +105,23 @@ public class SystemPreparer extends ExternalResource {
final ITestDevice device = mDeviceProvider.getDevice();
remount();
assertTrue(device.pushFile(file, outputPath));
- mPushedFiles.add(outputPath);
+ addPushedFile(device, outputPath);
return this;
}
+ private void addPushedFile(ITestDevice device, String outputPath)
+ throws DeviceNotAvailableException {
+ Path pathCreated = Paths.get(outputPath);
+
+ // Find the top most parent that is new to the device
+ while (pathCreated.getParent() != null
+ && !device.doesFileExist(pathCreated.getParent().toString())) {
+ pathCreated = pathCreated.getParent();
+ }
+
+ mPushedFiles.add(pathCreated.toString());
+ }
+
/** Deletes the given path from the device */
public SystemPreparer deleteFile(String file) throws DeviceNotAvailableException {
final ITestDevice device = mDeviceProvider.getDevice();
@@ -176,7 +202,9 @@ public class SystemPreparer extends ExternalResource {
case USERSPACE_UNTIL_ONLINE:
device.rebootUserspaceUntilOnline();
break;
- case START_STOP:
+ // TODO(b/159540015): Make this START_STOP instead of default once it's fixed. Can't
+ // currently be done because START_STOP is commented out.
+ default:
device.executeShellCommand("stop");
device.executeShellCommand("start");
ITestDevice.RecoveryMode cachedRecoveryMode = device.getRecoveryMode();
@@ -240,7 +268,7 @@ public class SystemPreparer extends ExternalResource {
/** Removes installed packages and files that were pushed to the device. */
@Override
- protected void after() {
+ public void after() {
final ITestDevice device = mDeviceProvider.getDevice();
try {
remount();
@@ -250,7 +278,9 @@ public class SystemPreparer extends ExternalResource {
for (final String packageName : mInstalledPackages) {
device.uninstallPackage(packageName);
}
- reboot();
+ if (!mDebugSkipAfterReboot) {
+ reboot();
+ }
} catch (DeviceNotAvailableException e) {
Assert.fail(e.toString());
}
@@ -377,6 +407,7 @@ public class SystemPreparer extends ExternalResource {
/**
* How to reboot the device. Ordered from slowest to fastest.
*/
+ @SuppressWarnings("DanglingJavadoc")
public enum RebootStrategy {
/** @see ITestDevice#reboot() */
FULL,
@@ -396,7 +427,15 @@ public class SystemPreparer extends ExternalResource {
*
* TODO(b/159540015): There's a bug with this causing unnecessary disk space usage, which
* can eventually lead to an insufficient storage space error.
+ *
+ * This can be uncommented for local development, but should be left out when merging.
+ * It is done this way to hopefully be caught by code review, since merging this will
+ * break all of postsubmit. But the nearly 50% reduction in test runtime is worth having
+ * this option exist.
+ *
+ * @deprecated do not use this in merged code until bug is resolved
*/
- START_STOP
+// @Deprecated
+// START_STOP
}
}
diff --git a/tests/utils/testutils/java/android/view/test/InsetsModeSession.java b/tests/utils/testutils/java/android/view/test/InsetsModeSession.java
deleted file mode 100644
index e05fdce0ca0c..000000000000
--- a/tests/utils/testutils/java/android/view/test/InsetsModeSession.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.view.test;
-
-import android.view.ViewRootImpl;
-
-/**
- * Session to set insets mode for {@link ViewRootImpl#sNewInsetsMode}.
- */
-public class InsetsModeSession implements AutoCloseable {
-
- private int mOldMode;
-
- public InsetsModeSession(int flag) {
- mOldMode = ViewRootImpl.sNewInsetsMode;
- ViewRootImpl.sNewInsetsMode = flag;
- }
-
- @Override
- public void close() {
- ViewRootImpl.sNewInsetsMode = mOldMode;
- }
-}
diff --git a/tests/utils/testutils/java/com/android/internal/util/test/BroadcastInterceptingContext.java b/tests/utils/testutils/java/com/android/internal/util/test/BroadcastInterceptingContext.java
index 4a1f96d145bd..3da8b460df13 100644
--- a/tests/utils/testutils/java/com/android/internal/util/test/BroadcastInterceptingContext.java
+++ b/tests/utils/testutils/java/com/android/internal/util/test/BroadcastInterceptingContext.java
@@ -196,6 +196,12 @@ public class BroadcastInterceptingContext extends ContextWrapper {
}
@Override
+ public void sendBroadcastMultiplePermissions(Intent intent, String[] receiverPermissions,
+ Bundle options) {
+ sendBroadcast(intent);
+ }
+
+ @Override
public void sendBroadcastAsUserMultiplePermissions(Intent intent, UserHandle user,
String[] receiverPermissions) {
sendBroadcast(intent);
diff --git a/tests/utils/testutils/java/com/android/server/wm/test/filters/FrameworksTestsFilter.java b/tests/utils/testutils/java/com/android/server/wm/test/filters/FrameworksTestsFilter.java
index ea803f2aba8b..bcd6ed73e133 100644
--- a/tests/utils/testutils/java/com/android/server/wm/test/filters/FrameworksTestsFilter.java
+++ b/tests/utils/testutils/java/com/android/server/wm/test/filters/FrameworksTestsFilter.java
@@ -30,12 +30,21 @@ import com.android.test.filters.SelectTest;
* -e selectTest_verbose true \
* com.android.frameworks.coretests/androidx.test.runner.AndroidJUnitRunner
* </pre>
+ *
+ * <p>Use this filter when running FrameworksMockingCoreTests as
+ * <pre>
+ * adb shell am instrument -w \
+ * -e filter com.android.server.wm.test.filters.FrameworksTestsFilter \
+ * -e selectTest_verbose true \
+ * com.android.frameworks.mockingcoretests/androidx.test.runner.AndroidJUnitRunner
+ * </pre>
*/
public final class FrameworksTestsFilter extends SelectTest {
private static final String[] SELECTED_TESTS = {
// Test specifications for FrameworksMockingCoreTests.
"android.app.activity.ActivityThreadClientTest",
+ "android.view.DisplayTest",
// Test specifications for FrameworksCoreTests.
"android.app.servertransaction.", // all tests under the package.
"android.view.CutoutSpecificationTest",
@@ -46,10 +55,14 @@ public final class FrameworksTestsFilter extends SelectTest {
"android.view.InsetsSourceTest",
"android.view.InsetsSourceConsumerTest",
"android.view.InsetsStateTest",
+ "android.view.RoundedCornerTest",
+ "android.view.RoundedCornersTest",
"android.view.WindowMetricsTest",
"android.view.PendingInsetsControllerTest",
- "android.app.WindowContextTest",
- "android.window.WindowMetricsHelperTest"
+ "android.window.WindowContextTest",
+ "android.window.WindowMetricsHelperTest",
+ "android.app.activity.ActivityThreadTest",
+ "android.window.WindowContextControllerTest"
};
public FrameworksTestsFilter(Bundle testArgs) {
diff --git a/tests/vcn/java/android/net/vcn/VcnTransportInfoTest.java b/tests/vcn/java/android/net/vcn/VcnTransportInfoTest.java
index abae81cf1742..19df3c75266c 100644
--- a/tests/vcn/java/android/net/vcn/VcnTransportInfoTest.java
+++ b/tests/vcn/java/android/net/vcn/VcnTransportInfoTest.java
@@ -17,6 +17,7 @@
package android.net.vcn;
import static android.net.NetworkCapabilities.REDACT_FOR_ACCESS_FINE_LOCATION;
+import static android.net.NetworkCapabilities.REDACT_FOR_NETWORK_SETTINGS;
import static android.net.NetworkCapabilities.REDACT_NONE;
import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
@@ -24,13 +25,15 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNull;
+import android.net.NetworkCapabilities;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiInfo;
-import android.os.Build;
import android.os.Parcel;
import org.junit.Test;
+import java.util.Arrays;
+
public class VcnTransportInfoTest {
private static final int SUB_ID = 1;
private static final int NETWORK_ID = 5;
@@ -55,19 +58,28 @@ public class VcnTransportInfoTest {
}
@Test
+ public void testMakeCopyRedactForNetworkSettings() {
+ for (VcnTransportInfo info : Arrays.asList(CELL_UNDERLYING_INFO, WIFI_UNDERLYING_INFO)) {
+ assertEquals(
+ INVALID_SUBSCRIPTION_ID,
+ ((VcnTransportInfo) info.makeCopy(REDACT_FOR_NETWORK_SETTINGS))
+ .getSubId());
+ assertNull(
+ ((VcnTransportInfo) info.makeCopy(REDACT_FOR_NETWORK_SETTINGS))
+ .getWifiInfo());
+ }
+ }
+
+ @Test
public void testMakeCopyRedactForAccessFineLocation() {
assertEquals(
SUB_ID,
((VcnTransportInfo) CELL_UNDERLYING_INFO.makeCopy(REDACT_FOR_ACCESS_FINE_LOCATION))
.getSubId());
-
- // TODO: remove the if statement when S pushes to AOSP.
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
- assertEquals(
- WifiConfiguration.INVALID_NETWORK_ID,
- ((VcnTransportInfo) WIFI_UNDERLYING_INFO.makeCopy(
- REDACT_FOR_ACCESS_FINE_LOCATION)).getWifiInfo().getNetworkId());
- }
+ assertEquals(
+ WifiConfiguration.INVALID_NETWORK_ID,
+ ((VcnTransportInfo) WIFI_UNDERLYING_INFO.makeCopy(REDACT_FOR_ACCESS_FINE_LOCATION))
+ .getWifiInfo().getNetworkId());
}
@Test
@@ -78,11 +90,20 @@ public class VcnTransportInfoTest {
}
@Test
- public void testApplicableRedactions() {
- assertEquals(REDACT_NONE, CELL_UNDERLYING_INFO.getApplicableRedactions());
+ public void testParcelUnparcel() {
+ verifyParcelingIsNull(CELL_UNDERLYING_INFO);
+ verifyParcelingIsNull(WIFI_UNDERLYING_INFO);
+ }
+
+ private void verifyParcelingIsNull(VcnTransportInfo vcnTransportInfo) {
+ VcnTransportInfo redacted = (VcnTransportInfo) vcnTransportInfo.makeCopy(
+ NetworkCapabilities.REDACT_FOR_NETWORK_SETTINGS);
+
+ Parcel parcel = Parcel.obtain();
+ redacted.writeToParcel(parcel, 0 /* flags */);
+ parcel.setDataPosition(0);
- final long wifiRedactions = WIFI_INFO.getApplicableRedactions();
- assertEquals(wifiRedactions, WIFI_UNDERLYING_INFO.getApplicableRedactions());
+ assertNull(VcnTransportInfo.CREATOR.createFromParcel(parcel));
}
@Test