summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Ravenwood.bp9
-rw-r--r--apex/jobscheduler/service/java/com/android/server/AppStateTrackerImpl.java7
-rw-r--r--apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java8
-rw-r--r--cmds/screencap/screencap.cpp15
-rw-r--r--core/api/current.txt44
-rw-r--r--core/api/lint-baseline.txt36
-rw-r--r--core/api/system-current.txt1
-rw-r--r--core/api/test-lint-baseline.txt4
-rw-r--r--core/java/android/app/AppOpsManager.java36
-rw-r--r--core/java/android/app/AppOpsManagerInternal.java51
-rw-r--r--core/java/android/content/AttributionSource.java6
-rw-r--r--core/java/android/hardware/usb/flags/system_sw_usb_flags.aconfig7
-rw-r--r--core/java/android/net/NetworkStack.java13
-rw-r--r--core/java/android/os/Binder.java14
-rw-r--r--core/java/android/os/Parcel.java16
-rw-r--r--core/java/com/android/internal/app/IAppOpsService.aidl39
-rw-r--r--core/jni/Android.bp3
-rw-r--r--core/jni/android_content_res_ResourceTimer.cpp6
-rw-r--r--core/jni/android_hardware_camera2_DngCreator.cpp4
-rw-r--r--core/jni/android_hardware_camera2_impl_CameraExtensionJpegProcessor.cpp2
-rw-r--r--core/jni/android_media_AudioProductStrategies.cpp4
-rw-r--r--core/jni/android_media_AudioSystem.cpp6
-rw-r--r--core/jni/android_net_LocalSocketImpl.cpp2
-rw-r--r--core/jni/android_os_HwBlob.cpp2
-rw-r--r--core/jni/android_os_Parcel.cpp2
-rw-r--r--core/jni/android_os_PerformanceHintManager.cpp2
-rw-r--r--core/jni/android_util_CharsetUtils.cpp4
-rw-r--r--core/jni/android_util_FileObserver.cpp2
-rw-r--r--core/jni/android_view_DisplayEventReceiver.cpp4
-rw-r--r--core/jni/android_view_SurfaceControl.cpp2
-rw-r--r--core/jni/android_window_WindowInfosListener.cpp4
-rw-r--r--core/jni/com_android_internal_content_om_OverlayManagerImpl.cpp4
-rw-r--r--core/jni/com_android_internal_os_KernelCpuUidBpfMapReader.cpp2
-rw-r--r--core/jni/com_android_internal_os_KernelSingleProcessCpuThreadReader.cpp6
-rw-r--r--core/jni/com_android_internal_os_LongArrayMultiStateCounter.cpp2
-rw-r--r--core/jni/com_android_internal_os_Zygote.cpp10
-rw-r--r--core/jni/com_android_internal_os_ZygoteCommandBuffer.cpp38
-rw-r--r--framework-minus-apex-ravenwood-policies.txt26
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitionHandler.java7
-rw-r--r--libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp9
-rw-r--r--libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h5
-rw-r--r--libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp17
-rw-r--r--libs/hwui/pipeline/skia/SkiaVulkanPipeline.h5
-rw-r--r--libs/hwui/renderthread/CanvasContext.cpp4
-rw-r--r--libs/hwui/renderthread/IRenderPipeline.h6
-rw-r--r--libs/hwui/renderthread/VulkanManager.cpp80
-rw-r--r--libs/hwui/renderthread/VulkanManager.h17
-rw-r--r--media/java/android/media/audiopolicy/AudioVolumeGroup.java3
-rw-r--r--media/jni/android_media_MediaMetricsJNI.cpp2
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/Utils.java24
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/LeAudioProfile.java22
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java40
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java8
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt53
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt31
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/data/repository/EmergencyServicesRepositoryImplTest.kt81
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/domain/interactor/BouncerActionButtonInteractorTest.kt223
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/telephony/data/repository/TelephonyRepositoryImplTest.kt (renamed from packages/SystemUI/tests/src/com/android/systemui/telephony/data/repository/TelephonyRepositoryImplTest.kt)56
-rw-r--r--packages/SystemUI/res/values/strings.xml5
-rw-r--r--packages/SystemUI/src/com/android/keyguard/EmergencyButtonController.java43
-rw-r--r--packages/SystemUI/src/com/android/systemui/bouncer/data/repository/EmergencyServicesRepository.kt57
-rw-r--r--packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerActionButtonInteractor.kt181
-rw-r--r--packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractorModule.kt50
-rw-r--r--packages/SystemUI/src/com/android/systemui/bouncer/shared/model/BouncerActionButtonModel.kt32
-rw-r--r--packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModel.kt26
-rw-r--r--packages/SystemUI/src/com/android/systemui/common/ui/data/repository/ConfigurationRepository.kt10
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/dagger/CommunalModule.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalMediaRepository.kt73
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalMediaRepositoryModule.kt25
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt16
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/domain/model/CommunalContentModel.kt11
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/complication/SmartSpaceComplication.java24
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/display/domain/interactor/ConnectedDisplayInteractor.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStateController.java53
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/view/KeyboardBacklightDialog.kt29
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/data/repository/BiometricSettingsRepository.kt16
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/ui/KeyguardMediaController.kt58
-rw-r--r--packages/SystemUI/src/com/android/systemui/mediaprojection/permission/BaseMediaProjectionPermissionDialogDelegate.kt (renamed from packages/SystemUI/src/com/android/systemui/mediaprojection/permission/BaseScreenSharePermissionDialog.kt)54
-rw-r--r--packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java44
-rw-r--r--packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionDialogDelegate.kt (renamed from packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionDialog.kt)19
-rw-r--r--packages/SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanelController.kt41
-rw-r--r--packages/SystemUI/src/com/android/systemui/power/data/repository/PowerRepository.kt33
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java23
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialogDelegate.kt (renamed from packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialog.kt)36
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconContainerViewBinder.kt84
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionsRepository.kt11
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcher.kt1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepository.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/telephony/data/repository/TelephonyRepository.kt40
-rw-r--r--packages/SystemUI/src/com/android/systemui/telephony/domain/interactor/TelephonyInteractor.kt9
-rw-r--r--packages/SystemUI/src/com/android/systemui/user/domain/interactor/SelectedUserInteractor.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/reference/ReferenceModule.kt26
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/reference/WeakReferenceFactory.kt30
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/EmergencyButtonControllerTest.kt5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/bouncer/data/repository/KeyguardBouncerRepositoryTest.kt26
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModelTest.kt2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/KeyguardBouncerViewModelTest.kt7
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModelTest.kt2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModelTest.kt1
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt1
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/communal/data/repository/CommunalMediaRepositoryImplTest.kt132
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt63
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/complication/ComplicationCollectionLiveDataTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/display/domain/interactor/ConnectedDisplayInteractorTest.kt3
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStateControllerTest.java29
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyboard/backlight/ui/view/KeyboardBacklightDialogTest.kt84
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/BiometricSettingsRepositoryTest.kt50
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/KeyguardMediaControllerTest.kt5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/navigationbar/gestural/BackPanelControllerTest.kt63
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/power/data/repository/PowerRepositoryImplTest.kt16
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt113
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingControllerTest.java80
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialogDelegateTest.kt (renamed from packages/SystemUI/tests/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialogTest.kt)59
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionsRepository.kt1
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt14
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BatteryControllerTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserSwitcherInteractorTest.kt55
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/common/ui/data/repository/FakeConfigurationRepository.kt10
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/FakeCommunalMediaRepository.kt23
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalInteractorFactory.kt5
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/power/data/repository/FakePowerRepository.kt12
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt73
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/telephony/data/repository/FakeTelephonyRepository.kt12
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/util/reference/FakeWeakReferenceFactory.kt37
-rw-r--r--ravenwood/Android.bp11
-rw-r--r--ravenwood/junit-src/android/platform/test/annotations/IgnoreUnderRavenwood.java33
-rw-r--r--ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java50
-rw-r--r--services/autofill/bugfixes.aconfig7
-rw-r--r--services/core/java/com/android/server/StorageManagerService.java24
-rw-r--r--services/core/java/com/android/server/TEST_MAPPING6
-rw-r--r--services/core/java/com/android/server/am/ActiveServices.java60
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java83
-rw-r--r--services/core/java/com/android/server/am/AppPermissionTracker.java13
-rw-r--r--services/core/java/com/android/server/appop/AppOpsService.java271
-rw-r--r--services/core/java/com/android/server/pdb/PersistentDataBlockService.java101
-rw-r--r--services/core/java/com/android/server/pm/ApexManager.java6
-rw-r--r--services/core/java/com/android/server/pm/AppsFilterBase.java2
-rw-r--r--services/core/java/com/android/server/pm/BackgroundDexOptService.java4
-rw-r--r--services/core/java/com/android/server/pm/CrossProfileAppsService.java2
-rw-r--r--services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java6
-rw-r--r--services/core/java/com/android/server/pm/CrossProfileDomainInfo.java5
-rw-r--r--services/core/java/com/android/server/pm/CrossProfileIntentFilterHelper.java10
-rw-r--r--services/core/java/com/android/server/pm/CrossProfileResolver.java4
-rw-r--r--services/core/java/com/android/server/pm/DataLoaderManagerService.java3
-rw-r--r--services/core/java/com/android/server/pm/DefaultCrossProfileIntentFilter.java8
-rw-r--r--services/core/java/com/android/server/pm/InstallArgs.java3
-rw-r--r--services/core/java/com/android/server/pm/InstallRequest.java2
-rw-r--r--services/core/java/com/android/server/pm/InstallingSession.java2
-rw-r--r--services/core/java/com/android/server/pm/LauncherAppsService.java7
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerService.java3
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerSession.java6
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerServiceTestParams.java4
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerShellCommand.java4
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerShellCommandDataLoader.java3
-rw-r--r--services/core/java/com/android/server/pm/PreferredComponent.java2
-rw-r--r--services/core/java/com/android/server/pm/SELinuxMMAC.java4
-rw-r--r--services/core/java/com/android/server/pm/Settings.java8
-rw-r--r--services/core/java/com/android/server/pm/ShortcutPackageItem.java2
-rw-r--r--services/core/java/com/android/server/pm/ShortcutService.java30
-rw-r--r--services/core/java/com/android/server/pm/SnapshotStatistics.java14
-rw-r--r--services/core/java/com/android/server/pm/UserJourneyLogger.java2
-rw-r--r--services/core/java/com/android/server/pm/dex/DexManager.java12
-rw-r--r--services/core/java/com/android/server/pm/parsing/PackageCacher.java2
-rw-r--r--services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java2
-rw-r--r--services/core/java/com/android/server/pm/parsing/PackageParser2.java6
-rw-r--r--services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java22
-rw-r--r--services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java8
-rw-r--r--services/core/java/com/android/server/pm/pkg/component/ParsedPermissionImpl.java3
-rw-r--r--services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java8
-rw-r--r--services/core/java/com/android/server/pm/resolution/ComponentResolver.java2
-rw-r--r--services/core/java/com/android/server/pm/resolution/ComponentResolverBase.java2
-rw-r--r--services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java4
-rw-r--r--services/core/java/com/android/server/pm/verify/domain/models/DomainVerificationPkgState.java2
-rw-r--r--services/core/java/com/android/server/policy/AppOpsPolicy.java72
-rw-r--r--services/core/java/com/android/server/power/stats/CpuPowerStatsCollector.java4
-rw-r--r--services/core/java/com/android/server/wm/Transition.java12
-rw-r--r--services/core/jni/tvinput/JTvInputHal.cpp22
-rw-r--r--services/core/jni/tvinput/JTvInputHal.h26
-rw-r--r--services/core/jni/tvinput/TvInputHal_hidl.cpp11
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/AppStateTrackerTest.java21
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/am/ActivityManagerServiceTest.java19
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/am/BackgroundRestrictionTest.java7
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java63
-rw-r--r--services/tests/servicestests/src/com/android/server/pdb/PersistentDataBlockServiceTest.java552
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/SuspendPackagesTest.java9
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RefreshRatePolicyTest.java10
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TransitionTests.java1
-rw-r--r--test-mock/api/current.txt2
-rw-r--r--tools/hoststubgen/TEST_MAPPING4
-rw-r--r--tools/hoststubgen/hoststubgen/Android.bp12
-rw-r--r--tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/Parcel_host.java27
-rw-r--r--tools/hoststubgen/hoststubgen/invoketest/Android.bp20
-rwxr-xr-xtools/hoststubgen/hoststubgen/invoketest/hoststubgen-invoke-test.sh163
-rw-r--r--tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt12
-rw-r--r--tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenOptions.kt6
-rw-r--r--tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/Utils.kt27
-rw-r--r--tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/asm/AsmUtils.kt92
-rw-r--r--tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/AnnotationBasedFilter.kt28
-rw-r--r--tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/ImplicitOutputFilter.kt79
-rw-r--r--tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/TextFileFilterPolicyParser.kt26
-rw-r--r--tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/utils/ClassFilter.kt141
-rw-r--r--tools/hoststubgen/hoststubgen/test-tiny-framework/Android.bp7
-rw-r--r--tools/hoststubgen/hoststubgen/test-tiny-framework/annotation-allowed-classes-tiny-framework.txt29
-rw-r--r--tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/01-hoststubgen-test-tiny-framework-orig-dump.txt308
-rw-r--r--tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/02-hoststubgen-test-tiny-framework-host-stub-dump.txt224
-rw-r--r--tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/03-hoststubgen-test-tiny-framework-host-impl-dump.txt318
-rw-r--r--tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/12-hoststubgen-test-tiny-framework-host-ext-stub-dump.txt224
-rw-r--r--tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/13-hoststubgen-test-tiny-framework-host-ext-impl-dump.txt384
-rwxr-xr-xtools/hoststubgen/hoststubgen/test-tiny-framework/run-test-manually.sh1
-rw-r--r--tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex.java51
-rw-r--r--tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple.java26
-rw-r--r--tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-test/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassTest.java39
-rw-r--r--tools/hoststubgen/hoststubgen/test/com/android/hoststubgen/utils/ClassFilterTest.kt87
-rwxr-xr-xtools/hoststubgen/scripts/run-all-tests.sh3
217 files changed, 5876 insertions, 1485 deletions
diff --git a/Ravenwood.bp b/Ravenwood.bp
index 1582266203c6..3310898ccfb5 100644
--- a/Ravenwood.bp
+++ b/Ravenwood.bp
@@ -77,10 +77,17 @@ android_ravenwood_libgroup {
"framework-minus-apex.ravenwood",
"hoststubgen-helper-runtime.ravenwood",
"hoststubgen-helper-framework-runtime.ravenwood",
+ "junit",
+ "truth",
+ "ravenwood-junit",
],
}
android_ravenwood_libgroup {
name: "ravenwood-utils",
- libs: [],
+ libs: [
+ "junit",
+ "truth",
+ "ravenwood-junit",
+ ],
}
diff --git a/apex/jobscheduler/service/java/com/android/server/AppStateTrackerImpl.java b/apex/jobscheduler/service/java/com/android/server/AppStateTrackerImpl.java
index 5fc77451e832..e08200b055d8 100644
--- a/apex/jobscheduler/service/java/com/android/server/AppStateTrackerImpl.java
+++ b/apex/jobscheduler/service/java/com/android/server/AppStateTrackerImpl.java
@@ -23,7 +23,6 @@ import android.app.AppOpsManager;
import android.app.AppOpsManager.PackageOps;
import android.app.IActivityManager;
import android.app.usage.UsageStatsManager;
-import android.content.AttributionSource;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -747,10 +746,8 @@ public class AppStateTrackerImpl implements AppStateTracker {
public void opChanged(int op, int uid, String packageName) throws RemoteException {
boolean restricted = false;
try {
- final AttributionSource attributionSource =
- new AttributionSource.Builder(uid).setPackageName(packageName).build();
- restricted = mAppOpsService.checkOperationWithState(TARGET_OP,
- attributionSource.asState()) != AppOpsManager.MODE_ALLOWED;
+ restricted = mAppOpsService.checkOperation(TARGET_OP,
+ uid, packageName) != AppOpsManager.MODE_ALLOWED;
} catch (RemoteException e) {
// Shouldn't happen
}
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java b/apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java
index 95f901c4a365..b8397d2cd1b4 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java
@@ -38,7 +38,6 @@ import android.app.tare.EconomyManager;
import android.app.tare.IEconomyManager;
import android.app.usage.UsageEvents;
import android.app.usage.UsageStatsManagerInternal;
-import android.content.AttributionSource;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
@@ -231,11 +230,8 @@ public class InternalResourceService extends SystemService {
public void opChanged(int op, int uid, String packageName) {
boolean restricted = false;
try {
- final AttributionSource attributionSource = new AttributionSource.Builder(uid)
- .setPackageName(packageName)
- .build();
- restricted = mAppOpsService.checkOperationWithState(
- AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, attributionSource.asState())
+ restricted = mAppOpsService.checkOperation(
+ AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, uid, packageName)
!= AppOpsManager.MODE_ALLOWED;
} catch (RemoteException e) {
// Shouldn't happen
diff --git a/cmds/screencap/screencap.cpp b/cmds/screencap/screencap.cpp
index ee9c464219d9..2d235331a672 100644
--- a/cmds/screencap/screencap.cpp
+++ b/cmds/screencap/screencap.cpp
@@ -142,13 +142,22 @@ int main(int argc, char** argv)
case 'p':
png = true;
break;
- case 'd':
- displayIdOpt = DisplayId::fromValue(atoll(optarg));
+ case 'd': {
+ errno = 0;
+ char* end = nullptr;
+ const uint64_t id = strtoull(optarg, &end, 10);
+ if (!end || *end != '\0' || errno == ERANGE) {
+ fprintf(stderr, "Invalid display ID: Out of range [0, 2^64).\n");
+ return 1;
+ }
+
+ displayIdOpt = DisplayId::fromValue(id);
if (!displayIdOpt) {
- fprintf(stderr, "Invalid display ID: %s\n", optarg);
+ fprintf(stderr, "Invalid display ID: Incorrect encoding.\n");
return 1;
}
break;
+ }
case '?':
case 'h':
if (ids.size() == 1) {
diff --git a/core/api/current.txt b/core/api/current.txt
index 14869dba9646..323f9e9cd7c6 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -4464,6 +4464,7 @@ package android.app {
method public boolean onPreparePanel(int, @Nullable android.view.View, @NonNull android.view.Menu);
method public void onProvideAssistContent(android.app.assist.AssistContent);
method public void onProvideAssistData(android.os.Bundle);
+ method public void onProvideKeyboardShortcuts(java.util.List<android.view.KeyboardShortcutGroup>, android.view.Menu, int);
method public android.net.Uri onProvideReferrer();
method public void onRequestPermissionsResult(int, @NonNull String[], @NonNull int[]);
method @FlaggedApi("android.permission.flags.device_aware_permission_apis") public void onRequestPermissionsResult(int, @NonNull String[], @NonNull int[], int);
@@ -13973,6 +13974,7 @@ package android.database {
method public String getColumnName(int);
method public android.os.Bundle getExtras();
method public android.net.Uri getNotificationUri();
+ method public java.util.List<android.net.Uri> getNotificationUris();
method public final int getPosition();
method public int getType(int);
method @Deprecated protected Object getUpdatedField(int);
@@ -13998,6 +14000,7 @@ package android.database {
method public android.os.Bundle respond(android.os.Bundle);
method public void setExtras(android.os.Bundle);
method public void setNotificationUri(android.content.ContentResolver, android.net.Uri);
+ method public void setNotificationUris(@NonNull android.content.ContentResolver, @NonNull java.util.List<android.net.Uri>);
method public void unregisterContentObserver(android.database.ContentObserver);
method public void unregisterDataSetObserver(android.database.DataSetObserver);
field @Deprecated protected boolean mClosed;
@@ -14129,6 +14132,7 @@ package android.database {
method public boolean hasNext();
method public java.util.Iterator<android.database.CursorJoiner.Result> iterator();
method public android.database.CursorJoiner.Result next();
+ method public void remove();
}
public enum CursorJoiner.Result {
@@ -14196,6 +14200,7 @@ package android.database {
method public int getInt(int);
method public long getLong(int);
method public android.net.Uri getNotificationUri();
+ method public java.util.List<android.net.Uri> getNotificationUris();
method public int getPosition();
method public short getShort(int);
method public String getString(int);
@@ -14220,6 +14225,7 @@ package android.database {
method public android.os.Bundle respond(android.os.Bundle);
method public void setExtras(android.os.Bundle);
method public void setNotificationUri(android.content.ContentResolver, android.net.Uri);
+ method public void setNotificationUris(android.content.ContentResolver, java.util.List<android.net.Uri>);
method public void unregisterContentObserver(android.database.ContentObserver);
method public void unregisterDataSetObserver(android.database.DataSetObserver);
}
@@ -22213,6 +22219,9 @@ package android.media {
ctor public MediaCodec.CryptoException(int, @Nullable String);
method @Nullable public android.media.MediaCodec.CryptoInfo getCryptoInfo();
method public int getErrorCode();
+ method public int getErrorContext();
+ method public int getOemError();
+ method public int getVendorError();
field @Deprecated public static final int ERROR_FRAME_TOO_LARGE = 8; // 0x8
field @Deprecated public static final int ERROR_INSUFFICIENT_OUTPUT_PROTECTION = 4; // 0x4
field @Deprecated public static final int ERROR_INSUFFICIENT_SECURITY = 7; // 0x7
@@ -22725,6 +22734,9 @@ package android.media {
public final class MediaCryptoException extends java.lang.Exception implements android.media.MediaDrmThrowable {
ctor public MediaCryptoException(@Nullable String);
+ method public int getErrorContext();
+ method public int getOemError();
+ method public int getVendorError();
}
public abstract class MediaDataSource implements java.io.Closeable {
@@ -22949,6 +22961,9 @@ package android.media {
public static final class MediaDrm.MediaDrmStateException extends java.lang.IllegalStateException implements android.media.MediaDrmThrowable {
method @NonNull public String getDiagnosticInfo();
method public int getErrorCode();
+ method public int getErrorContext();
+ method public int getOemError();
+ method public int getVendorError();
method public boolean isTransient();
}
@@ -23022,6 +23037,9 @@ package android.media {
public static final class MediaDrm.SessionException extends java.lang.RuntimeException implements android.media.MediaDrmThrowable {
ctor public MediaDrm.SessionException(int, @Nullable String);
method @Deprecated public int getErrorCode();
+ method public int getErrorContext();
+ method public int getOemError();
+ method public int getVendorError();
method public boolean isTransient();
field @Deprecated public static final int ERROR_RESOURCE_CONTENTION = 1; // 0x1
field @Deprecated public static final int ERROR_UNKNOWN = 0; // 0x0
@@ -23029,6 +23047,9 @@ package android.media {
public class MediaDrmException extends java.lang.Exception implements android.media.MediaDrmThrowable {
ctor public MediaDrmException(String);
+ method public int getErrorContext();
+ method public int getOemError();
+ method public int getVendorError();
}
public class MediaDrmResetException extends java.lang.IllegalStateException implements android.media.MediaDrmThrowable {
@@ -31918,6 +31939,7 @@ package android.opengl {
method public void surfaceCreated(android.view.SurfaceHolder);
method public void surfaceDestroyed(android.view.SurfaceHolder);
method @Deprecated public void surfaceRedrawNeeded(android.view.SurfaceHolder);
+ method public void surfaceRedrawNeededAsync(android.view.SurfaceHolder, Runnable);
field public static final int DEBUG_CHECK_GL_ERROR = 1; // 0x1
field public static final int DEBUG_LOG_GL_CALLS = 2; // 0x2
field public static final int RENDERMODE_CONTINUOUSLY = 1; // 0x1
@@ -47459,6 +47481,7 @@ package android.text {
method public boolean hasNext();
method public java.util.Iterator<java.lang.String> iterator();
method public String next();
+ method public void remove();
method public void setString(String);
}
@@ -48924,6 +48947,7 @@ package android.util {
method public void ensureCapacity(int);
method public java.util.Set<java.util.Map.Entry<K,V>> entrySet();
method public boolean equals(@Nullable Object);
+ method public void forEach(java.util.function.BiConsumer<? super K,? super V>);
method public V get(Object);
method public int hashCode();
method public int indexOfKey(Object);
@@ -48937,6 +48961,7 @@ package android.util {
method public V remove(Object);
method public boolean removeAll(java.util.Collection<?>);
method public V removeAt(int);
+ method public void replaceAll(java.util.function.BiFunction<? super K,? super V,? extends V>);
method public boolean retainAll(java.util.Collection<?>);
method public V setValueAt(int, V);
method public int size();
@@ -48967,6 +48992,7 @@ package android.util {
method public boolean removeAll(android.util.ArraySet<? extends E>);
method public boolean removeAll(java.util.Collection<?>);
method public E removeAt(int);
+ method public boolean removeIf(java.util.function.Predicate<? super E>);
method public boolean retainAll(java.util.Collection<?>);
method public int size();
method public Object[] toArray();
@@ -52834,6 +52860,7 @@ package android.view {
method protected void dispatchThawSelfOnly(android.util.SparseArray<android.os.Parcelable>);
method protected boolean drawChild(@NonNull android.graphics.Canvas, android.view.View, long);
method public void endViewTransition(android.view.View);
+ method @Nullable public android.window.OnBackInvokedDispatcher findOnBackInvokedDispatcherForChild(@NonNull android.view.View, @NonNull android.view.View);
method public android.view.View focusSearch(android.view.View, int);
method public void focusableViewAvailable(android.view.View);
method protected android.view.ViewGroup.LayoutParams generateDefaultLayoutParams();
@@ -52875,6 +52902,7 @@ package android.view {
method public void notifySubtreeAccessibilityStateChanged(android.view.View, android.view.View, int);
method public final void offsetDescendantRectToMyCoords(android.view.View, android.graphics.Rect);
method public final void offsetRectIntoDescendantCoords(android.view.View, android.graphics.Rect);
+ method @CallSuper public void onDescendantInvalidated(@NonNull android.view.View, @NonNull android.view.View);
method public boolean onInterceptHoverEvent(android.view.MotionEvent);
method public boolean onInterceptTouchEvent(android.view.MotionEvent);
method protected abstract void onLayout(boolean, int, int, int, int);
@@ -55058,12 +55086,14 @@ package android.view.inputmethod {
method @Nullable public android.view.inputmethod.ExtractedText getExtractedText(android.view.inputmethod.ExtractedTextRequest, int);
method @Nullable public android.os.Handler getHandler();
method @Nullable public CharSequence getSelectedText(int);
+ method @Nullable public android.view.inputmethod.SurroundingText getSurroundingText(@IntRange(from=0) int, @IntRange(from=0) int, int);
method @Nullable public CharSequence getTextAfterCursor(@IntRange(from=0) int, int);
method @Nullable public CharSequence getTextBeforeCursor(@IntRange(from=0) int, int);
method public boolean performContextMenuAction(int);
method public boolean performEditorAction(int);
method public boolean performPrivateCommand(String, android.os.Bundle);
method public static final void removeComposingSpans(@NonNull android.text.Spannable);
+ method public boolean replaceText(@IntRange(from=0) int, @IntRange(from=0) int, @NonNull CharSequence, int, @Nullable android.view.inputmethod.TextAttribute);
method public boolean reportFullscreenMode(boolean);
method public boolean requestCursorUpdates(int);
method public boolean sendKeyEvent(android.view.KeyEvent);
@@ -55071,6 +55101,7 @@ package android.view.inputmethod {
method public static void setComposingSpans(@NonNull android.text.Spannable);
method public boolean setComposingText(CharSequence, int);
method public boolean setSelection(int, int);
+ method @Nullable public android.view.inputmethod.TextSnapshot takeSnapshot();
}
public final class CompletionInfo implements android.os.Parcelable {
@@ -55407,6 +55438,7 @@ package android.view.inputmethod {
method public boolean commitContent(android.view.inputmethod.InputContentInfo, int, android.os.Bundle);
method public boolean commitCorrection(android.view.inputmethod.CorrectionInfo);
method public boolean commitText(CharSequence, int);
+ method public boolean commitText(@NonNull CharSequence, int, @Nullable android.view.inputmethod.TextAttribute);
method public boolean deleteSurroundingText(int, int);
method public boolean deleteSurroundingTextInCodePoints(int, int);
method public boolean endBatchEdit();
@@ -55415,18 +55447,29 @@ package android.view.inputmethod {
method public android.view.inputmethod.ExtractedText getExtractedText(android.view.inputmethod.ExtractedTextRequest, int);
method public android.os.Handler getHandler();
method public CharSequence getSelectedText(int);
+ method @Nullable public android.view.inputmethod.SurroundingText getSurroundingText(int, int, int);
method @Nullable public CharSequence getTextAfterCursor(@IntRange(from=0) int, int);
method @Nullable public CharSequence getTextBeforeCursor(@IntRange(from=0) int, int);
method public boolean performContextMenuAction(int);
method public boolean performEditorAction(int);
+ method public void performHandwritingGesture(@NonNull android.view.inputmethod.HandwritingGesture, @Nullable java.util.concurrent.Executor, @Nullable java.util.function.IntConsumer);
method public boolean performPrivateCommand(String, android.os.Bundle);
+ method public boolean performSpellCheck();
+ method public boolean previewHandwritingGesture(@NonNull android.view.inputmethod.PreviewableHandwritingGesture, @Nullable android.os.CancellationSignal);
+ method public boolean replaceText(@IntRange(from=0) int, @IntRange(from=0) int, @NonNull CharSequence, int, @Nullable android.view.inputmethod.TextAttribute);
method public boolean reportFullscreenMode(boolean);
method public boolean requestCursorUpdates(int);
+ method public boolean requestCursorUpdates(int, int);
+ method public void requestTextBoundsInfo(@NonNull android.graphics.RectF, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.view.inputmethod.TextBoundsInfoResult>);
method public boolean sendKeyEvent(android.view.KeyEvent);
method public boolean setComposingRegion(int, int);
+ method public boolean setComposingRegion(int, int, @Nullable android.view.inputmethod.TextAttribute);
method public boolean setComposingText(CharSequence, int);
+ method public boolean setComposingText(@NonNull CharSequence, int, @Nullable android.view.inputmethod.TextAttribute);
+ method public boolean setImeConsumesInput(boolean);
method public boolean setSelection(int, int);
method public void setTarget(android.view.inputmethod.InputConnection);
+ method @Nullable public android.view.inputmethod.TextSnapshot takeSnapshot();
}
public final class InputContentInfo implements android.os.Parcelable {
@@ -57993,6 +58036,7 @@ package android.widget {
public abstract class BaseAdapter implements android.widget.ListAdapter android.widget.SpinnerAdapter {
ctor public BaseAdapter();
method public boolean areAllItemsEnabled();
+ method public CharSequence[] getAutofillOptions();
method public android.view.View getDropDownView(int, android.view.View, android.view.ViewGroup);
method public int getItemViewType(int);
method public int getViewTypeCount();
diff --git a/core/api/lint-baseline.txt b/core/api/lint-baseline.txt
index 1e6aa498f417..483d2a4d26b2 100644
--- a/core/api/lint-baseline.txt
+++ b/core/api/lint-baseline.txt
@@ -1,4 +1,40 @@
// Baseline format: 1.0
+BannedThrow: android.database.sqlite.SQLiteRawStatement#bindBlob(int, byte[]):
+ Methods must not throw unchecked exceptions
+BannedThrow: android.database.sqlite.SQLiteRawStatement#bindBlob(int, byte[], int, int):
+ Methods must not throw unchecked exceptions
+BannedThrow: android.database.sqlite.SQLiteRawStatement#bindDouble(int, double):
+ Methods must not throw unchecked exceptions
+BannedThrow: android.database.sqlite.SQLiteRawStatement#bindInt(int, int):
+ Methods must not throw unchecked exceptions
+BannedThrow: android.database.sqlite.SQLiteRawStatement#bindLong(int, long):
+ Methods must not throw unchecked exceptions
+BannedThrow: android.database.sqlite.SQLiteRawStatement#bindNull(int):
+ Methods must not throw unchecked exceptions
+BannedThrow: android.database.sqlite.SQLiteRawStatement#bindText(int, String):
+ Methods must not throw unchecked exceptions
+BannedThrow: android.database.sqlite.SQLiteRawStatement#getColumnBlob(int):
+ Methods must not throw unchecked exceptions
+BannedThrow: android.database.sqlite.SQLiteRawStatement#getColumnDouble(int):
+ Methods must not throw unchecked exceptions
+BannedThrow: android.database.sqlite.SQLiteRawStatement#getColumnInt(int):
+ Methods must not throw unchecked exceptions
+BannedThrow: android.database.sqlite.SQLiteRawStatement#getColumnLength(int):
+ Methods must not throw unchecked exceptions
+BannedThrow: android.database.sqlite.SQLiteRawStatement#getColumnLong(int):
+ Methods must not throw unchecked exceptions
+BannedThrow: android.database.sqlite.SQLiteRawStatement#getColumnName(int):
+ Methods must not throw unchecked exceptions
+BannedThrow: android.database.sqlite.SQLiteRawStatement#getColumnText(int):
+ Methods must not throw unchecked exceptions
+BannedThrow: android.database.sqlite.SQLiteRawStatement#getColumnType(int):
+ Methods must not throw unchecked exceptions
+BannedThrow: android.database.sqlite.SQLiteRawStatement#readColumnBlob(int, byte[], int, int, int):
+ Methods must not throw unchecked exceptions
+BannedThrow: android.database.sqlite.SQLiteRawStatement#step():
+ Methods must not throw unchecked exceptions
+
+
BroadcastBehavior: android.app.AlarmManager#ACTION_NEXT_ALARM_CLOCK_CHANGED:
Field 'ACTION_NEXT_ALARM_CLOCK_CHANGED' is missing @BroadcastBehavior
BroadcastBehavior: android.app.AlarmManager#ACTION_SCHEDULE_EXACT_ALARM_PERMISSION_STATE_CHANGED:
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index b5e940734b1e..eefa36eb4f2d 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -10228,6 +10228,7 @@ package android.os {
ctor public ParcelableHolder(int);
method public int describeContents();
method @Nullable public <T extends android.os.Parcelable> T getParcelable(@NonNull Class<T>);
+ method public int getStability();
method public void readFromParcel(@NonNull android.os.Parcel);
method public void setParcelable(@Nullable android.os.Parcelable);
method public void writeToParcel(@NonNull android.os.Parcel, int);
diff --git a/core/api/test-lint-baseline.txt b/core/api/test-lint-baseline.txt
index 559db514dabf..3a91e25de9e6 100644
--- a/core/api/test-lint-baseline.txt
+++ b/core/api/test-lint-baseline.txt
@@ -1,4 +1,8 @@
// Baseline format: 1.0
+BannedThrow: android.os.vibrator.persistence.VibrationXmlSerializer#serialize(android.os.VibrationEffect, java.io.Writer):
+ Methods must not throw unchecked exceptions
+
+
BroadcastBehavior: android.app.AlarmManager#ACTION_NEXT_ALARM_CLOCK_CHANGED:
Field 'ACTION_NEXT_ALARM_CLOCK_CHANGED' is missing @BroadcastBehavior
BroadcastBehavior: android.app.AlarmManager#ACTION_SCHEDULE_EXACT_ALARM_PERMISSION_STATE_CHANGED:
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index a99dfa605407..3d5444997107 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -8357,9 +8357,7 @@ public class AppOpsManager {
*/
public int unsafeCheckOpRawNoThrow(int op, int uid, @NonNull String packageName) {
try {
- final AttributionSource attributionSource =
- new AttributionSource.Builder(uid).setPackageName(packageName).build();
- return mService.checkOperationWithStateRaw(op, attributionSource.asState());
+ return mService.checkOperationRaw(op, uid, packageName, null);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -8522,12 +8520,7 @@ public class AppOpsManager {
}
}
- final AttributionSource attributionSource =
- new AttributionSource.Builder(uid)
- .setPackageName(packageName)
- .setAttributionTag(attributionTag)
- .build();
- SyncNotedAppOp syncOp = mService.noteOperationWithState(op, attributionSource.asState(),
+ SyncNotedAppOp syncOp = mService.noteOperation(op, uid, packageName, attributionTag,
collectionMode == COLLECT_ASYNC, message, shouldCollectMessage);
if (syncOp.getOpMode() == MODE_ALLOWED) {
@@ -8767,9 +8760,7 @@ public class AppOpsManager {
@UnsupportedAppUsage
public int checkOp(int op, int uid, String packageName) {
try {
- final AttributionSource attributionSource =
- new AttributionSource.Builder(uid).setPackageName(packageName).build();
- int mode = mService.checkOperationWithState(op, attributionSource.asState());
+ int mode = mService.checkOperation(op, uid, packageName);
if (mode == MODE_ERRORED) {
throw new SecurityException(buildSecurityExceptionMsg(op, uid, packageName));
}
@@ -8790,9 +8781,7 @@ public class AppOpsManager {
@UnsupportedAppUsage
public int checkOpNoThrow(int op, int uid, String packageName) {
try {
- final AttributionSource attributionSource =
- new AttributionSource.Builder(uid).setPackageName(packageName).build();
- int mode = mService.checkOperationWithState(op, attributionSource.asState());
+ int mode = mService.checkOperation(op, uid, packageName);
return mode == AppOpsManager.MODE_FOREGROUND ? AppOpsManager.MODE_ALLOWED : mode;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -9037,14 +9026,8 @@ public class AppOpsManager {
}
}
- final AttributionSource attributionSource =
- new AttributionSource.Builder(uid)
- .setPackageName(packageName)
- .setAttributionTag(attributionTag)
- .build();
- SyncNotedAppOp syncOp = mService.startOperationWithState(token, op,
- attributionSource.asState(), startIfModeDefault,
- collectionMode == COLLECT_ASYNC, message,
+ SyncNotedAppOp syncOp = mService.startOperation(token, op, uid, packageName,
+ attributionTag, startIfModeDefault, collectionMode == COLLECT_ASYNC, message,
shouldCollectMessage, attributionFlags, attributionChainId);
if (syncOp.getOpMode() == MODE_ALLOWED) {
@@ -9257,12 +9240,7 @@ public class AppOpsManager {
public void finishOp(IBinder token, int op, int uid, @NonNull String packageName,
@Nullable String attributionTag) {
try {
- final AttributionSource attributionSource =
- new AttributionSource.Builder(uid)
- .setPackageName(packageName)
- .setAttributionTag(attributionTag)
- .build();
- mService.finishOperationWithState(token, op, attributionSource.asState());
+ mService.finishOperation(token, op, uid, packageName, attributionTag);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/app/AppOpsManagerInternal.java b/core/java/android/app/AppOpsManagerInternal.java
index a3de8faa1273..43023fe9c2ab 100644
--- a/core/java/android/app/AppOpsManagerInternal.java
+++ b/core/java/android/app/AppOpsManagerInternal.java
@@ -26,12 +26,11 @@ import android.util.SparseArray;
import android.util.SparseIntArray;
import com.android.internal.app.IAppOpsCallback;
+import com.android.internal.util.function.HeptFunction;
import com.android.internal.util.function.HexFunction;
-import com.android.internal.util.function.NonaFunction;
import com.android.internal.util.function.QuadFunction;
+import com.android.internal.util.function.QuintConsumer;
import com.android.internal.util.function.QuintFunction;
-import com.android.internal.util.function.TriConsumer;
-import com.android.internal.util.function.TriFunction;
import com.android.internal.util.function.UndecFunction;
/**
@@ -46,13 +45,15 @@ public abstract class AppOpsManagerInternal {
* Allows overriding check operation behavior.
*
* @param code The op code to check.
- * @param attributionSource the {@link AttributionSource} responsible for data access
+ * @param uid The UID for which to check.
+ * @param packageName The package for which to check.
+ * @param attributionTag The attribution tag for which to check.
* @param raw Whether to check the raw op i.e. not interpret the mode based on UID state.
* @param superImpl The super implementation.
* @return The app op check result.
*/
- int checkOperation(int code, AttributionSource attributionSource,
- boolean raw, TriFunction<Integer, AttributionSource, Boolean, Integer>
+ int checkOperation(int code, int uid, String packageName, @Nullable String attributionTag,
+ boolean raw, QuintFunction<Integer, Integer, String, String, Boolean, Integer>
superImpl);
/**
@@ -72,23 +73,25 @@ public abstract class AppOpsManagerInternal {
* Allows overriding note operation behavior.
*
* @param code The op code to note.
- * @param attributionSource the {@link AttributionSource} responsible for data access
+ * @param uid The UID for which to note.
+ * @param packageName The package for which to note. {@code null} for system package.
+ * @param featureId Id of the feature in the package
* @param shouldCollectAsyncNotedOp If an {@link AsyncNotedAppOp} should be collected
* @param message The message in the async noted op
* @param superImpl The super implementation.
* @return The app op note result.
*/
- SyncNotedAppOp noteOperation(int code, AttributionSource attributionSource,
- boolean shouldCollectAsyncNotedOp,
+ SyncNotedAppOp noteOperation(int code, int uid, @Nullable String packageName,
+ @Nullable String featureId, boolean shouldCollectAsyncNotedOp,
@Nullable String message, boolean shouldCollectMessage,
- @NonNull QuintFunction<Integer, AttributionSource, Boolean, String, Boolean,
+ @NonNull HeptFunction<Integer, Integer, String, String, Boolean, String, Boolean,
SyncNotedAppOp> superImpl);
/**
* Allows overriding note proxy operation behavior.
*
* @param code The op code to note.
- * @param attributionSource the {@link AttributionSource} responsible for data access
+ * @param attributionSource The permission identity of the caller.
* @param shouldCollectAsyncNotedOp If an {@link AsyncNotedAppOp} should be collected
* @param message The message in the async noted op
* @param shouldCollectMessage whether to collect messages
@@ -107,7 +110,9 @@ public abstract class AppOpsManagerInternal {
*
* @param token The client state.
* @param code The op code to start.
- * @param attributionSource the {@link AttributionSource} responsible for data access
+ * @param uid The UID for which to note.
+ * @param packageName The package for which to note. {@code null} for system package.
+ * @param attributionTag the attribution tag.
* @param startIfModeDefault Whether to start the op of the mode is default.
* @param shouldCollectAsyncNotedOp If an {@link AsyncNotedAppOp} should be collected
* @param message The message in the async noted op
@@ -117,12 +122,12 @@ public abstract class AppOpsManagerInternal {
* @param superImpl The super implementation.
* @return The app op note result.
*/
- SyncNotedAppOp startOperation(IBinder token, int code,
- AttributionSource attributionSource,
+ SyncNotedAppOp startOperation(IBinder token, int code, int uid,
+ @Nullable String packageName, @Nullable String attributionTag,
boolean startIfModeDefault, boolean shouldCollectAsyncNotedOp,
@Nullable String message, boolean shouldCollectMessage,
@AttributionFlags int attributionFlags, int attributionChainId,
- @NonNull NonaFunction<IBinder, Integer, AttributionSource, Boolean,
+ @NonNull UndecFunction<IBinder, Integer, Integer, String, String, Boolean,
Boolean, String, Boolean, Integer, Integer, SyncNotedAppOp> superImpl);
/**
@@ -130,7 +135,7 @@ public abstract class AppOpsManagerInternal {
*
* @param clientId The client calling start, represented by an IBinder
* @param code The op code to start.
- * @param attributionSource the {@link AttributionSource} responsible for data access
+ * @param attributionSource The permission identity of the caller.
* @param startIfModeDefault Whether to start the op of the mode is default.
* @param shouldCollectAsyncNotedOp If an {@link AsyncNotedAppOp} should be collected
* @param message The message in the async noted op
@@ -156,19 +161,21 @@ public abstract class AppOpsManagerInternal {
*
* @param clientId The client state.
* @param code The op code to finish.
- * @param attributionSource the {@link AttributionSource} responsible for data access
+ * @param uid The UID for which the op was noted.
+ * @param packageName The package for which it was noted. {@code null} for system package.
+ * @param attributionTag the attribution tag.
*/
- default void finishOperation(IBinder clientId, int code,
- AttributionSource attributionSource,
- @NonNull TriConsumer<IBinder, Integer, AttributionSource> superImpl) {
- superImpl.accept(clientId, code, attributionSource);
+ default void finishOperation(IBinder clientId, int code, int uid, String packageName,
+ String attributionTag,
+ @NonNull QuintConsumer<IBinder, Integer, Integer, String, String> superImpl) {
+ superImpl.accept(clientId, code, uid, packageName, attributionTag);
}
/**
* Allows overriding finish proxy op.
*
* @param code The op code to finish.
- * @param attributionSource the {@link AttributionSource} responsible for data access
+ * @param attributionSource The permission identity of the caller.
* @param skipProxyOperation Whether to skip the proxy in the proxy/proxied operation
* @param clientId The client calling finishProxyOperation
* @param superImpl The "standard" implementation to potentially call
diff --git a/core/java/android/content/AttributionSource.java b/core/java/android/content/AttributionSource.java
index c2bc974a42ae..4b2cee698df2 100644
--- a/core/java/android/content/AttributionSource.java
+++ b/core/java/android/content/AttributionSource.java
@@ -235,12 +235,6 @@ public final class AttributionSource implements Parcelable {
}
/** @hide */
- public AttributionSource withUid(int uid) {
- return new AttributionSource(uid, getPid(), getPackageName(), getAttributionTag(),
- getToken(), mAttributionSourceState.renouncedPermissions, getDeviceId(), getNext());
- }
-
- /** @hide */
public AttributionSource withPid(int pid) {
return new AttributionSource(getUid(), pid, getPackageName(), getAttributionTag(),
getToken(), mAttributionSourceState.renouncedPermissions, getDeviceId(), getNext());
diff --git a/core/java/android/hardware/usb/flags/system_sw_usb_flags.aconfig b/core/java/android/hardware/usb/flags/system_sw_usb_flags.aconfig
index 6b78d05c848d..5c5083a691be 100644
--- a/core/java/android/hardware/usb/flags/system_sw_usb_flags.aconfig
+++ b/core/java/android/hardware/usb/flags/system_sw_usb_flags.aconfig
@@ -6,3 +6,10 @@ flag {
description: "Enable USB data compliance warnings when set"
bug: "296119135"
}
+
+flag {
+ name: "enable_input_power_limited_warning"
+ namespace: "system_sw_usb"
+ description: "Flag incompatible charging on COMPLIANCE_WARNING_INPUT_POWER_LIMITED instead of COMPLIANCE_WARNING_OTHER when enabled"
+ bug: "308700954"
+}
diff --git a/core/java/android/net/NetworkStack.java b/core/java/android/net/NetworkStack.java
index dbb312720373..19ba6a1d22ed 100644
--- a/core/java/android/net/NetworkStack.java
+++ b/core/java/android/net/NetworkStack.java
@@ -23,6 +23,7 @@ import android.content.Context;
import android.os.IBinder;
import android.os.ServiceManager;
+import com.android.net.flags.Flags;
import com.android.net.module.util.PermissionUtils;
/**
* Constants and utilities for client code communicating with the network stack service.
@@ -103,4 +104,16 @@ public class NetworkStack {
final @NonNull String... otherPermissions) {
PermissionUtils.enforceNetworkStackPermissionOr(context, otherPermissions);
}
+
+ /**
+ * Get setting of the "set_data_saver_via_cm" flag.
+ *
+ * @hide
+ */
+ // A workaround for aconfig. Currently, aconfig value read from platform and mainline code can
+ // be inconsistent. To avoid the problem, CTS for mainline code can get the flag value by this
+ // method.
+ public static boolean getDataSaverViaCmFlag() {
+ return Flags.setDataSaverViaCm();
+ }
}
diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java
index 3db1cb0500f9..995622004fa6 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -333,6 +333,12 @@ public class Binder implements IBinder {
@CriticalNative
public static final native boolean isDirectlyHandlingTransactionNative();
+ /** @hide */
+ public static final boolean isDirectlyHandlingTransactionNative$ravenwood() {
+ // Ravenwood doesn't support IPC
+ return false;
+ }
+
private static boolean sIsHandlingBinderTransaction = false;
/**
@@ -715,7 +721,9 @@ public class Binder implements IBinder {
*/
public Binder(@Nullable String descriptor) {
mObject = getNativeBBinderHolder();
- NoImagePreloadHolder.sRegistry.registerNativeAllocation(this, mObject);
+ if (mObject != 0L) {
+ NoImagePreloadHolder.sRegistry.registerNativeAllocation(this, mObject);
+ }
if (FIND_POTENTIAL_LEAKS) {
final Class<? extends Binder> klass = getClass();
@@ -1277,6 +1285,10 @@ public class Binder implements IBinder {
private static native long getNativeBBinderHolder();
+ private static long getNativeBBinderHolder$ravenwood() {
+ return 0L;
+ }
+
/**
* By default, we use the calling UID since we can always trust it.
*/
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index 352c9d2ba81f..86628d95b25a 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -1558,7 +1558,7 @@ public final class Parcel {
ensureWithinMemoryLimit(typeSize, totalObjects);
}
- private void ensureWithinMemoryLimit(int typeSize, @NonNull int length) {
+ private void ensureWithinMemoryLimit(int typeSize, int length) {
int estimatedAllocationSize = 0;
try {
estimatedAllocationSize = Math.multiplyExact(typeSize, length);
@@ -2957,6 +2957,14 @@ public final class Parcel {
}
/** @hide */
+ public final void writeException$ravenwood(@NonNull Exception e) {
+ // Ravenwood doesn't support IPC, no transaction headers needed
+ writeInt(getExceptionCode(e));
+ writeString(e.getMessage());
+ writeInt(0);
+ }
+
+ /** @hide */
public static int getExceptionCode(@NonNull Throwable e) {
int code = 0;
if (e instanceof Parcelable
@@ -3039,6 +3047,12 @@ public final class Parcel {
}
}
+ /** @hide */
+ public final void writeNoException$ravenwood() {
+ // Ravenwood doesn't support IPC, no transaction headers needed
+ writeInt(0);
+ }
+
/**
* Special function for reading an exception result from the header of
* a parcel, to be used after receiving the result of a transaction. This
diff --git a/core/java/com/android/internal/app/IAppOpsService.aidl b/core/java/com/android/internal/app/IAppOpsService.aidl
index 1b05982a7569..492e2ac7cc28 100644
--- a/core/java/com/android/internal/app/IAppOpsService.aidl
+++ b/core/java/com/android/internal/app/IAppOpsService.aidl
@@ -42,22 +42,18 @@ import com.android.internal.app.MessageSamplingConfig;
// frameworks/native/libs/permission/include/binder/IAppOpsService.h must match the order here.
// Please be careful to respect both these issues when modifying this file.
interface IAppOpsService {
- // Deprecated, use checkOperationWithState instead.
+ // These methods are also called by native code, so please be careful that the number in
+ // frameworks/native/libs/permission/include/binder/IAppOpsService.h matches the ordering here.
int checkOperation(int code, int uid, String packageName);
- // Deprecated, use noteOperationWithState instead.
SyncNotedAppOp noteOperation(int code, int uid, String packageName, @nullable String attributionTag,
boolean shouldCollectAsyncNotedOp, String message, boolean shouldCollectMessage);
- // Deprecated, use startOperationWithState instead.
SyncNotedAppOp startOperation(IBinder clientId, int code, int uid, String packageName,
@nullable String attributionTag, boolean startIfModeDefault,
boolean shouldCollectAsyncNotedOp, String message, boolean shouldCollectMessage,
int attributionFlags, int attributionChainId);
- // Deprecated, use finishOperationWithState instead.
@UnsupportedAppUsage
void finishOperation(IBinder clientId, int code, int uid, String packageName,
@nullable String attributionTag);
- // These methods are also called by native code, so please be careful that the number in
- // frameworks/native/libs/permission/include/binder/IAppOpsService.h matches the ordering here.
void startWatchingMode(int op, String packageName, IAppOpsCallback callback);
void stopWatchingMode(IAppOpsCallback callback);
int permissionToOpCode(String permission);
@@ -138,33 +134,20 @@ interface IAppOpsService {
void stopWatchingAsyncNoted(String packageName, IAppOpsAsyncNotedCallback callback);
List<AsyncNotedAppOp> extractAsyncOps(String packageName);
- // Deprecated, use checkOperationWithStateRaw instead.
int checkOperationRaw(int code, int uid, String packageName, @nullable String attributionTag);
void reloadNonHistoricalState();
void collectNoteOpCallsForValidation(String stackTrace, int op, String packageName, long version);
- // These methods are also called by native code, so please be careful that the number in
- // frameworks/native/libs/permission/include/binder/IAppOpsService.h matches the ordering here.
- int checkOperationWithState(int code, in AttributionSourceState attributionSourceState);
- int checkOperationWithStateRaw(int code, in AttributionSourceState attributionSourceState);
- SyncNotedAppOp noteOperationWithState(int code, in AttributionSourceState attributionSourceState,
- boolean shouldCollectAsyncNotedOp, String message, boolean shouldCollectMessage);
- SyncNotedAppOp startOperationWithState(IBinder clientId, int code,
- in AttributionSourceState attributionSourceState, boolean startIfModeDefault,
- boolean shouldCollectAsyncNotedOp, String message, boolean shouldCollectMessage,
- int attributionFlags, int attributionChainId);
- void finishOperationWithState(IBinder clientId, int code, in AttributionSourceState attributionSourceState);
- // End of methods also called by native code (there may be more blocks like this of native
- // methods later in this file).
+
SyncNotedAppOp noteProxyOperationWithState(int code,
- in AttributionSourceState attributionSourceStateState,
- boolean shouldCollectAsyncNotedOp, String message, boolean shouldCollectMessage,
- boolean skipProxyOperation);
+ in AttributionSourceState attributionSourceStateState,
+ boolean shouldCollectAsyncNotedOp, String message, boolean shouldCollectMessage,
+ boolean skipProxyOperation);
SyncNotedAppOp startProxyOperationWithState(IBinder clientId, int code,
- in AttributionSourceState attributionSourceStateState, boolean startIfModeDefault,
- boolean shouldCollectAsyncNotedOp, String message, boolean shouldCollectMessage,
- boolean skipProxyOperation, int proxyAttributionFlags, int proxiedAttributionFlags,
- int attributionChainId);
+ in AttributionSourceState attributionSourceStateState, boolean startIfModeDefault,
+ boolean shouldCollectAsyncNotedOp, String message, boolean shouldCollectMessage,
+ boolean skipProxyOperation, int proxyAttributionFlags, int proxiedAttributionFlags,
+ int attributionChainId);
void finishProxyOperationWithState(IBinder clientId, int code,
- in AttributionSourceState attributionSourceStateState, boolean skipProxyOperation);
+ in AttributionSourceState attributionSourceStateState, boolean skipProxyOperation);
}
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 3795fc8594ae..440a33244a62 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -43,7 +43,10 @@ cc_library_shared_for_libandroid_runtime {
"-Wall",
"-Werror",
+ "-Wextra",
+ "-Wthread-safety",
"-Wno-error=deprecated-declarations",
+ "-Wno-unused-parameter",
"-Wunused",
"-Wunreachable-code",
diff --git a/core/jni/android_content_res_ResourceTimer.cpp b/core/jni/android_content_res_ResourceTimer.cpp
index 91e3c921afe6..66bda6100b31 100644
--- a/core/jni/android_content_res_ResourceTimer.cpp
+++ b/core/jni/android_content_res_ResourceTimer.cpp
@@ -44,9 +44,9 @@ static struct {
static int NativeGetTimers(JNIEnv* env, jobject /*clazz*/, jobjectArray timer, jboolean reset) {
size_t size = ResourceTimer::counterSize;
- if (jsize st = env->GetArrayLength(timer); st < size) {
- // Shrink the size to the minimum of the available counters and the available space.
- size = st;
+ if (size_t st = env->GetArrayLength(timer); st < size) {
+ // Shrink the size to the minimum of the available counters and the available space.
+ size = st;
}
for (size_t i = 0; i < size; i++) {
ResourceTimer::Timer src;
diff --git a/core/jni/android_hardware_camera2_DngCreator.cpp b/core/jni/android_hardware_camera2_DngCreator.cpp
index 30e546cc290d..82570be8e329 100644
--- a/core/jni/android_hardware_camera2_DngCreator.cpp
+++ b/core/jni/android_hardware_camera2_DngCreator.cpp
@@ -1892,8 +1892,8 @@ static sp<TiffWriter> DngCreator_setup(JNIEnv* env, jobject thiz, uint32_t image
camera_metadata_entry entry =
results.find(ANDROID_SENSOR_NOISE_PROFILE);
- const status_t numPlaneColors = isBayer ? 3 : 1;
- const status_t numCfaChannels = isBayer ? 4 : 1;
+ const unsigned long numPlaneColors = isBayer ? 3 : 1;
+ const unsigned long numCfaChannels = isBayer ? 4 : 1;
uint8_t cfaOut[numCfaChannels];
if ((err = convertCFA(cfaEnum, /*out*/cfaOut)) != OK) {
diff --git a/core/jni/android_hardware_camera2_impl_CameraExtensionJpegProcessor.cpp b/core/jni/android_hardware_camera2_impl_CameraExtensionJpegProcessor.cpp
index 139075907bf3..4bde87f65326 100644
--- a/core/jni/android_hardware_camera2_impl_CameraExtensionJpegProcessor.cpp
+++ b/core/jni/android_hardware_camera2_impl_CameraExtensionJpegProcessor.cpp
@@ -599,7 +599,7 @@ static jint CameraExtensionJpegProcessor_compressJpegFromYUV420p(
quality, cropLeft, cropTop, cropRight, cropBottom, rot90);
size_t finalJpegSize = actualJpegSize + sizeof(CameraBlob);
- if (finalJpegSize > outBufCapacity) {
+ if (finalJpegSize > static_cast<size_t>(outBufCapacity)) {
ALOGE("%s: Final jpeg buffer %zu not large enough for the jpeg blob header with "\
"capacity %d", __FUNCTION__, finalJpegSize, outBufCapacity);
return actualJpegSize;
diff --git a/core/jni/android_media_AudioProductStrategies.cpp b/core/jni/android_media_AudioProductStrategies.cpp
index 4b563d7f3bd8..7c9dae0ef306 100644
--- a/core/jni/android_media_AudioProductStrategies.cpp
+++ b/core/jni/android_media_AudioProductStrategies.cpp
@@ -88,12 +88,12 @@ static jint convertAudioProductStrategiesFromNative(
int attrGroupIndex = 0;
std::map<int /**attributesGroupIndex*/, std::vector<VolumeGroupAttributes> > groups;
for (const auto &attr : strategy.getVolumeGroupAttributes()) {
- int groupId = attr.getGroupId();
+ auto groupId = attr.getGroupId();
int streamType = attr.getStreamType();
const auto &iter = std::find_if(begin(groups), end(groups),
[groupId, streamType](const auto &iter) {
const auto &frontAttr = iter.second.front();
- return frontAttr.getGroupId() == groupId && frontAttr.getStreamType() == streamType;
+ return (frontAttr.getGroupId() == groupId && frontAttr.getStreamType() == streamType);
});
// Same Volume Group Id and same stream type
if (iter != end(groups)) {
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index 6440cc3952f8..3413ededb889 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -2501,7 +2501,7 @@ static std::vector<uid_t> convertJIntArrayToUidVector(JNIEnv *env, jintArray jAr
int *nativeArray = nullptr;
nativeArray = env->GetIntArrayElements(jArray, 0);
if (nativeArray != nullptr) {
- for (size_t i = 0; i < len; i++) {
+ for (size_t i = 0; i < static_cast<size_t>(len); i++) {
nativeVector.push_back(nativeArray[i]);
}
env->ReleaseIntArrayElements(jArray, nativeArray, 0);
@@ -2565,7 +2565,7 @@ static jint android_media_AudioSystem_setSupportedSystemUsages(JNIEnv *env, jobj
if (nativeSystemUsages != nullptr) {
jsize len = env->GetArrayLength(systemUsages);
- for (size_t i = 0; i < len; i++) {
+ for (size_t i = 0; i < static_cast<size_t>(len); i++) {
audio_usage_t nativeAudioUsage =
static_cast<audio_usage_t>(nativeSystemUsages[i]);
nativeSystemUsagesVector.push_back(nativeAudioUsage);
@@ -2776,7 +2776,7 @@ static jint android_media_AudioSystem_getDevicesForAttributes(JNIEnv *env, jobje
return jStatus;
}
- if (devices.size() > maxResultSize) {
+ if (devices.size() > static_cast<size_t>(maxResultSize)) {
return AUDIO_JAVA_INVALID_OPERATION;
}
size_t index = 0;
diff --git a/core/jni/android_net_LocalSocketImpl.cpp b/core/jni/android_net_LocalSocketImpl.cpp
index 9bd07007586c..47b4a469aa5b 100644
--- a/core/jni/android_net_LocalSocketImpl.cpp
+++ b/core/jni/android_net_LocalSocketImpl.cpp
@@ -221,7 +221,7 @@ static int socket_write_all(JNIEnv *env, jobject object, int fd,
ssize_t rc = SendFileDescriptorVector(fd, buffer, len, fds);
- while (rc != len) {
+ while (rc != static_cast<ssize_t>(len)) {
if (rc == -1) {
jniThrowIOException(env, errno);
return -1;
diff --git a/core/jni/android_os_HwBlob.cpp b/core/jni/android_os_HwBlob.cpp
index a9db91be1d5b..e554b44233b5 100644
--- a/core/jni/android_os_HwBlob.cpp
+++ b/core/jni/android_os_HwBlob.cpp
@@ -265,7 +265,7 @@ jobject JHwBlob::NewObject(JNIEnv *env, size_t size) {
// justify passing such a large amount of data over this path. So the
// alternative (updating the constructor and other code to accept other
// types, should also probably not be taken in this case).
- CHECK_LE(size, std::numeric_limits<jint>::max());
+ CHECK_LE(size, static_cast<size_t>(std::numeric_limits<jint>::max()));
return env->NewObject(clazz.get(), constructID, static_cast<jint>(size));
}
diff --git a/core/jni/android_os_Parcel.cpp b/core/jni/android_os_Parcel.cpp
index 4d8dac1daaf0..3539476b8ce8 100644
--- a/core/jni/android_os_Parcel.cpp
+++ b/core/jni/android_os_Parcel.cpp
@@ -691,7 +691,7 @@ static jboolean android_os_Parcel_hasFileDescriptorsInRange(JNIEnv* env, jclass
// String tries to allocate itself on the stack, within a known size, but will
// make a heap allocation if not.
-template <size_t StackReserve>
+template <jsize StackReserve>
class StackString {
public:
StackString(JNIEnv* env, jstring str) : mEnv(env), mJStr(str) {
diff --git a/core/jni/android_os_PerformanceHintManager.cpp b/core/jni/android_os_PerformanceHintManager.cpp
index 27c4cd4d2cd1..95bf49fe501e 100644
--- a/core/jni/android_os_PerformanceHintManager.cpp
+++ b/core/jni/android_os_PerformanceHintManager.cpp
@@ -224,7 +224,7 @@ static jintArray nativeGetThreadIds(JNIEnv* env, jclass clazz, jlong nativeSessi
return nullptr;
}
jint* threadIds = env->GetIntArrayElements(jintArr, 0);
- for (int i = 0; i < size; ++i) {
+ for (size_t i = 0; i < size; ++i) {
threadIds[i] = tidsVector[i];
}
env->ReleaseIntArrayElements(jintArr, threadIds, 0);
diff --git a/core/jni/android_util_CharsetUtils.cpp b/core/jni/android_util_CharsetUtils.cpp
index 7ab6e8f27fb2..7071cf2336d6 100644
--- a/core/jni/android_util_CharsetUtils.cpp
+++ b/core/jni/android_util_CharsetUtils.cpp
@@ -25,7 +25,7 @@ static jint android_util_CharsetUtils_toModifiedUtf8Bytes(JNIEnv *env, jobject c
// Quickly check if destination has plenty of room for worst-case
// 4-bytes-per-char encoded size
- const size_t worstLen = (srcLen * 4);
+ const jint worstLen = (srcLen * 4);
if (destOff >= 0 && destOff + worstLen < destLen) {
env->GetStringUTFRegion(src, 0, srcLen, destPtr + destOff);
return strlen(destPtr + destOff + srcLen) + srcLen;
@@ -33,7 +33,7 @@ static jint android_util_CharsetUtils_toModifiedUtf8Bytes(JNIEnv *env, jobject c
// String still might fit in destination, but we need to measure
// its actual encoded size to be sure
- const size_t encodedLen = env->GetStringUTFLength(src);
+ const jint encodedLen = env->GetStringUTFLength(src);
if (destOff >= 0 && destOff + encodedLen < destLen) {
env->GetStringUTFRegion(src, 0, srcLen, destPtr + destOff);
return encodedLen;
diff --git a/core/jni/android_util_FileObserver.cpp b/core/jni/android_util_FileObserver.cpp
index c64c21244fe0..8d3da7b81f5b 100644
--- a/core/jni/android_util_FileObserver.cpp
+++ b/core/jni/android_util_FileObserver.cpp
@@ -114,7 +114,7 @@ static void android_os_fileobserver_startWatching(JNIEnv* env, jobject object, j
if (fd >= 0)
{
size_t count = wfds.size();
- for (jsize i = 0; i < count; ++i) {
+ for (size_t i = 0; i < count; ++i) {
jstring pathString = (jstring) env->GetObjectArrayElement(pathStrings, i);
ScopedUtfChars path(env, pathString);
diff --git a/core/jni/android_view_DisplayEventReceiver.cpp b/core/jni/android_view_DisplayEventReceiver.cpp
index 41c65aec3144..fef8ad7499f7 100644
--- a/core/jni/android_view_DisplayEventReceiver.cpp
+++ b/core/jni/android_view_DisplayEventReceiver.cpp
@@ -140,7 +140,7 @@ static jobject createJavaVsyncEventData(JNIEnv* env, VsyncEventData vsyncEventDa
env->ExceptionClear();
return NULL;
}
- for (int i = 0; i < vsyncEventData.frameTimelinesLength; i++) {
+ for (size_t i = 0; i < vsyncEventData.frameTimelinesLength; i++) {
VsyncEventData::FrameTimeline frameTimeline = vsyncEventData.frameTimelines[i];
ScopedLocalRef<jobject>
frameTimelineObj(env,
@@ -193,7 +193,7 @@ void NativeDisplayEventReceiver::dispatchVsync(nsecs_t timestamp, PhysicalDispla
gDisplayEventReceiverClassInfo
.vsyncEventDataClassInfo
.frameTimelines)));
- for (int i = 0; i < vsyncEventData.frameTimelinesLength; i++) {
+ for (size_t i = 0; i < vsyncEventData.frameTimelinesLength; i++) {
VsyncEventData::FrameTimeline& frameTimeline = vsyncEventData.frameTimelines[i];
ScopedLocalRef<jobject>
frameTimelineObj(env, env->GetObjectArrayElement(frameTimelinesObj.get(), i));
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 98335988459a..a800e6ea60e4 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -1950,7 +1950,7 @@ public:
jobjectArray jJankDataArray = env->NewObjectArray(jankData.size(),
gJankDataClassInfo.clazz, nullptr);
- for (int i = 0; i < jankData.size(); i++) {
+ for (size_t i = 0; i < jankData.size(); i++) {
jobject jJankData = env->NewObject(gJankDataClassInfo.clazz,
gJankDataClassInfo.ctor, jankData[i].frameVsyncId, jankData[i].jankType);
env->SetObjectArrayElement(jJankDataArray, i, jJankData);
diff --git a/core/jni/android_window_WindowInfosListener.cpp b/core/jni/android_window_WindowInfosListener.cpp
index 55995df299b0..bc69d1e67668 100644
--- a/core/jni/android_window_WindowInfosListener.cpp
+++ b/core/jni/android_window_WindowInfosListener.cpp
@@ -67,7 +67,7 @@ jobject fromDisplayInfo(JNIEnv* env, gui::DisplayInfo displayInfo) {
static jobjectArray fromWindowInfos(JNIEnv* env, const std::vector<WindowInfo>& windowInfos) {
jobjectArray jWindowHandlesArray =
env->NewObjectArray(windowInfos.size(), gInputWindowHandleClass, nullptr);
- for (int i = 0; i < windowInfos.size(); i++) {
+ for (size_t i = 0; i < windowInfos.size(); i++) {
ScopedLocalRef<jobject>
jWindowHandle(env,
android_view_InputWindowHandle_fromWindowInfo(env, windowInfos[i]));
@@ -80,7 +80,7 @@ static jobjectArray fromWindowInfos(JNIEnv* env, const std::vector<WindowInfo>&
static jobjectArray fromDisplayInfos(JNIEnv* env, const std::vector<DisplayInfo>& displayInfos) {
jobjectArray jDisplayInfoArray =
env->NewObjectArray(displayInfos.size(), gDisplayInfoClassInfo.clazz, nullptr);
- for (int i = 0; i < displayInfos.size(); i++) {
+ for (size_t i = 0; i < displayInfos.size(); i++) {
ScopedLocalRef<jobject> jDisplayInfo(env, fromDisplayInfo(env, displayInfos[i]));
env->SetObjectArrayElement(jDisplayInfoArray, i, jDisplayInfo.get());
}
diff --git a/core/jni/com_android_internal_content_om_OverlayManagerImpl.cpp b/core/jni/com_android_internal_content_om_OverlayManagerImpl.cpp
index d4f6e1868695..0c39a6928391 100644
--- a/core/jni/com_android_internal_content_om_OverlayManagerImpl.cpp
+++ b/core/jni/com_android_internal_content_om_OverlayManagerImpl.cpp
@@ -266,11 +266,11 @@ static void CreateFrroFile(JNIEnv* env, jclass /*clazz*/, jstring jsFrroFilePath
auto jsResourceName = reinterpret_cast<jstring>(
env->GetObjectField(entry, gFabricatedOverlayInternalEntryOffsets.resourceName));
const ScopedUtfChars resourceName(env, jsResourceName);
- const auto dataType =
+ const jint dataType =
env->GetIntField(entry, gFabricatedOverlayInternalEntryOffsets.dataType);
// In Java, the data type is int but the maximum value of data Type is less than 0xff.
- if (dataType >= UCHAR_MAX) {
+ if (dataType >= static_cast<jint>(UCHAR_MAX)) {
jniThrowException(env, IllegalArgumentException, "Unsupported data type");
return;
}
diff --git a/core/jni/com_android_internal_os_KernelCpuUidBpfMapReader.cpp b/core/jni/com_android_internal_os_KernelCpuUidBpfMapReader.cpp
index 098a4d868269..cf70c90af8be 100644
--- a/core/jni/com_android_internal_os_KernelCpuUidBpfMapReader.cpp
+++ b/core/jni/com_android_internal_os_KernelCpuUidBpfMapReader.cpp
@@ -55,7 +55,7 @@ static void copy2DVecToArray(JNIEnv *env, jlongArray ar, std::vector<std::vector
static jboolean KernelCpuUidFreqTimeBpfMapReader_removeUidRange(JNIEnv *env, jclass, jint startUid,
jint endUid) {
- for (uint32_t uid = startUid; uid <= endUid; ++uid) {
+ for (jint uid = startUid; uid <= endUid; ++uid) {
if (!android::bpf::clearUidTimes(uid)) return false;
}
return true;
diff --git a/core/jni/com_android_internal_os_KernelSingleProcessCpuThreadReader.cpp b/core/jni/com_android_internal_os_KernelSingleProcessCpuThreadReader.cpp
index dfae68429f6d..be9013bec08e 100644
--- a/core/jni/com_android_internal_os_KernelSingleProcessCpuThreadReader.cpp
+++ b/core/jni/com_android_internal_os_KernelSingleProcessCpuThreadReader.cpp
@@ -147,7 +147,7 @@ static jboolean startAggregatingThreadCpuTimes(JNIEnv *env, jclass, jintArray se
std::unique_ptr<ICpuTimeInStateReader> cpuTimeInStateReader(
getCpuTimeInStateReader(env, cpuTimeInStateReaderObject));
- for (int i = 0; i < selectedThreadIds.size(); i++) {
+ for (size_t i = 0; i < selectedThreadIds.size(); i++) {
if (!cpuTimeInStateReader->startAggregatingTaskCpuTimes(selectedThreadIds[i],
SELECTED_THREAD_AGGREGATION_KEY)) {
return false;
@@ -312,11 +312,11 @@ MockCpuTimeInStateReader::getAggregatedTaskCpuFreqTimes(
auto fields = android::base::Split(line.c_str(), ":");
android::base::ParseUint(fields[0], &aggregationKey);
- for (int j = 1; j < fields.size(); j++) {
+ for (size_t j = 1; j < fields.size(); j++) {
auto numbers = android::base::Split(fields[j], " ");
std::vector<uint64_t> chunk;
- for (int k = 0; k < numbers.size(); k++) {
+ for (size_t k = 0; k < numbers.size(); k++) {
uint64_t time;
android::base::ParseUint(numbers[k], &time);
chunk.emplace_back(time);
diff --git a/core/jni/com_android_internal_os_LongArrayMultiStateCounter.cpp b/core/jni/com_android_internal_os_LongArrayMultiStateCounter.cpp
index 1f29735b93a4..dab47e9a9e28 100644
--- a/core/jni/com_android_internal_os_LongArrayMultiStateCounter.cpp
+++ b/core/jni/com_android_internal_os_LongArrayMultiStateCounter.cpp
@@ -288,7 +288,7 @@ static jboolean native_combineValues_LongArrayContainer(JNIEnv *env, jobject sel
}
bool nonZero = false;
- for (int i = 0; i < vector->size(); i++) {
+ for (size_t i = 0; i < vector->size(); i++) {
jint index = scopedIndexMap[i];
if (index < 0 || index >= size) {
jniThrowExceptionFmt(env, "java/lang/IndexOutOfBoundsException",
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 9c1bea779201..7c5885adb220 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -1094,8 +1094,8 @@ static std::string getAppDataDirName(std::string_view parent_path, std::string_v
}
struct dirent* ent;
while ((ent = readdir(dir.get()))) {
- if (ent->d_ino == ce_data_inode) {
- return ent->d_name;
+ if (static_cast<long long>(ent->d_ino) == ce_data_inode) {
+ return ent->d_name;
}
}
}
@@ -1765,14 +1765,14 @@ static void ReloadBuildJavaConstant(JNIEnv* env, jclass build_class, const char*
static void ReloadBuildJavaConstants(JNIEnv* env) {
jclass build_cls = env->FindClass("android/os/Build");
size_t arr_size = sizeof(build_constants) / sizeof(build_constants[0]);
- for (int i = 0; i < arr_size; i++) {
+ for (size_t i = 0; i < arr_size; i++) {
const char* field_name = build_constants[i].first;
const char* sysprop_name = build_constants[i].second;
ReloadBuildJavaConstant(env, build_cls, field_name, "Ljava/lang/String;", sysprop_name);
}
jclass build_version_cls = env->FindClass("android/os/Build$VERSION");
arr_size = sizeof(build_version_constants) / sizeof(build_version_constants[0]);
- for (int i = 0; i < arr_size; i++) {
+ for (size_t i = 0; i < arr_size; i++) {
const char* field_name = build_version_constants[i].first;
const char* sysprop_name = build_version_constants[i].second;
ReloadBuildJavaConstant(env, build_version_cls, field_name, "Ljava/lang/String;", sysprop_name);
@@ -2901,7 +2901,7 @@ static jint com_android_internal_os_Zygote_nativeParseSigChld(JNIEnv* env, jclas
return -1;
}
ScopedByteArrayRO source(env, in);
- if (source.size() < length) {
+ if (source.size() < static_cast<size_t>(length)) {
// Invalid parameter
jniThrowException(env, "java/lang/IllegalArgumentException", nullptr);
return -1;
diff --git a/core/jni/com_android_internal_os_ZygoteCommandBuffer.cpp b/core/jni/com_android_internal_os_ZygoteCommandBuffer.cpp
index 2b5b8f7a108e..87ab4969040e 100644
--- a/core/jni/com_android_internal_os_ZygoteCommandBuffer.cpp
+++ b/core/jni/com_android_internal_os_ZygoteCommandBuffer.cpp
@@ -76,7 +76,7 @@ class NativeCommandBuffer {
return {};
}
fail_fn(CREATE_ERROR("session socket read failed: %s", strerror(errno)));
- } else if (nread == MAX_COMMAND_BYTES - mEnd) {
+ } else if (nread == static_cast<ssize_t>(MAX_COMMAND_BYTES - mEnd)) {
// This is pessimistic by one character, but close enough.
fail_fn("ZygoteCommandBuffer overflowed: command too long");
}
@@ -136,7 +136,7 @@ class NativeCommandBuffer {
}
char* countString = line.value().first; // Newline terminated.
long nArgs = atol(countString);
- if (nArgs <= 0 || nArgs >= MAX_COMMAND_BYTES / 2) {
+ if (nArgs <= 0 || nArgs >= static_cast<long>(MAX_COMMAND_BYTES / 2)) {
fail_fn(CREATE_ERROR("Unreasonable argument count %ld", nArgs));
}
mLinesLeft = nArgs;
@@ -153,7 +153,7 @@ class NativeCommandBuffer {
// As a side effect, this sets mNiceName to a non-empty string, if possible.
template<class FailFn>
bool isSimpleForkCommand(int minUid, FailFn fail_fn) {
- if (mLinesLeft <= 0 || mLinesLeft >= MAX_COMMAND_BYTES / 2) {
+ if (mLinesLeft <= 0 || mLinesLeft >= static_cast<int32_t>(MAX_COMMAND_BYTES / 2)) {
return false;
}
static const char* RUNTIME_ARGS = "--runtime-args";
@@ -179,14 +179,14 @@ class NativeCommandBuffer {
if (!read_result.has_value()) {
return false;
}
- auto [arg_start, arg_end] = read_result.value();
- if (arg_end - arg_start == RA_LENGTH
- && strncmp(arg_start, RUNTIME_ARGS, RA_LENGTH) == 0) {
+ const auto [arg_start, arg_end] = read_result.value();
+ if (static_cast<size_t>(arg_end - arg_start) == RA_LENGTH &&
+ strncmp(arg_start, RUNTIME_ARGS, RA_LENGTH) == 0) {
saw_runtime_args = true;
continue;
}
- if (arg_end - arg_start >= NN_LENGTH
- && strncmp(arg_start, NICE_NAME, NN_LENGTH) == 0) {
+ if (static_cast<size_t>(arg_end - arg_start) >= NN_LENGTH &&
+ strncmp(arg_start, NICE_NAME, NN_LENGTH) == 0) {
size_t name_len = arg_end - (arg_start + NN_LENGTH);
size_t copy_len = std::min(name_len, NICE_NAME_BYTES - 1);
memcpy(mNiceName, arg_start + NN_LENGTH, copy_len);
@@ -196,21 +196,21 @@ class NativeCommandBuffer {
}
continue;
}
- if (arg_end - arg_start == IW_LENGTH
- && strncmp(arg_start, INVOKE_WITH, IW_LENGTH) == 0) {
+ if (static_cast<size_t>(arg_end - arg_start) == IW_LENGTH &&
+ strncmp(arg_start, INVOKE_WITH, IW_LENGTH) == 0) {
// This also removes the need for invoke-with security checks here.
return false;
}
- if (arg_end - arg_start == CZ_LENGTH
- && strncmp(arg_start, CHILD_ZYGOTE, CZ_LENGTH) == 0) {
+ if (static_cast<size_t>(arg_end - arg_start) == CZ_LENGTH &&
+ strncmp(arg_start, CHILD_ZYGOTE, CZ_LENGTH) == 0) {
return false;
}
- if (arg_end - arg_start >= CA_LENGTH
- && strncmp(arg_start, CAPABILITIES, CA_LENGTH) == 0) {
+ if (static_cast<size_t>(arg_end - arg_start) >= CA_LENGTH &&
+ strncmp(arg_start, CAPABILITIES, CA_LENGTH) == 0) {
return false;
}
- if (arg_end - arg_start >= SU_LENGTH
- && strncmp(arg_start, SETUID, SU_LENGTH) == 0) {
+ if (static_cast<size_t>(arg_end - arg_start) >= SU_LENGTH &&
+ strncmp(arg_start, SETUID, SU_LENGTH) == 0) {
int uid = digitsVal(arg_start + SU_LENGTH, arg_end);
if (uid < minUid) {
return false;
@@ -218,8 +218,8 @@ class NativeCommandBuffer {
saw_setuid = true;
continue;
}
- if (arg_end - arg_start >= SG_LENGTH
- && strncmp(arg_start, SETGID, SG_LENGTH) == 0) {
+ if (static_cast<size_t>(arg_end - arg_start) >= SG_LENGTH &&
+ strncmp(arg_start, SETGID, SG_LENGTH) == 0) {
int gid = digitsVal(arg_start + SG_LENGTH, arg_end);
if (gid == -1) {
return false;
@@ -422,7 +422,7 @@ jboolean com_android_internal_os_ZygoteCommandBuffer_nativeForkRepeatedly(
bool first_time = true;
do {
- if (credentials.uid != expected_uid) {
+ if (credentials.uid != static_cast<uid_t>(expected_uid)) {
return JNI_FALSE;
}
n_buffer->readAllLines(first_time ? fail_fn_1 : fail_fn_n);
diff --git a/framework-minus-apex-ravenwood-policies.txt b/framework-minus-apex-ravenwood-policies.txt
index 8e76fd22f99a..48c0a2de8f86 100644
--- a/framework-minus-apex-ravenwood-policies.txt
+++ b/framework-minus-apex-ravenwood-policies.txt
@@ -71,8 +71,9 @@ class android.util.proto.WireTypeMismatchException stubclass
# Misc
class android.util.Dumpable stubclass
class android.util.DebugUtils stubclass
-class android.util.UtilConfig stubclass
+class android.util.MathUtils stubclass
class android.util.Patterns stubclass
+class android.util.UtilConfig stubclass
# Internals
class com.android.internal.util.ArrayUtils stubclass
@@ -89,3 +90,26 @@ class com.android.internal.util.GrowingArrayUtils stubclass
class com.android.internal.util.LineBreakBufferedWriter stubclass
class com.android.internal.util.Preconditions stubclass
class com.android.internal.util.StringPool stubclass
+
+# Parcel
+class android.os.Parcel stubclass
+ method writeException (Ljava/lang/Exception;)V @writeException$ravenwood
+ method writeNoException ()V @writeNoException$ravenwood
+class android.os.Parcel !com.android.hoststubgen.nativesubstitution.Parcel_host
+
+class android.os.Parcelable stubclass
+class android.os.ParcelFormatException stubclass
+class android.os.BadParcelableException stubclass
+class android.os.BadTypeParcelableException stubclass
+
+# Binder: just enough to construct, no further functionality
+class android.os.Binder stub
+ method <init> ()V stub
+ method <init> (Ljava/lang/String;)V stub
+ method isDirectlyHandlingTransaction ()Z stub
+ method isDirectlyHandlingTransactionNative ()Z @isDirectlyHandlingTransactionNative$ravenwood
+ method getNativeBBinderHolder ()J @getNativeBBinderHolder$ravenwood
+
+# Containers
+class android.os.BaseBundle stubclass
+class android.os.Bundle stubclass
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitionHandler.java
index 0890861596a5..e63bbc07bc41 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitionHandler.java
@@ -252,12 +252,7 @@ public class KeyguardTransitionHandler
Log.wtf(TAG, "RemoteException thrown from KeyguardService transition", e);
}
nextFinishCallback.onTransitionFinished(null);
- } else if (nextInfo.getType() == TRANSIT_SLEEP) {
- // An empty SLEEP transition comes in as a signal to abort transitions whenever a sleep
- // token is held. In cases where keyguard is showing, we are running the animation for
- // the device sleeping/waking, so it's best to ignore this and keep playing anyway.
- return;
- } else if (handles(nextInfo)) {
+ } else {
// In all other cases, fast-forward to let the next queued transition start playing.
finishAnimationImmediately(currentTransition, playing);
}
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
index 774478669058..c5ffbb70213e 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
@@ -187,11 +187,12 @@ IRenderPipeline::DrawResult SkiaOpenGLPipeline::draw(
dumpResourceCacheUsage();
}
- return {true, IRenderPipeline::DrawResult::kUnknownTime};
+ return {true, IRenderPipeline::DrawResult::kUnknownTime, android::base::unique_fd{}};
}
-bool SkiaOpenGLPipeline::swapBuffers(const Frame& frame, bool drew, const SkRect& screenDirty,
- FrameInfo* currentFrameInfo, bool* requireSwap) {
+bool SkiaOpenGLPipeline::swapBuffers(const Frame& frame, IRenderPipeline::DrawResult& drawResult,
+ const SkRect& screenDirty, FrameInfo* currentFrameInfo,
+ bool* requireSwap) {
GL_CHECKPOINT(LOW);
// Even if we decided to cancel the frame, from the perspective of jank
@@ -202,7 +203,7 @@ bool SkiaOpenGLPipeline::swapBuffers(const Frame& frame, bool drew, const SkRect
return false;
}
- *requireSwap = drew || mEglManager.damageRequiresSwap();
+ *requireSwap = drawResult.success || mEglManager.damageRequiresSwap();
if (*requireSwap && (CC_UNLIKELY(!mEglManager.swapBuffers(frame, screenDirty)))) {
return false;
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h
index f0461bef170c..098a74655831 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h
@@ -44,8 +44,9 @@ public:
const std::vector<sp<RenderNode> >& renderNodes, FrameInfoVisualizer* profiler,
const renderthread::HardwareBufferRenderParams& bufferParams) override;
GrSurfaceOrigin getSurfaceOrigin() override { return kBottomLeft_GrSurfaceOrigin; }
- bool swapBuffers(const renderthread::Frame& frame, bool drew, const SkRect& screenDirty,
- FrameInfo* currentFrameInfo, bool* requireSwap) override;
+ bool swapBuffers(const renderthread::Frame& frame, IRenderPipeline::DrawResult& drawResult,
+ const SkRect& screenDirty, FrameInfo* currentFrameInfo,
+ bool* requireSwap) override;
DeferredLayerUpdater* createTextureLayer() override;
bool setSurface(ANativeWindow* surface, renderthread::SwapBehavior swapBehavior) override;
[[nodiscard]] android::base::unique_fd flush() override;
diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
index 86096d5bd01c..12cb69da772b 100644
--- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
@@ -87,7 +87,7 @@ IRenderPipeline::DrawResult SkiaVulkanPipeline::draw(
}
if (backBuffer.get() == nullptr) {
- return {false, -1};
+ return {false, -1, android::base::unique_fd{}};
}
// update the coordinates of the global light position based on surface rotation
@@ -110,10 +110,10 @@ IRenderPipeline::DrawResult SkiaVulkanPipeline::draw(
profiler->draw(profileRenderer);
}
- nsecs_t submissionTime = IRenderPipeline::DrawResult::kUnknownTime;
+ VulkanManager::VkDrawResult drawResult;
{
ATRACE_NAME("flush commands");
- submissionTime = vulkanManager().finishFrame(backBuffer.get());
+ drawResult = vulkanManager().finishFrame(backBuffer.get());
}
layerUpdateQueue->clear();
@@ -122,11 +122,12 @@ IRenderPipeline::DrawResult SkiaVulkanPipeline::draw(
dumpResourceCacheUsage();
}
- return {true, submissionTime};
+ return {true, drawResult.submissionTime, std::move(drawResult.presentFence)};
}
-bool SkiaVulkanPipeline::swapBuffers(const Frame& frame, bool drew, const SkRect& screenDirty,
- FrameInfo* currentFrameInfo, bool* requireSwap) {
+bool SkiaVulkanPipeline::swapBuffers(const Frame& frame, IRenderPipeline::DrawResult& drawResult,
+ const SkRect& screenDirty, FrameInfo* currentFrameInfo,
+ bool* requireSwap) {
// Even if we decided to cancel the frame, from the perspective of jank
// metrics the frame was swapped at this point
currentFrameInfo->markSwapBuffers();
@@ -135,10 +136,10 @@ bool SkiaVulkanPipeline::swapBuffers(const Frame& frame, bool drew, const SkRect
return false;
}
- *requireSwap = drew;
+ *requireSwap = drawResult.success;
if (*requireSwap) {
- vulkanManager().swapBuffers(mVkSurface, screenDirty);
+ vulkanManager().swapBuffers(mVkSurface, screenDirty, std::move(drawResult.presentFence));
}
return *requireSwap;
diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
index 284cde537ec0..e2ea57d32cd5 100644
--- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
@@ -44,8 +44,9 @@ public:
const std::vector<sp<RenderNode> >& renderNodes, FrameInfoVisualizer* profiler,
const renderthread::HardwareBufferRenderParams& bufferParams) override;
GrSurfaceOrigin getSurfaceOrigin() override { return kTopLeft_GrSurfaceOrigin; }
- bool swapBuffers(const renderthread::Frame& frame, bool drew, const SkRect& screenDirty,
- FrameInfo* currentFrameInfo, bool* requireSwap) override;
+ bool swapBuffers(const renderthread::Frame& frame, IRenderPipeline::DrawResult& drawResult,
+ const SkRect& screenDirty, FrameInfo* currentFrameInfo,
+ bool* requireSwap) override;
DeferredLayerUpdater* createTextureLayer() override;
[[nodiscard]] android::base::unique_fd flush() override;
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 9e3bb79f03f3..56b52dc2abe7 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -664,8 +664,8 @@ void CanvasContext::draw(bool solelyTextureViewUpdates) {
bool didDraw = false;
int error = OK;
- bool didSwap = mRenderPipeline->swapBuffers(frame, drawResult.success, windowDirty,
- mCurrentFrameInfo, &requireSwap);
+ bool didSwap = mRenderPipeline->swapBuffers(frame, drawResult, windowDirty, mCurrentFrameInfo,
+ &requireSwap);
mCurrentFrameInfo->set(FrameInfoIndex::CommandSubmissionCompleted) = std::max(
drawResult.commandSubmissionTime, mCurrentFrameInfo->get(FrameInfoIndex::SwapBuffers));
diff --git a/libs/hwui/renderthread/IRenderPipeline.h b/libs/hwui/renderthread/IRenderPipeline.h
index 6c2cb9d71c55..9c879d5a58d1 100644
--- a/libs/hwui/renderthread/IRenderPipeline.h
+++ b/libs/hwui/renderthread/IRenderPipeline.h
@@ -61,6 +61,7 @@ public:
// submission occurred. -1 if this time is unknown.
static constexpr nsecs_t kUnknownTime = -1;
nsecs_t commandSubmissionTime = kUnknownTime;
+ android::base::unique_fd presentFence;
};
virtual DrawResult draw(const Frame& frame, const SkRect& screenDirty, const SkRect& dirty,
const LightGeometry& lightGeometry, LayerUpdateQueue* layerUpdateQueue,
@@ -68,8 +69,9 @@ public:
const std::vector<sp<RenderNode>>& renderNodes,
FrameInfoVisualizer* profiler,
const HardwareBufferRenderParams& bufferParams) = 0;
- virtual bool swapBuffers(const Frame& frame, bool drew, const SkRect& screenDirty,
- FrameInfo* currentFrameInfo, bool* requireSwap) = 0;
+ virtual bool swapBuffers(const Frame& frame, IRenderPipeline::DrawResult&,
+ const SkRect& screenDirty, FrameInfo* currentFrameInfo,
+ bool* requireSwap) = 0;
virtual DeferredLayerUpdater* createTextureLayer() = 0;
[[nodiscard]] virtual android::base::unique_fd flush() = 0;
virtual void setHardwareBuffer(AHardwareBuffer* hardwareBuffer) = 0;
diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp
index 22c586248705..e706eb083ab6 100644
--- a/libs/hwui/renderthread/VulkanManager.cpp
+++ b/libs/hwui/renderthread/VulkanManager.cpp
@@ -531,32 +531,21 @@ struct DestroySemaphoreInfo {
PFN_vkDestroySemaphore mDestroyFunction;
VkDevice mDevice;
VkSemaphore mSemaphore;
- // We need to make sure we don't delete the VkSemaphore until it is done being used by both Skia
- // (including by the GPU) and inside the VulkanManager. So we always start with two refs, one
- // owned by Skia and one owned by the VulkanManager. The refs are decremented each time
- // destroy_semaphore is called with this object. Skia will call destroy_semaphore once it is
- // done with the semaphore and the GPU has finished work on the semaphore. The VulkanManager
- // calls destroy_semaphore after sending the semaphore to Skia and exporting it if need be.
- int mRefs = 2;
DestroySemaphoreInfo(PFN_vkDestroySemaphore destroyFunction, VkDevice device,
VkSemaphore semaphore)
: mDestroyFunction(destroyFunction), mDevice(device), mSemaphore(semaphore) {}
+
+ ~DestroySemaphoreInfo() { mDestroyFunction(mDevice, mSemaphore, nullptr); }
};
static void destroy_semaphore(void* context) {
DestroySemaphoreInfo* info = reinterpret_cast<DestroySemaphoreInfo*>(context);
- --info->mRefs;
- if (!info->mRefs) {
- info->mDestroyFunction(info->mDevice, info->mSemaphore, nullptr);
- delete info;
- }
+ delete info;
}
-nsecs_t VulkanManager::finishFrame(SkSurface* surface) {
+VulkanManager::VkDrawResult VulkanManager::finishFrame(SkSurface* surface) {
ATRACE_NAME("Vulkan finish frame");
- ALOGE_IF(mSwapSemaphore != VK_NULL_HANDLE || mDestroySemaphoreContext != nullptr,
- "finishFrame already has an outstanding semaphore");
VkExportSemaphoreCreateInfo exportInfo;
exportInfo.sType = VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO;
@@ -576,11 +565,11 @@ nsecs_t VulkanManager::finishFrame(SkSurface* surface) {
GrFlushInfo flushInfo;
if (err == VK_SUCCESS) {
- mDestroySemaphoreContext = new DestroySemaphoreInfo(mDestroySemaphore, mDevice, semaphore);
flushInfo.fNumSemaphores = 1;
flushInfo.fSignalSemaphores = &backendSemaphore;
flushInfo.fFinishedProc = destroy_semaphore;
- flushInfo.fFinishedContext = mDestroySemaphoreContext;
+ flushInfo.fFinishedContext =
+ new DestroySemaphoreInfo(mDestroySemaphore, mDevice, semaphore);
} else {
semaphore = VK_NULL_HANDLE;
}
@@ -589,10 +578,11 @@ nsecs_t VulkanManager::finishFrame(SkSurface* surface) {
GrSemaphoresSubmitted submitted = context->flush(
surface, SkSurfaces::BackendSurfaceAccess::kPresent, flushInfo);
context->submit();
- const nsecs_t submissionTime = systemTime();
+ VkDrawResult drawResult{
+ .submissionTime = systemTime(),
+ };
if (semaphore != VK_NULL_HANDLE) {
if (submitted == GrSemaphoresSubmitted::kYes) {
- mSwapSemaphore = semaphore;
if (mFrameBoundaryANDROID) {
// retrieve VkImage used as render target
VkImage image = VK_NULL_HANDLE;
@@ -611,45 +601,37 @@ nsecs_t VulkanManager::finishFrame(SkSurface* surface) {
}
// frameBoundaryANDROID needs to know about mSwapSemaphore, but
// it won't wait on it.
- mFrameBoundaryANDROID(mDevice, mSwapSemaphore, image);
+ mFrameBoundaryANDROID(mDevice, semaphore, image);
}
- } else {
- destroy_semaphore(mDestroySemaphoreContext);
- mDestroySemaphoreContext = nullptr;
}
- }
- skiapipeline::ShaderCache::get().onVkFrameFlushed(context);
-
- return submissionTime;
-}
-
-void VulkanManager::swapBuffers(VulkanSurface* surface, const SkRect& dirtyRect) {
- if (CC_UNLIKELY(Properties::waitForGpuCompletion)) {
- ATRACE_NAME("Finishing GPU work");
- mDeviceWaitIdle(mDevice);
- }
-
- int fenceFd = -1;
- if (mSwapSemaphore != VK_NULL_HANDLE) {
VkSemaphoreGetFdInfoKHR getFdInfo;
getFdInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR;
getFdInfo.pNext = nullptr;
- getFdInfo.semaphore = mSwapSemaphore;
+ getFdInfo.semaphore = semaphore;
getFdInfo.handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;
- VkResult err = mGetSemaphoreFdKHR(mDevice, &getFdInfo, &fenceFd);
+ int fenceFd = -1;
+ err = mGetSemaphoreFdKHR(mDevice, &getFdInfo, &fenceFd);
ALOGE_IF(VK_SUCCESS != err, "VulkanManager::swapBuffers(): Failed to get semaphore Fd");
+ drawResult.presentFence.reset(fenceFd);
} else {
- ALOGE("VulkanManager::swapBuffers(): Semaphore submission failed");
+ ALOGE("VulkanManager::finishFrame(): Semaphore submission failed");
mQueueWaitIdle(mGraphicsQueue);
}
- if (mDestroySemaphoreContext) {
- destroy_semaphore(mDestroySemaphoreContext);
+
+ skiapipeline::ShaderCache::get().onVkFrameFlushed(context);
+
+ return drawResult;
+}
+
+void VulkanManager::swapBuffers(VulkanSurface* surface, const SkRect& dirtyRect,
+ android::base::unique_fd&& presentFence) {
+ if (CC_UNLIKELY(Properties::waitForGpuCompletion)) {
+ ATRACE_NAME("Finishing GPU work");
+ mDeviceWaitIdle(mDevice);
}
- surface->presentCurrentBuffer(dirtyRect, fenceFd);
- mSwapSemaphore = VK_NULL_HANDLE;
- mDestroySemaphoreContext = nullptr;
+ surface->presentCurrentBuffer(dirtyRect, presentFence.release());
}
void VulkanManager::destroySurface(VulkanSurface* surface) {
@@ -753,22 +735,17 @@ status_t VulkanManager::createReleaseFence(int* nativeFence, GrDirectContext* gr
GrBackendSemaphore backendSemaphore;
backendSemaphore.initVulkan(semaphore);
- DestroySemaphoreInfo* destroyInfo =
- new DestroySemaphoreInfo(mDestroySemaphore, mDevice, semaphore);
// Even if Skia fails to submit the semaphore, it will still call the destroy_semaphore callback
- // which will remove its ref to the semaphore. The VulkanManager must still release its ref,
- // when it is done with the semaphore.
GrFlushInfo flushInfo;
flushInfo.fNumSemaphores = 1;
flushInfo.fSignalSemaphores = &backendSemaphore;
flushInfo.fFinishedProc = destroy_semaphore;
- flushInfo.fFinishedContext = destroyInfo;
+ flushInfo.fFinishedContext = new DestroySemaphoreInfo(mDestroySemaphore, mDevice, semaphore);
GrSemaphoresSubmitted submitted = grContext->flush(flushInfo);
grContext->submit();
if (submitted == GrSemaphoresSubmitted::kNo) {
ALOGE("VulkanManager::createReleaseFence: Failed to submit semaphore");
- destroy_semaphore(destroyInfo);
return INVALID_OPERATION;
}
@@ -781,7 +758,6 @@ status_t VulkanManager::createReleaseFence(int* nativeFence, GrDirectContext* gr
int fenceFd = 0;
err = mGetSemaphoreFdKHR(mDevice, &getFdInfo, &fenceFd);
- destroy_semaphore(destroyInfo);
if (VK_SUCCESS != err) {
ALOGE("VulkanManager::createReleaseFence: Failed to get semaphore Fd");
return INVALID_OPERATION;
diff --git a/libs/hwui/renderthread/VulkanManager.h b/libs/hwui/renderthread/VulkanManager.h
index dbef7fbd51b2..b92ebb3cdf71 100644
--- a/libs/hwui/renderthread/VulkanManager.h
+++ b/libs/hwui/renderthread/VulkanManager.h
@@ -22,6 +22,7 @@
#endif
#include <GrContextOptions.h>
#include <SkSurface.h>
+#include <android-base/unique_fd.h>
#include <utils/StrongPointer.h>
#include <vk/GrVkBackendContext.h>
#include <vk/GrVkExtensions.h>
@@ -82,10 +83,17 @@ public:
void destroySurface(VulkanSurface* surface);
Frame dequeueNextBuffer(VulkanSurface* surface);
+
+ struct VkDrawResult {
+ // The estimated start time for intiating GPU work, -1 if unknown.
+ nsecs_t submissionTime;
+ android::base::unique_fd presentFence;
+ };
+
// Finishes the frame and submits work to the GPU
- // Returns the estimated start time for intiating GPU work, -1 otherwise.
- nsecs_t finishFrame(SkSurface* surface);
- void swapBuffers(VulkanSurface* surface, const SkRect& dirtyRect);
+ VkDrawResult finishFrame(SkSurface* surface);
+ void swapBuffers(VulkanSurface* surface, const SkRect& dirtyRect,
+ android::base::unique_fd&& presentFence);
// Inserts a wait on fence command into the Vulkan command buffer.
status_t fenceWait(int fence, GrDirectContext* grContext);
@@ -201,9 +209,6 @@ private:
GrVkExtensions mExtensions;
uint32_t mDriverVersion = 0;
- VkSemaphore mSwapSemaphore = VK_NULL_HANDLE;
- void* mDestroySemaphoreContext = nullptr;
-
std::once_flag mInitFlag;
std::atomic_bool mInitialized = false;
};
diff --git a/media/java/android/media/audiopolicy/AudioVolumeGroup.java b/media/java/android/media/audiopolicy/AudioVolumeGroup.java
index 1a9ebbc56d68..d60712674990 100644
--- a/media/java/android/media/audiopolicy/AudioVolumeGroup.java
+++ b/media/java/android/media/audiopolicy/AudioVolumeGroup.java
@@ -17,6 +17,7 @@
package android.media.audiopolicy;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.media.AudioAttributes;
import android.media.AudioSystem;
@@ -107,7 +108,7 @@ public final class AudioVolumeGroup implements Parcelable {
}
@Override
- public boolean equals(@NonNull Object o) {
+ public boolean equals(@Nullable Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
diff --git a/media/jni/android_media_MediaMetricsJNI.cpp b/media/jni/android_media_MediaMetricsJNI.cpp
index 08a8d897c96e..2769dbc430ba 100644
--- a/media/jni/android_media_MediaMetricsJNI.cpp
+++ b/media/jni/android_media_MediaMetricsJNI.cpp
@@ -127,7 +127,7 @@ jobject MediaMetricsJNI::writeMetricsToBundle(
if (item->getTimestamp() > 0) {
bh.put(mediametrics::BUNDLE_TIMESTAMP, (int64_t)item->getTimestamp());
}
- if (item->getUid() != -1) {
+ if (static_cast<int32_t>(item->getUid()) != -1) {
bh.put(mediametrics::BUNDLE_UID, (int32_t)item->getUid());
}
for (const auto &prop : *item) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/Utils.java b/packages/SettingsLib/src/com/android/settingslib/Utils.java
index f0741061a051..f03263b71138 100644
--- a/packages/SettingsLib/src/com/android/settingslib/Utils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/Utils.java
@@ -23,6 +23,7 @@ import android.graphics.ColorFilter;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.drawable.Drawable;
+import android.hardware.usb.flags.Flags;
import android.hardware.usb.UsbManager;
import android.hardware.usb.UsbPort;
import android.hardware.usb.UsbPortStatus;
@@ -704,12 +705,23 @@ public class Utils {
continue;
}
for (int complianceWarningType : complianceWarnings) {
- switch (complianceWarningType) {
- case UsbPortStatus.COMPLIANCE_WARNING_OTHER:
- case UsbPortStatus.COMPLIANCE_WARNING_DEBUG_ACCESSORY:
- return true;
- default:
- break;
+ if (Flags.enableUsbDataComplianceWarning()
+ && Flags.enableInputPowerLimitedWarning()) {
+ switch (complianceWarningType) {
+ case UsbPortStatus.COMPLIANCE_WARNING_INPUT_POWER_LIMITED:
+ case UsbPortStatus.COMPLIANCE_WARNING_DEBUG_ACCESSORY:
+ return true;
+ default:
+ break;
+ }
+ } else {
+ switch (complianceWarningType) {
+ case UsbPortStatus.COMPLIANCE_WARNING_OTHER:
+ case UsbPortStatus.COMPLIANCE_WARNING_DEBUG_ACCESSORY:
+ return true;
+ default:
+ break;
+ }
}
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LeAudioProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LeAudioProfile.java
index a93524f6d873..51164e836590 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LeAudioProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LeAudioProfile.java
@@ -126,13 +126,25 @@ public class LeAudioProfile implements LocalBluetoothProfile {
}
public List<BluetoothDevice> getConnectedDevices() {
+ return getDevicesByStates(new int[] {
+ BluetoothProfile.STATE_CONNECTED,
+ BluetoothProfile.STATE_CONNECTING,
+ BluetoothProfile.STATE_DISCONNECTING});
+ }
+
+ public List<BluetoothDevice> getConnectableDevices() {
+ return getDevicesByStates(new int[] {
+ BluetoothProfile.STATE_DISCONNECTED,
+ BluetoothProfile.STATE_CONNECTED,
+ BluetoothProfile.STATE_CONNECTING,
+ BluetoothProfile.STATE_DISCONNECTING});
+ }
+
+ private List<BluetoothDevice> getDevicesByStates(int[] states) {
if (mService == null) {
- return new ArrayList<BluetoothDevice>(0);
+ return new ArrayList<>(0);
}
- return mService.getDevicesMatchingConnectionStates(
- new int[] {BluetoothProfile.STATE_CONNECTED,
- BluetoothProfile.STATE_CONNECTING,
- BluetoothProfile.STATE_DISCONNECTING});
+ return mService.getDevicesMatchingConnectionStates(states);
}
/*
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java
index 29846ac30909..a88a9c72e4a9 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java
@@ -28,6 +28,7 @@ import android.app.ActivityManager;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
+import android.hardware.usb.flags.Flags;
import android.hardware.usb.UsbManager;
import android.hardware.usb.UsbPort;
import android.hardware.usb.UsbPortStatus;
@@ -36,6 +37,7 @@ import android.media.AudioManager;
import android.os.BatteryManager;
import android.os.SystemProperties;
import android.os.UserHandle;
+import android.platform.test.flag.junit.SetFlagsRule;
import android.provider.Settings;
import android.telephony.AccessNetworkConstants;
import android.telephony.NetworkRegistrationInfo;
@@ -44,6 +46,7 @@ import android.text.TextUtils;
import org.junit.After;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentMatcher;
@@ -85,6 +88,8 @@ public class UtilsTest {
@Mock
private UsbPortStatus mUsbPortStatus;
+ @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
@@ -425,8 +430,38 @@ public class UtilsTest {
}
@Test
- public void containsIncompatibleChargers_complianeWarningOther_returnTrue() {
+ public void containsIncompatibleChargers_complianeWarningOther_returnTrue_flagDisabled() {
+ mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_USB_DATA_COMPLIANCE_WARNING);
+ mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_INPUT_POWER_LIMITED_WARNING);
setupIncompatibleCharging(UsbPortStatus.COMPLIANCE_WARNING_OTHER);
+
+ assertThat(Utils.containsIncompatibleChargers(mContext, TAG)).isTrue();
+ }
+
+ @Test
+ public void containsIncompatibleChargers_complianeWarningPower_returnFalse_flagDisabled() {
+ mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_USB_DATA_COMPLIANCE_WARNING);
+ mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_INPUT_POWER_LIMITED_WARNING);
+ setupIncompatibleCharging(UsbPortStatus.COMPLIANCE_WARNING_INPUT_POWER_LIMITED);
+
+ assertThat(Utils.containsIncompatibleChargers(mContext, TAG)).isFalse();
+ }
+
+ @Test
+ public void containsIncompatibleChargers_complianeWarningOther_returnFalse_flagEnabled() {
+ mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_USB_DATA_COMPLIANCE_WARNING);
+ mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_INPUT_POWER_LIMITED_WARNING);
+ setupIncompatibleCharging(UsbPortStatus.COMPLIANCE_WARNING_OTHER);
+
+ assertThat(Utils.containsIncompatibleChargers(mContext, TAG)).isFalse();
+ }
+
+ @Test
+ public void containsIncompatibleChargers_complianeWarningPower_returnTrue_flagEnabled() {
+ mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_USB_DATA_COMPLIANCE_WARNING);
+ mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_INPUT_POWER_LIMITED_WARNING);
+ setupIncompatibleCharging(UsbPortStatus.COMPLIANCE_WARNING_INPUT_POWER_LIMITED);
+
assertThat(Utils.containsIncompatibleChargers(mContext, TAG)).isTrue();
}
@@ -446,7 +481,6 @@ public class UtilsTest {
public void containsIncompatibleChargers_emptyComplianceWarnings_returnFalse() {
setupIncompatibleCharging();
when(mUsbPortStatus.getComplianceWarnings()).thenReturn(new int[1]);
-
assertThat(Utils.containsIncompatibleChargers(mContext, TAG)).isFalse();
}
@@ -476,7 +510,7 @@ public class UtilsTest {
}
private void setupIncompatibleCharging() {
- setupIncompatibleCharging(UsbPortStatus.COMPLIANCE_WARNING_OTHER);
+ setupIncompatibleCharging(UsbPortStatus.COMPLIANCE_WARNING_DEBUG_ACCESSORY);
}
private void setupIncompatibleCharging(int complianceWarningType) {
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java b/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java
index c2fc0d9a4d91..6ff36d43f91f 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java
@@ -235,14 +235,18 @@ public final class DeviceConfigService extends Binder {
for (String aconfigFlag : aconfigFlagNames) {
String val = allFlags.get(aconfigFlag);
if (val != null) {
+ // aconfigFlag is in the form of [namespace]/[package].[flag_name]
int idx = aconfigFlag.indexOf("/");
if (idx == -1 || idx == aconfigFlag.length() - 1 || idx == 0) {
log("invalid flag entry in device config: " + aconfigFlag);
continue;
}
- String aconfigFlagNameByPackage = aconfigFlag.substring(idx+1);
+
+ // we intend to print out [package].[flag_name] [namespace]=val
+ String aconfigFlagNameByPackage = aconfigFlag.substring(idx + 1);
String namespace = aconfigFlag.substring(0, idx);
- lines.add(aconfigFlagNameByPackage + " " + namespace + "=" + val);
+ lines.add("flag:" + aconfigFlagNameByPackage + " namespace:" + namespace +
+ " value:" + val);
}
}
Collections.sort(lines);
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt
index d668c691ee0d..defaa20a84c7 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt
@@ -25,7 +25,9 @@ import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.animation.core.snap
import androidx.compose.animation.core.tween
import androidx.compose.foundation.Canvas
+import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.Image
+import androidx.compose.foundation.combinedClickable
import androidx.compose.foundation.gestures.detectTapGestures
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
@@ -68,7 +70,6 @@ import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalLayoutDirection
-import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.DpOffset
import androidx.compose.ui.unit.LayoutDirection
@@ -77,7 +78,9 @@ import androidx.compose.ui.unit.times
import com.android.compose.PlatformButton
import com.android.compose.animation.scene.ElementKey
import com.android.compose.animation.scene.SceneScope
+import com.android.compose.modifiers.thenIf
import com.android.compose.windowsizeclass.LocalWindowSizeClass
+import com.android.systemui.bouncer.shared.model.BouncerActionButtonModel
import com.android.systemui.bouncer.ui.viewmodel.AuthMethodBouncerViewModel
import com.android.systemui.bouncer.ui.viewmodel.BouncerViewModel
import com.android.systemui.bouncer.ui.viewmodel.PasswordBouncerViewModel
@@ -195,6 +198,7 @@ private fun Bouncer(
val message: BouncerViewModel.MessageViewModel by viewModel.message.collectAsState()
val dialogMessage: String? by viewModel.throttlingDialogMessage.collectAsState()
var dialog: Dialog? by remember { mutableStateOf(null) }
+ val actionButton: BouncerActionButtonModel? by viewModel.actionButton.collectAsState()
Column(
horizontalAlignment = Alignment.CenterHorizontally,
@@ -221,21 +225,7 @@ private fun Bouncer(
)
}
- if (viewModel.isEmergencyButtonVisible) {
- Button(
- onClick = viewModel::onEmergencyServicesButtonClicked,
- colors =
- ButtonDefaults.buttonColors(
- containerColor = MaterialTheme.colorScheme.tertiaryContainer,
- contentColor = MaterialTheme.colorScheme.onTertiaryContainer,
- ),
- ) {
- Text(
- text = stringResource(com.android.internal.R.string.lockscreen_emergency_call),
- style = MaterialTheme.typography.bodyMedium,
- )
- }
- }
+ actionButton?.let { BouncerActionButton(viewModel = it) }
if (dialogMessage != null) {
if (dialog == null) {
@@ -320,6 +310,37 @@ private fun UserInputArea(
}
}
+/**
+ * Renders the action button on the bouncer, which triggers either Return to Call or Emergency Call.
+ */
+@OptIn(ExperimentalFoundationApi::class)
+@Composable
+private fun BouncerActionButton(
+ viewModel: BouncerActionButtonModel,
+ modifier: Modifier = Modifier,
+) {
+ Button(
+ onClick = viewModel.onClick,
+ modifier =
+ modifier.thenIf(viewModel.onLongClick != null) {
+ Modifier.combinedClickable(
+ onClick = viewModel.onClick,
+ onLongClick = viewModel.onLongClick,
+ )
+ },
+ colors =
+ ButtonDefaults.buttonColors(
+ containerColor = MaterialTheme.colorScheme.tertiaryContainer,
+ contentColor = MaterialTheme.colorScheme.onTertiaryContainer,
+ ),
+ ) {
+ Text(
+ text = viewModel.label,
+ style = MaterialTheme.typography.bodyMedium,
+ )
+ }
+}
+
/** Renders the UI of the user switcher that's displayed on large screens next to the bouncer UI. */
@Composable
private fun UserSwitcher(
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt
index 77b844debb42..142978284cfb 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt
@@ -25,6 +25,7 @@ import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.grid.GridItemSpan
@@ -48,6 +49,8 @@ import androidx.compose.ui.viewinterop.AndroidView
import com.android.systemui.communal.domain.model.CommunalContentModel
import com.android.systemui.communal.shared.model.CommunalContentSize
import com.android.systemui.communal.ui.viewmodel.CommunalViewModel
+import com.android.systemui.media.controls.ui.MediaHierarchyManager
+import com.android.systemui.media.controls.ui.MediaHostState
import com.android.systemui.res.R
@Composable
@@ -73,6 +76,7 @@ fun CommunalHub(
CommunalContent(
modifier = Modifier.fillMaxHeight().width(Dimensions.CardWidth),
model = communalContent[index],
+ viewModel = viewModel,
deleteOnClick = viewModel::onDeleteWidget,
size =
SizeF(
@@ -94,6 +98,7 @@ fun CommunalHub(
@Composable
private fun CommunalContent(
model: CommunalContentModel,
+ viewModel: CommunalViewModel,
size: SizeF,
deleteOnClick: (id: Int) -> Unit,
modifier: Modifier = Modifier,
@@ -102,6 +107,7 @@ private fun CommunalContent(
is CommunalContentModel.Widget -> WidgetContent(model, size, deleteOnClick, modifier)
is CommunalContentModel.Smartspace -> SmartspaceContent(model, modifier)
is CommunalContentModel.Tutorial -> TutorialContent(modifier)
+ is CommunalContentModel.Umo -> Umo(viewModel, modifier)
}
}
@@ -155,6 +161,31 @@ private fun TutorialContent(modifier: Modifier = Modifier) {
Card(modifier = modifier, content = {})
}
+@Composable
+private fun Umo(viewModel: CommunalViewModel, modifier: Modifier = Modifier) {
+ AndroidView(
+ modifier =
+ modifier
+ .width(Dimensions.CardWidth)
+ .height(Dimensions.CardHeightThird)
+ .padding(Dimensions.Spacing),
+ factory = {
+ viewModel.mediaHost.expansion = MediaHostState.EXPANDED
+ viewModel.mediaHost.showsOnlyActiveMedia = false
+ viewModel.mediaHost.falsingProtectionNeeded = false
+ viewModel.mediaHost.init(MediaHierarchyManager.LOCATION_COMMUNAL_HUB)
+ viewModel.mediaHost.hostView.layoutParams =
+ FrameLayout.LayoutParams(
+ FrameLayout.LayoutParams.MATCH_PARENT,
+ FrameLayout.LayoutParams.MATCH_PARENT
+ )
+ viewModel.mediaHost.hostView
+ },
+ // For reusing composition in lazy lists.
+ onReset = {},
+ )
+}
+
private fun CommunalContentSize.dp(): Dp {
return when (this) {
CommunalContentSize.FULL -> Dimensions.CardHeightFull
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/data/repository/EmergencyServicesRepositoryImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/data/repository/EmergencyServicesRepositoryImplTest.kt
new file mode 100644
index 000000000000..c2117ae5bda4
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/data/repository/EmergencyServicesRepositoryImplTest.kt
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2023 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.systemui.bouncer.data.repository
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.internal.R
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.scene.SceneTestUtils
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class EmergencyServicesRepositoryImplTest : SysuiTestCase() {
+
+ private val utils = SceneTestUtils(this)
+ private val testScope = utils.testScope
+
+ private lateinit var underTest: EmergencyServicesRepository
+
+ @Before
+ fun setUp() {
+ overrideResource(
+ R.bool.config_enable_emergency_call_while_sim_locked,
+ ENABLE_EMERGENCY_CALL_WHILE_SIM_LOCKED
+ )
+
+ underTest =
+ EmergencyServicesRepository(
+ resources = context.resources,
+ applicationScope = testScope.backgroundScope,
+ configurationRepository = utils.configurationRepository,
+ )
+ }
+
+ @Test
+ fun enableEmergencyCallWhileSimLocked() =
+ testScope.runTest {
+ val enableEmergencyCallWhileSimLocked by
+ collectLastValue(underTest.enableEmergencyCallWhileSimLocked)
+
+ setEmergencyCallWhileSimLocked(isEnabled = false)
+ assertThat(enableEmergencyCallWhileSimLocked).isFalse()
+
+ setEmergencyCallWhileSimLocked(isEnabled = true)
+ assertThat(enableEmergencyCallWhileSimLocked).isTrue()
+ }
+
+ private fun TestScope.setEmergencyCallWhileSimLocked(isEnabled: Boolean) {
+ overrideResource(R.bool.config_enable_emergency_call_while_sim_locked, isEnabled)
+ utils.configurationRepository.onConfigurationChange()
+ runCurrent()
+ }
+
+ companion object {
+ private const val ENABLE_EMERGENCY_CALL_WHILE_SIM_LOCKED = true
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/domain/interactor/BouncerActionButtonInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/domain/interactor/BouncerActionButtonInteractorTest.kt
new file mode 100644
index 000000000000..fde3ad723d71
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/domain/interactor/BouncerActionButtonInteractorTest.kt
@@ -0,0 +1,223 @@
+/*
+ * Copyright 2023 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.systemui.bouncer.domain.interactor
+
+import android.app.ActivityTaskManager
+import android.telecom.TelecomManager
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.internal.R
+import com.android.internal.logging.nano.MetricsProto
+import com.android.internal.logging.testing.FakeMetricsLogger
+import com.android.internal.util.EmergencyAffordanceManager
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.authentication.data.model.AuthenticationMethodModel
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.flags.Flags.REFACTOR_GETCURRENTUSER
+import com.android.systemui.log.table.TableLogBuffer
+import com.android.systemui.scene.SceneTestUtils
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionsRepository
+import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy
+import com.android.systemui.user.domain.interactor.SelectedUserInteractor
+import com.android.systemui.util.mockito.whenever
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.eq
+import org.mockito.Mock
+import org.mockito.Mockito.never
+import org.mockito.Mockito.times
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class BouncerActionButtonInteractorTest : SysuiTestCase() {
+
+ @Mock private lateinit var activityTaskManager: ActivityTaskManager
+ @Mock private lateinit var emergencyAffordanceManager: EmergencyAffordanceManager
+ @Mock private lateinit var selectedUserInteractor: SelectedUserInteractor
+ @Mock private lateinit var tableLogger: TableLogBuffer
+ @Mock private lateinit var telecomManager: TelecomManager
+
+ private val utils = SceneTestUtils(this)
+ private val testScope = utils.testScope
+ private val metricsLogger = FakeMetricsLogger()
+ private var currentUserId: Int = 0
+ private var needsEmergencyAffordance = true
+
+ private lateinit var mobileConnectionsRepository: FakeMobileConnectionsRepository
+
+ private lateinit var underTest: BouncerActionButtonInteractor
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ overrideResource(R.string.lockscreen_emergency_call, MESSAGE_EMERGENCY_CALL)
+ overrideResource(R.string.lockscreen_return_to_call, MESSAGE_RETURN_TO_CALL)
+ overrideResource(
+ R.bool.config_enable_emergency_call_while_sim_locked,
+ ENABLE_EMERGENCY_CALL_WHILE_SIM_LOCKED
+ )
+ whenever(selectedUserInteractor.getSelectedUserId()).thenReturn(currentUserId)
+ whenever(emergencyAffordanceManager.needsEmergencyAffordance())
+ .thenReturn(needsEmergencyAffordance)
+ whenever(telecomManager.isInCall).thenReturn(false)
+
+ utils.featureFlags.set(REFACTOR_GETCURRENTUSER, true)
+
+ mobileConnectionsRepository =
+ FakeMobileConnectionsRepository(FakeMobileMappingsProxy(), tableLogger)
+
+ utils.telephonyRepository.setHasTelephonyRadio(true)
+
+ underTest =
+ utils.bouncerActionButtonInteractor(
+ mobileConnectionsRepository = mobileConnectionsRepository,
+ activityTaskManager = activityTaskManager,
+ telecomManager = telecomManager,
+ emergencyAffordanceManager = emergencyAffordanceManager,
+ metricsLogger = metricsLogger,
+ )
+ }
+
+ @Test
+ fun noTelephonyRadio_noButton() =
+ testScope.runTest {
+ utils.telephonyRepository.setHasTelephonyRadio(false)
+ underTest =
+ utils.bouncerActionButtonInteractor(
+ mobileConnectionsRepository = mobileConnectionsRepository,
+ activityTaskManager = activityTaskManager,
+ telecomManager = telecomManager,
+ )
+
+ val actionButton by collectLastValue(underTest.actionButton)
+ assertThat(actionButton).isNull()
+ }
+
+ @Test
+ fun noTelecomManager_noButton() =
+ testScope.runTest {
+ underTest =
+ utils.bouncerActionButtonInteractor(
+ mobileConnectionsRepository = mobileConnectionsRepository,
+ activityTaskManager = activityTaskManager,
+ telecomManager = null,
+ )
+ val actionButton by collectLastValue(underTest.actionButton)
+ assertThat(actionButton).isNull()
+ }
+
+ @Test
+ fun duringCall_returnToCallButton() =
+ testScope.runTest {
+ val actionButton by collectLastValue(underTest.actionButton)
+ utils.telephonyRepository.setIsInCall(true)
+
+ assertThat(actionButton).isNotNull()
+ assertThat(actionButton?.label).isEqualTo(MESSAGE_RETURN_TO_CALL)
+ assertThat(actionButton?.onClick).isNotNull()
+ assertThat(actionButton?.onLongClick).isNull()
+
+ actionButton?.onClick?.invoke()
+
+ assertThat(metricsLogger.logs.size).isEqualTo(1)
+ assertThat(metricsLogger.logs.element().category)
+ .isEqualTo(MetricsProto.MetricsEvent.ACTION_EMERGENCY_CALL)
+ verify(activityTaskManager).stopSystemLockTaskMode()
+ verify(telecomManager).showInCallScreen(eq(false))
+ }
+
+ @Test
+ fun noCall_secureAuthMethod_emergencyCallButton() =
+ testScope.runTest {
+ val actionButton by collectLastValue(underTest.actionButton)
+ mobileConnectionsRepository.isAnySimSecure.value = false
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
+ utils.telephonyRepository.setIsInCall(false)
+
+ assertThat(actionButton).isNotNull()
+ assertThat(actionButton?.label).isEqualTo(MESSAGE_EMERGENCY_CALL)
+ assertThat(actionButton?.onClick).isNotNull()
+ assertThat(actionButton?.onLongClick).isNotNull()
+
+ actionButton?.onClick?.invoke()
+
+ assertThat(metricsLogger.logs.size).isEqualTo(1)
+ assertThat(metricsLogger.logs.element().category)
+ .isEqualTo(MetricsProto.MetricsEvent.ACTION_EMERGENCY_CALL)
+ verify(activityTaskManager).stopSystemLockTaskMode()
+
+ // TODO(b/25189994): Test the activity has been started once we switch to the
+ // ActivityStarter interface here.
+ verify(emergencyAffordanceManager, never()).performEmergencyCall()
+
+ actionButton?.onLongClick?.invoke()
+ verify(emergencyAffordanceManager).performEmergencyCall()
+ }
+
+ @Test
+ fun noCall_insecureAuthMethodButSecureSim_emergencyCallButton() =
+ testScope.runTest {
+ val actionButton by collectLastValue(underTest.actionButton)
+ mobileConnectionsRepository.isAnySimSecure.value = true
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.None)
+ utils.telephonyRepository.setIsInCall(false)
+
+ assertThat(actionButton).isNotNull()
+ assertThat(actionButton?.label).isEqualTo(MESSAGE_EMERGENCY_CALL)
+ assertThat(actionButton?.onClick).isNotNull()
+ assertThat(actionButton?.onLongClick).isNotNull()
+ }
+
+ @Test
+ fun noCall_insecure_noButton() =
+ testScope.runTest {
+ val actionButton by collectLastValue(underTest.actionButton)
+ mobileConnectionsRepository.isAnySimSecure.value = false
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.None)
+ utils.telephonyRepository.setIsInCall(false)
+
+ assertThat(actionButton).isNull()
+ }
+
+ @Test
+ fun noCall_simSecureButEmergencyNotSupported_noButton() =
+ testScope.runTest {
+ val actionButton by collectLastValue(underTest.actionButton)
+ mobileConnectionsRepository.isAnySimSecure.value = true
+ overrideResource(R.bool.config_enable_emergency_call_while_sim_locked, false)
+ utils.configurationRepository.onConfigurationChange()
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.None)
+ utils.telephonyRepository.setIsInCall(false)
+ runCurrent()
+
+ assertThat(actionButton).isNull()
+ }
+
+ companion object {
+ private const val MESSAGE_EMERGENCY_CALL = "Emergency"
+ private const val MESSAGE_RETURN_TO_CALL = "Return to call"
+ private const val ENABLE_EMERGENCY_CALL_WHILE_SIM_LOCKED = true
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/telephony/data/repository/TelephonyRepositoryImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/telephony/data/repository/TelephonyRepositoryImplTest.kt
index 020903057eb3..262795fe0eb6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/telephony/data/repository/TelephonyRepositoryImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/telephony/data/repository/TelephonyRepositoryImplTest.kt
@@ -17,48 +17,62 @@
package com.android.systemui.telephony.data.repository
+import android.telecom.TelecomManager
import android.telephony.TelephonyCallback
+import android.telephony.TelephonyManager
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.scene.SceneTestUtils
import com.android.systemui.telephony.TelephonyListenerManager
import com.android.systemui.util.mockito.kotlinArgumentCaptor
+import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.flow.launchIn
-import kotlinx.coroutines.flow.onEach
-import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
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.verify
import org.mockito.MockitoAnnotations
+@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
-@RunWith(JUnit4::class)
+@RunWith(AndroidJUnit4::class)
class TelephonyRepositoryImplTest : SysuiTestCase() {
@Mock private lateinit var manager: TelephonyListenerManager
+ @Mock private lateinit var telecomManager: TelecomManager
+
+ private val utils = SceneTestUtils(this)
+ private val testScope = utils.testScope
private lateinit var underTest: TelephonyRepositoryImpl
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
+ whenever(telecomManager.isInCall).thenReturn(false)
underTest =
TelephonyRepositoryImpl(
+ applicationScope = testScope.backgroundScope,
applicationContext = context,
+ backgroundDispatcher = utils.testDispatcher,
manager = manager,
+ telecomManager = telecomManager,
)
}
@Test
fun callState() =
- runBlocking(IMMEDIATE) {
- var callState: Int? = null
- val job = underTest.callState.onEach { callState = it }.launchIn(this)
+ testScope.runTest {
+ val callState by collectLastValue(underTest.callState)
+ runCurrent()
+
val listenerCaptor = kotlinArgumentCaptor<TelephonyCallback.CallStateListener>()
verify(manager).addCallStateListener(listenerCaptor.capture())
val listener = listenerCaptor.value
@@ -71,13 +85,25 @@ class TelephonyRepositoryImplTest : SysuiTestCase() {
listener.onCallStateChanged(2)
assertThat(callState).isEqualTo(2)
+ }
- job.cancel()
+ @Test
+ fun isInCall() =
+ testScope.runTest {
+ val isInCall by collectLastValue(underTest.isInCall)
+ runCurrent()
- verify(manager).removeCallStateListener(listener)
- }
+ val listenerCaptor = kotlinArgumentCaptor<TelephonyCallback.CallStateListener>()
+ verify(manager).addCallStateListener(listenerCaptor.capture())
+ val listener = listenerCaptor.value
+ whenever(telecomManager.isInCall).thenReturn(true)
+ listener.onCallStateChanged(TelephonyManager.CALL_STATE_OFFHOOK)
- companion object {
- private val IMMEDIATE = Dispatchers.Main.immediate
- }
+ assertThat(isInCall).isTrue()
+
+ whenever(telecomManager.isInCall).thenReturn(false)
+ listener.onCallStateChanged(TelephonyManager.CALL_STATE_IDLE)
+
+ assertThat(isInCall).isFalse()
+ }
}
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 9a3c6d5b322f..8780f58743cd 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -3266,9 +3266,4 @@
<string name="privacy_dialog_active_app_usage_2">In use by <xliff:g id="app_name" example="Gmail">%1$s</xliff:g> (<xliff:g id="attribution_label" example="For Wallet">%2$s</xliff:g> \u2022 <xliff:g id="proxy_label" example="Speech services">%3$s</xliff:g>)</string>
<!-- Label for recent app usage of a phone sensor with sub-attribution and proxy label in the privacy dialog [CHAR LIMIT=NONE] -->
<string name="privacy_dialog_recent_app_usage_2">Recently used by <xliff:g id="app_name" example="Gmail">%1$s</xliff:g> (<xliff:g id="attribution_label" example="For Wallet">%2$s</xliff:g> \u2022 <xliff:g id="proxy_label" example="Speech services">%3$s</xliff:g>)</string>
-
- <!-- Content description for keyboard backlight brightness dialog [CHAR LIMIT=NONE] -->
- <string name="keyboard_backlight_dialog_title">Keyboard backlight</string>
- <!-- Content description for keyboard backlight brightness value [CHAR LIMIT=NONE] -->
- <string name="keyboard_backlight_value">Level %1$d of %2$d</string>
</resources>
diff --git a/packages/SystemUI/src/com/android/keyguard/EmergencyButtonController.java b/packages/SystemUI/src/com/android/keyguard/EmergencyButtonController.java
index 5de370f22eb8..77338410642c 100644
--- a/packages/SystemUI/src/com/android/keyguard/EmergencyButtonController.java
+++ b/packages/SystemUI/src/com/android/keyguard/EmergencyButtonController.java
@@ -28,7 +28,6 @@ import android.os.PowerManager;
import android.os.SystemClock;
import android.os.UserHandle;
import android.telecom.TelecomManager;
-import android.telephony.TelephonyManager;
import android.util.Log;
import androidx.annotation.Nullable;
@@ -54,21 +53,20 @@ import javax.inject.Inject;
/** View Controller for {@link com.android.keyguard.EmergencyButton}. */
@KeyguardBouncerScope
public class EmergencyButtonController extends ViewController<EmergencyButton> {
- static final String LOG_TAG = "EmergencyButton";
+ private static final String TAG = "EmergencyButton";
private final ConfigurationController mConfigurationController;
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
- private final TelephonyManager mTelephonyManager;
private final PowerManager mPowerManager;
private final ActivityTaskManager mActivityTaskManager;
- private ShadeController mShadeController;
+ private final ShadeController mShadeController;
private final TelecomManager mTelecomManager;
private final MetricsLogger mMetricsLogger;
private EmergencyButtonCallback mEmergencyButtonCallback;
- private LockPatternUtils mLockPatternUtils;
- private Executor mMainExecutor;
- private Executor mBackgroundExecutor;
- private SelectedUserInteractor mSelectedUserInteractor;
+ private final LockPatternUtils mLockPatternUtils;
+ private final Executor mMainExecutor;
+ private final Executor mBackgroundExecutor;
+ private final SelectedUserInteractor mSelectedUserInteractor;
private final KeyguardUpdateMonitorCallback mInfoCallback =
new KeyguardUpdateMonitorCallback() {
@@ -93,17 +91,18 @@ public class EmergencyButtonController extends ViewController<EmergencyButton> {
@VisibleForTesting
public EmergencyButtonController(@Nullable EmergencyButton view,
ConfigurationController configurationController,
- KeyguardUpdateMonitor keyguardUpdateMonitor, TelephonyManager telephonyManager,
- PowerManager powerManager, ActivityTaskManager activityTaskManager,
+ KeyguardUpdateMonitor keyguardUpdateMonitor,
+ PowerManager powerManager,
+ ActivityTaskManager activityTaskManager,
ShadeController shadeController,
- @Nullable TelecomManager telecomManager, MetricsLogger metricsLogger,
+ @Nullable TelecomManager telecomManager,
+ MetricsLogger metricsLogger,
LockPatternUtils lockPatternUtils,
Executor mainExecutor, Executor backgroundExecutor,
SelectedUserInteractor selectedUserInteractor) {
super(view);
mConfigurationController = configurationController;
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
- mTelephonyManager = telephonyManager;
mPowerManager = powerManager;
mActivityTaskManager = activityTaskManager;
mShadeController = shadeController;
@@ -183,7 +182,7 @@ public class EmergencyButtonController extends ViewController<EmergencyButton> {
} else {
mKeyguardUpdateMonitor.reportEmergencyCallAction(true /* bypassHandler */);
if (mTelecomManager == null) {
- Log.wtf(LOG_TAG, "TelecomManager was null, cannot launch emergency dialer");
+ Log.wtf(TAG, "TelecomManager was null, cannot launch emergency dialer");
return;
}
Intent emergencyDialIntent =
@@ -212,10 +211,9 @@ public class EmergencyButtonController extends ViewController<EmergencyButton> {
public static class Factory {
private final ConfigurationController mConfigurationController;
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
- private final TelephonyManager mTelephonyManager;
private final PowerManager mPowerManager;
private final ActivityTaskManager mActivityTaskManager;
- private ShadeController mShadeController;
+ private final ShadeController mShadeController;
@Nullable
private final TelecomManager mTelecomManager;
private final MetricsLogger mMetricsLogger;
@@ -226,10 +224,12 @@ public class EmergencyButtonController extends ViewController<EmergencyButton> {
@Inject
public Factory(ConfigurationController configurationController,
- KeyguardUpdateMonitor keyguardUpdateMonitor, TelephonyManager telephonyManager,
- PowerManager powerManager, ActivityTaskManager activityTaskManager,
+ KeyguardUpdateMonitor keyguardUpdateMonitor,
+ PowerManager powerManager,
+ ActivityTaskManager activityTaskManager,
ShadeController shadeController,
- @Nullable TelecomManager telecomManager, MetricsLogger metricsLogger,
+ @Nullable TelecomManager telecomManager,
+ MetricsLogger metricsLogger,
LockPatternUtils lockPatternUtils,
@Main Executor mainExecutor,
@Background Executor backgroundExecutor,
@@ -237,7 +237,6 @@ public class EmergencyButtonController extends ViewController<EmergencyButton> {
mConfigurationController = configurationController;
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
- mTelephonyManager = telephonyManager;
mPowerManager = powerManager;
mActivityTaskManager = activityTaskManager;
mShadeController = shadeController;
@@ -252,9 +251,9 @@ public class EmergencyButtonController extends ViewController<EmergencyButton> {
/** Construct an {@link com.android.keyguard.EmergencyButtonController}. */
public EmergencyButtonController create(EmergencyButton view) {
return new EmergencyButtonController(view, mConfigurationController,
- mKeyguardUpdateMonitor, mTelephonyManager, mPowerManager, mActivityTaskManager,
- mShadeController, mTelecomManager, mMetricsLogger, mLockPatternUtils,
- mMainExecutor, mBackgroundExecutor, mSelectedUserInteractor);
+ mKeyguardUpdateMonitor, mPowerManager, mActivityTaskManager, mShadeController,
+ mTelecomManager, mMetricsLogger, mLockPatternUtils, mMainExecutor,
+ mBackgroundExecutor, mSelectedUserInteractor);
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/data/repository/EmergencyServicesRepository.kt b/packages/SystemUI/src/com/android/systemui/bouncer/data/repository/EmergencyServicesRepository.kt
new file mode 100644
index 000000000000..bba00506df85
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/data/repository/EmergencyServicesRepository.kt
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2023 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.systemui.bouncer.data.repository
+
+import android.content.res.Resources
+import com.android.internal.R
+import com.android.systemui.common.ui.data.repository.ConfigurationRepository
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.Main
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.stateIn
+
+/** Encapsulates Emergency Services related state. */
+@SysUISingleton
+class EmergencyServicesRepository
+@Inject
+constructor(
+ @Application private val applicationScope: CoroutineScope,
+ @Main private val resources: Resources,
+ configurationRepository: ConfigurationRepository,
+) {
+ /**
+ * Whether to enable emergency services calls while the SIM card is locked. This is disabled in
+ * certain countries that don't support this.
+ */
+ val enableEmergencyCallWhileSimLocked: StateFlow<Boolean> =
+ configurationRepository.onConfigurationChange
+ .map { getEnableEmergencyCallWhileSimLocked() }
+ .stateIn(
+ scope = applicationScope,
+ started = SharingStarted.Eagerly,
+ initialValue = getEnableEmergencyCallWhileSimLocked()
+ )
+
+ private fun getEnableEmergencyCallWhileSimLocked(): Boolean {
+ return resources.getBoolean(R.bool.config_enable_emergency_call_while_sim_locked)
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerActionButtonInteractor.kt b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerActionButtonInteractor.kt
new file mode 100644
index 000000000000..f36ef6630a48
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerActionButtonInteractor.kt
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2023 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.systemui.bouncer.domain.interactor
+
+import android.annotation.SuppressLint
+import android.app.ActivityOptions
+import android.app.ActivityTaskManager
+import android.content.Context
+import android.content.Intent
+import android.os.UserHandle
+import android.telecom.TelecomManager
+import com.android.internal.R
+import com.android.internal.logging.MetricsLogger
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent
+import com.android.internal.util.EmergencyAffordanceManager
+import com.android.systemui.authentication.domain.interactor.AuthenticationInteractor
+import com.android.systemui.bouncer.data.repository.EmergencyServicesRepository
+import com.android.systemui.bouncer.shared.model.BouncerActionButtonModel
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.doze.DozeLogger
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionsRepository
+import com.android.systemui.telephony.domain.interactor.TelephonyInteractor
+import com.android.systemui.user.domain.interactor.SelectedUserInteractor
+import com.android.systemui.util.EmergencyDialerConstants
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.merge
+import kotlinx.coroutines.withContext
+
+/**
+ * Encapsulates business logic and application state for the bouncer action button. The action
+ * button can support multiple different actions, depending on device state.
+ */
+@SysUISingleton
+class BouncerActionButtonInteractor
+@Inject
+constructor(
+ @Application private val applicationContext: Context,
+ @Background private val backgroundDispatcher: CoroutineDispatcher,
+ private val repository: EmergencyServicesRepository,
+ // TODO(b/307977401): Replace with `MobileConnectionsInteractor` when available.
+ private val mobileConnectionsRepository: MobileConnectionsRepository,
+ private val telephonyInteractor: TelephonyInteractor,
+ private val authenticationInteractor: AuthenticationInteractor,
+ private val selectedUserInteractor: SelectedUserInteractor,
+ private val activityTaskManager: ActivityTaskManager,
+ private val telecomManager: TelecomManager?,
+ private val emergencyAffordanceManager: EmergencyAffordanceManager,
+ private val emergencyDialerIntentFactory: EmergencyDialerIntentFactory,
+ private val metricsLogger: MetricsLogger,
+ private val dozeLogger: DozeLogger,
+) {
+ /** The bouncer action button. If `null`, the button should not be shown. */
+ val actionButton: Flow<BouncerActionButtonModel?> =
+ if (telecomManager == null || !telephonyInteractor.hasTelephonyRadio) {
+ flowOf(null)
+ } else {
+ merge(
+ telephonyInteractor.isInCall.asUnitFlow,
+ mobileConnectionsRepository.isAnySimSecure.asUnitFlow,
+ authenticationInteractor.authenticationMethod.asUnitFlow,
+ repository.enableEmergencyCallWhileSimLocked.asUnitFlow,
+ )
+ .map {
+ when {
+ isReturnToCallButton() -> returnToCallButtonModel
+ isEmergencyCallButton() -> emergencyCallButtonModel
+ else -> null // Do not show the button.
+ }
+ }
+ .distinctUntilChanged()
+ }
+
+ private val returnToCallButtonModel: BouncerActionButtonModel by lazy {
+ BouncerActionButtonModel(
+ label = applicationContext.getString(R.string.lockscreen_return_to_call),
+ onClick = {
+ prepareToPerformAction()
+ returnToCall()
+ },
+ onLongClick = null
+ )
+ }
+
+ private val emergencyCallButtonModel: BouncerActionButtonModel by lazy {
+ BouncerActionButtonModel(
+ label = applicationContext.getString(R.string.lockscreen_emergency_call),
+ onClick = {
+ prepareToPerformAction()
+ dozeLogger.logEmergencyCall()
+ startEmergencyDialerActivity()
+ },
+ // TODO(b/308001302): The long click detector doesn't work properly, investigate.
+ onLongClick = {
+ if (emergencyAffordanceManager.needsEmergencyAffordance()) {
+ prepareToPerformAction()
+
+ // TODO(b/298026988): Check that !longPressWasDragged before invoking.
+ emergencyAffordanceManager.performEmergencyCall()
+ }
+ }
+ )
+ }
+
+ private fun startEmergencyDialerActivity() {
+ emergencyDialerIntentFactory()?.apply {
+ flags =
+ Intent.FLAG_ACTIVITY_NEW_TASK or
+ Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS or
+ Intent.FLAG_ACTIVITY_CLEAR_TOP
+
+ putExtra(
+ EmergencyDialerConstants.EXTRA_ENTRY_TYPE,
+ EmergencyDialerConstants.ENTRY_TYPE_LOCKSCREEN_BUTTON,
+ )
+
+ // TODO(b/25189994): Use the ActivityStarter interface instead.
+ applicationContext.startActivityAsUser(
+ this,
+ ActivityOptions.makeCustomAnimation(applicationContext, 0, 0).toBundle(),
+ UserHandle(selectedUserInteractor.getSelectedUserId())
+ )
+ }
+ }
+
+ private fun isReturnToCallButton() = telephonyInteractor.isInCall.value
+
+ private suspend fun isEmergencyCallButton(): Boolean {
+ return if (mobileConnectionsRepository.getIsAnySimSecure()) {
+ // Some countries can't handle emergency calls while SIM is locked.
+ repository.enableEmergencyCallWhileSimLocked.value
+ } else {
+ // Only show if there is a secure screen (password/pin/pattern/SIM pin/SIM puk).
+ withContext(backgroundDispatcher) {
+ authenticationInteractor.getAuthenticationMethod().isSecure
+ }
+ }
+ }
+
+ private fun prepareToPerformAction() {
+ // TODO(b/308001302): Trigger occlusion and resetting bouncer state.
+ metricsLogger.action(MetricsEvent.ACTION_EMERGENCY_CALL)
+ activityTaskManager.stopSystemLockTaskMode()
+ }
+
+ @SuppressLint("MissingPermission")
+ private fun returnToCall() {
+ telecomManager?.showInCallScreen(/* showDialpad = */ false)
+ }
+
+ private val <T> Flow<T>.asUnitFlow: Flow<Unit>
+ get() = map {}
+}
+
+/**
+ * Creates an intent to launch the Emergency Services dialer. If no [TelecomManager] is present,
+ * returns `null`.
+ */
+interface EmergencyDialerIntentFactory {
+ operator fun invoke(): Intent?
+}
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractorModule.kt b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractorModule.kt
new file mode 100644
index 000000000000..e398c930e86e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractorModule.kt
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2023 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.systemui.bouncer.domain.interactor
+
+import android.content.Context
+import android.content.Intent
+import android.telecom.TelecomManager
+import com.android.internal.util.EmergencyAffordanceManager
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import dagger.Module
+import dagger.Provides
+
+/** Module for providing interactor-related objects for the bouncer. */
+@Module
+object BouncerInteractorModule {
+
+ @Provides
+ fun emergencyDialerIntentFactory(
+ telecomManager: TelecomManager?
+ ): EmergencyDialerIntentFactory {
+ return object : EmergencyDialerIntentFactory {
+ override fun invoke(): Intent? {
+ return telecomManager?.createLaunchEmergencyDialerIntent(/* number = */ null)
+ }
+ }
+ }
+
+ @Provides
+ @SysUISingleton
+ fun emergencyAffordanceManager(
+ @Application applicationContext: Context,
+ ): EmergencyAffordanceManager {
+ return EmergencyAffordanceManager(applicationContext)
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/shared/model/BouncerActionButtonModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/shared/model/BouncerActionButtonModel.kt
new file mode 100644
index 000000000000..7f1730cb2abd
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/shared/model/BouncerActionButtonModel.kt
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2023 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.systemui.bouncer.shared.model
+
+/** Models the action button on the bouncer. */
+data class BouncerActionButtonModel(
+ /** The text to be shown on the button. */
+ val label: String,
+
+ /** The action to perform when the user clicks on the button. */
+ val onClick: () -> Unit,
+
+ /**
+ * The action to perform when the user long-clicks on the button. When not provided, long-clicks
+ * will be treated as regular clicks.
+ */
+ val onLongClick: (() -> Unit)? = null,
+)
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModel.kt
index ef0609a99e05..0f7772454b78 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModel.kt
@@ -21,14 +21,15 @@ import android.graphics.Bitmap
import androidx.core.graphics.drawable.toBitmap
import com.android.systemui.authentication.domain.interactor.AuthenticationInteractor
import com.android.systemui.authentication.domain.model.AuthenticationMethodModel
+import com.android.systemui.bouncer.domain.interactor.BouncerActionButtonInteractor
import com.android.systemui.bouncer.domain.interactor.BouncerInteractor
+import com.android.systemui.bouncer.shared.model.BouncerActionButtonModel
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.common.shared.model.Text
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.scene.shared.flag.SceneContainerFlags
-import com.android.systemui.telephony.domain.interactor.TelephonyInteractor
import com.android.systemui.user.ui.viewmodel.UserActionViewModel
import com.android.systemui.user.ui.viewmodel.UserSwitcherViewModel
import com.android.systemui.user.ui.viewmodel.UserViewModel
@@ -59,10 +60,10 @@ class BouncerViewModel(
private val bouncerInteractor: BouncerInteractor,
authenticationInteractor: AuthenticationInteractor,
flags: SceneContainerFlags,
- private val telephonyInteractor: TelephonyInteractor,
selectedUser: Flow<UserViewModel>,
users: Flow<List<UserViewModel>>,
userSwitcherMenu: Flow<List<UserActionViewModel>>,
+ actionButtonInteractor: BouncerActionButtonInteractor,
) {
val selectedUserImage: StateFlow<Bitmap?> =
selectedUser
@@ -150,8 +151,16 @@ class BouncerViewModel(
),
)
- val isEmergencyButtonVisible: Boolean
- get() = telephonyInteractor.hasTelephonyRadio
+ /**
+ * The bouncer action button (Return to Call / Emergency Call). If `null`, the button should not
+ * be shown.
+ */
+ val actionButton: StateFlow<BouncerActionButtonModel?> =
+ actionButtonInteractor.actionButton.stateIn(
+ scope = applicationScope,
+ started = SharingStarted.WhileSubscribed(),
+ initialValue = null
+ )
init {
if (flags.isEnabled()) {
@@ -176,11 +185,6 @@ class BouncerViewModel(
}
}
- /** Notifies that the emergency services button was clicked. */
- fun onEmergencyServicesButtonClicked() {
- // TODO(b/280877228): implement this
- }
-
/** Notifies that a throttling dialog has been dismissed by the user. */
fun onThrottlingDialogDismissed() {
_throttlingDialogMessage.value = null
@@ -271,8 +275,8 @@ object BouncerViewModelModule {
bouncerInteractor: BouncerInteractor,
authenticationInteractor: AuthenticationInteractor,
flags: SceneContainerFlags,
- telephonyInteractor: TelephonyInteractor,
userSwitcherViewModel: UserSwitcherViewModel,
+ actionButtonInteractor: BouncerActionButtonInteractor,
): BouncerViewModel {
return BouncerViewModel(
applicationContext = applicationContext,
@@ -281,10 +285,10 @@ object BouncerViewModelModule {
bouncerInteractor = bouncerInteractor,
authenticationInteractor = authenticationInteractor,
flags = flags,
- telephonyInteractor = telephonyInteractor,
selectedUser = userSwitcherViewModel.selectedUser,
users = userSwitcherViewModel.users,
userSwitcherMenu = userSwitcherViewModel.menu,
+ actionButtonInteractor = actionButtonInteractor,
)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/common/ui/data/repository/ConfigurationRepository.kt b/packages/SystemUI/src/com/android/systemui/common/ui/data/repository/ConfigurationRepository.kt
index e44927432719..7fa762a6614f 100644
--- a/packages/SystemUI/src/com/android/systemui/common/ui/data/repository/ConfigurationRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/common/ui/data/repository/ConfigurationRepository.kt
@@ -44,11 +44,15 @@ import kotlinx.coroutines.flow.stateIn
interface ConfigurationRepository {
/** Called whenever ui mode, theme or configuration has changed. */
val onAnyConfigurationChange: Flow<Unit>
+
+ /** Called whenever the configuration has changed. */
+ val onConfigurationChange: Flow<Unit>
+
val scaleForResolution: Flow<Float>
fun getResolutionScale(): Float
- /** Convience to context.resources.getDimensionPixelSize() */
+ /** Convenience to context.resources.getDimensionPixelSize() */
fun getDimensionPixelSize(id: Int): Int
}
@@ -87,7 +91,7 @@ constructor(
awaitClose { configurationController.removeCallback(callback) }
}
- private val configurationChange: Flow<Unit> =
+ override val onConfigurationChange: Flow<Unit> =
ConflatedCallbackFlow.conflatedCallbackFlow {
val callback =
object : ConfigurationController.ConfigurationListener {
@@ -100,7 +104,7 @@ constructor(
}
override val scaleForResolution: StateFlow<Float> =
- configurationChange
+ onConfigurationChange
.mapLatest { getResolutionScale() }
.distinctUntilChanged()
.stateIn(scope, SharingStarted.WhileSubscribed(), getResolutionScale())
diff --git a/packages/SystemUI/src/com/android/systemui/communal/dagger/CommunalModule.kt b/packages/SystemUI/src/com/android/systemui/communal/dagger/CommunalModule.kt
index c3421de8f663..273adcf83271 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/dagger/CommunalModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/dagger/CommunalModule.kt
@@ -17,6 +17,7 @@
package com.android.systemui.communal.dagger
import com.android.systemui.communal.data.db.CommunalDatabaseModule
+import com.android.systemui.communal.data.repository.CommunalMediaRepositoryModule
import com.android.systemui.communal.data.repository.CommunalRepositoryModule
import com.android.systemui.communal.data.repository.CommunalTutorialRepositoryModule
import com.android.systemui.communal.data.repository.CommunalWidgetRepositoryModule
@@ -26,6 +27,7 @@ import dagger.Module
includes =
[
CommunalRepositoryModule::class,
+ CommunalMediaRepositoryModule::class,
CommunalTutorialRepositoryModule::class,
CommunalWidgetRepositoryModule::class,
CommunalDatabaseModule::class,
diff --git a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalMediaRepository.kt b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalMediaRepository.kt
new file mode 100644
index 000000000000..e41c32261c11
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalMediaRepository.kt
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2023 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.systemui.communal.data.repository
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.media.controls.models.player.MediaData
+import com.android.systemui.media.controls.pipeline.MediaDataManager
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.onCompletion
+import kotlinx.coroutines.flow.onStart
+
+/** Encapsulates the state of smartspace in communal. */
+interface CommunalMediaRepository {
+ val mediaPlaying: Flow<Boolean>
+}
+
+@SysUISingleton
+class CommunalMediaRepositoryImpl
+@Inject
+constructor(
+ private val mediaDataManager: MediaDataManager,
+) : CommunalMediaRepository {
+
+ private val mediaDataListener =
+ object : MediaDataManager.Listener {
+ override fun onMediaDataLoaded(
+ key: String,
+ oldKey: String?,
+ data: MediaData,
+ immediately: Boolean,
+ receivedSmartspaceCardLatency: Int,
+ isSsReactivated: Boolean
+ ) {
+ if (!mediaDataManager.hasAnyMediaOrRecommendation()) {
+ return
+ }
+ _mediaPlaying.value = true
+ }
+
+ override fun onMediaDataRemoved(key: String) {
+ if (mediaDataManager.hasAnyMediaOrRecommendation()) {
+ return
+ }
+ _mediaPlaying.value = false
+ }
+ }
+
+ private val _mediaPlaying: MutableStateFlow<Boolean> = MutableStateFlow(false)
+
+ override val mediaPlaying: Flow<Boolean> =
+ _mediaPlaying
+ .onStart {
+ mediaDataManager.addListener(mediaDataListener)
+ _mediaPlaying.value = mediaDataManager.hasAnyMediaOrRecommendation()
+ }
+ .onCompletion { mediaDataManager.removeListener(mediaDataListener) }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalMediaRepositoryModule.kt b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalMediaRepositoryModule.kt
new file mode 100644
index 000000000000..2c6d9e4c39c3
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalMediaRepositoryModule.kt
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2023 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.systemui.communal.data.repository
+
+import dagger.Binds
+import dagger.Module
+
+@Module
+interface CommunalMediaRepositoryModule {
+ @Binds fun communalMediaRepository(impl: CommunalMediaRepositoryImpl): CommunalMediaRepository
+}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt
index 524cccf4017d..eb36b19972f9 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt
@@ -19,6 +19,7 @@ package com.android.systemui.communal.domain.interactor
import android.app.smartspace.SmartspaceTarget
import android.appwidget.AppWidgetHost
import android.content.ComponentName
+import com.android.systemui.communal.data.repository.CommunalMediaRepository
import com.android.systemui.communal.data.repository.CommunalRepository
import com.android.systemui.communal.data.repository.CommunalWidgetRepository
import com.android.systemui.communal.domain.model.CommunalContentModel
@@ -37,12 +38,14 @@ import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
/** Encapsulates business-logic related to communal mode. */
+@OptIn(ExperimentalCoroutinesApi::class)
@SysUISingleton
class CommunalInteractor
@Inject
constructor(
private val communalRepository: CommunalRepository,
private val widgetRepository: CommunalWidgetRepository,
+ mediaRepository: CommunalMediaRepository,
smartspaceRepository: SmartspaceRepository,
tutorialInteractor: CommunalTutorialInteractor,
private val appWidgetHost: AppWidgetHost,
@@ -87,8 +90,8 @@ constructor(
if (isTutorialMode) {
return@flatMapLatest flowOf(tutorialContent)
}
- combine(smartspaceContent, widgetContent) { smartspace, widgets ->
- smartspace + widgets
+ combine(smartspaceContent, umoContent, widgetContent) { smartspace, umo, widgets ->
+ smartspace + umo + widgets
}
}
@@ -138,4 +141,13 @@ constructor(
CommunalContentModel.Tutorial(id = 6, CommunalContentSize.HALF),
CommunalContentModel.Tutorial(id = 7, CommunalContentSize.HALF),
)
+
+ private val umoContent: Flow<List<CommunalContentModel.Umo>> =
+ mediaRepository.mediaPlaying.flatMapLatest { mediaPlaying ->
+ if (mediaPlaying) {
+ flowOf(listOf(CommunalContentModel.Umo(CommunalContentSize.THIRD)))
+ } else {
+ flowOf(emptyList())
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/model/CommunalContentModel.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/model/CommunalContentModel.kt
index 69382a5a5552..bb9b4b5f522f 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/domain/model/CommunalContentModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/domain/model/CommunalContentModel.kt
@@ -53,4 +53,15 @@ sealed interface CommunalContentModel {
) : CommunalContentModel {
override val key = "smartspace_$smartspaceTargetId"
}
+
+ class Umo(
+ override val size: CommunalContentSize,
+ ) : CommunalContentModel {
+ override val key = UMO_KEY
+ }
+
+ companion object {
+ /** Key for the [Umo] in CommunalContentModel. There should only ever be one UMO. */
+ const val UMO_KEY = "umo"
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt
index 3df6e7e781b6..5efe6ceeb65a 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt
@@ -21,7 +21,10 @@ import com.android.systemui.communal.domain.interactor.CommunalInteractor
import com.android.systemui.communal.domain.model.CommunalContentModel
import com.android.systemui.communal.shared.model.CommunalSceneKey
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.media.controls.ui.MediaHost
+import com.android.systemui.media.dagger.MediaModule
import javax.inject.Inject
+import javax.inject.Named
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.StateFlow
@@ -30,6 +33,7 @@ class CommunalViewModel
@Inject
constructor(
private val communalInteractor: CommunalInteractor,
+ @Named(MediaModule.COMMUNAL_HUB) val mediaHost: MediaHost,
) {
val currentScene: StateFlow<CommunalSceneKey> = communalInteractor.desiredScene
fun onSceneChanged(scene: CommunalSceneKey) {
diff --git a/packages/SystemUI/src/com/android/systemui/complication/SmartSpaceComplication.java b/packages/SystemUI/src/com/android/systemui/complication/SmartSpaceComplication.java
index b98794ef8026..9bb23d8564e4 100644
--- a/packages/SystemUI/src/com/android/systemui/complication/SmartSpaceComplication.java
+++ b/packages/SystemUI/src/com/android/systemui/complication/SmartSpaceComplication.java
@@ -71,6 +71,18 @@ public class SmartSpaceComplication implements Complication {
private final DreamOverlayStateController mDreamOverlayStateController;
private final SmartSpaceComplication mComplication;
private final FeatureFlags mFeatureFlags;
+ private final DreamOverlayStateController.Callback mStateControllerCallback =
+ new DreamOverlayStateController.Callback() {
+ @Override
+ public void onStateChanged() {
+ if (mDreamOverlayStateController.isOverlayActive()) {
+ mSmartSpaceController.addListener(mSmartspaceListener);
+ } else {
+ mSmartSpaceController.removeListener(mSmartspaceListener);
+ mDreamOverlayStateController.removeComplication(mComplication);
+ }
+ }
+ };
private final BcSmartspaceDataPlugin.SmartspaceTargetListener mSmartspaceListener =
new BcSmartspaceDataPlugin.SmartspaceTargetListener() {
@@ -103,17 +115,7 @@ public class SmartSpaceComplication implements Complication {
return;
}
- mDreamOverlayStateController.addCallback(new DreamOverlayStateController.Callback() {
- @Override
- public void onStateChanged() {
- if (mDreamOverlayStateController.isOverlayActive()) {
- mSmartSpaceController.addListener(mSmartspaceListener);
- } else {
- mSmartSpaceController.removeListener(mSmartspaceListener);
- mDreamOverlayStateController.removeComplication(mComplication);
- }
- }
- });
+ mDreamOverlayStateController.addCallback(mStateControllerCallback);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index 58dcf0691687..b34b4599cf70 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -37,6 +37,7 @@ import com.android.systemui.biometrics.FingerprintReEnrollNotification;
import com.android.systemui.biometrics.UdfpsDisplayModeProvider;
import com.android.systemui.biometrics.dagger.BiometricsModule;
import com.android.systemui.biometrics.domain.BiometricsDomainLayerModule;
+import com.android.systemui.bouncer.domain.interactor.BouncerInteractorModule;
import com.android.systemui.bouncer.ui.BouncerViewModule;
import com.android.systemui.classifier.FalsingModule;
import com.android.systemui.clipboardoverlay.dagger.ClipboardOverlayModule;
@@ -129,6 +130,7 @@ import com.android.systemui.user.domain.UserDomainLayerModule;
import com.android.systemui.util.concurrency.SysUIConcurrencyModule;
import com.android.systemui.util.dagger.UtilModule;
import com.android.systemui.util.kotlin.CoroutinesModule;
+import com.android.systemui.util.reference.ReferenceModule;
import com.android.systemui.util.sensors.SensorModule;
import com.android.systemui.util.settings.SettingsUtilModule;
import com.android.systemui.util.time.SystemClock;
@@ -166,6 +168,7 @@ import javax.inject.Named;
AuthenticationModule.class,
BiometricsModule.class,
BiometricsDomainLayerModule.class,
+ BouncerInteractorModule.class,
BouncerViewModule.class,
ClipboardOverlayModule.class,
ClockRegistryModule.class,
@@ -199,6 +202,7 @@ import javax.inject.Named;
PrivacyModule.class,
QRCodeScannerModule.class,
QSFragmentStartableModule.class,
+ ReferenceModule.class,
RetailModeModule.class,
ScreenshotModule.class,
SensorModule.class,
diff --git a/packages/SystemUI/src/com/android/systemui/display/domain/interactor/ConnectedDisplayInteractor.kt b/packages/SystemUI/src/com/android/systemui/display/domain/interactor/ConnectedDisplayInteractor.kt
index cf868856c419..20a9e5d572c9 100644
--- a/packages/SystemUI/src/com/android/systemui/display/domain/interactor/ConnectedDisplayInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/display/domain/interactor/ConnectedDisplayInteractor.kt
@@ -20,15 +20,18 @@ import android.companion.virtual.VirtualDeviceManager
import android.companion.virtual.flags.Flags
import android.view.Display
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.display.data.repository.DisplayRepository
import com.android.systemui.display.domain.interactor.ConnectedDisplayInteractor.PendingDisplay
import com.android.systemui.display.domain.interactor.ConnectedDisplayInteractor.State
import com.android.systemui.keyguard.data.repository.KeyguardRepository
import javax.inject.Inject
+import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filter
+import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
/** Provides information about an external connected display. */
@@ -81,6 +84,7 @@ constructor(
private val virtualDeviceManager: VirtualDeviceManager,
keyguardRepository: KeyguardRepository,
displayRepository: DisplayRepository,
+ @Background backgroundCoroutineDispatcher: CoroutineDispatcher,
) : ConnectedDisplayInteractor {
override val connectedDisplayState: Flow<State> =
@@ -101,6 +105,7 @@ constructor(
State.CONNECTED
}
}
+ .flowOn(backgroundCoroutineDispatcher)
.distinctUntilChanged()
override val connectedDisplayAddition: Flow<Unit> =
@@ -108,6 +113,7 @@ constructor(
.filter {
it != null && (isExternalDisplay(it) || isVirtualDeviceOwnedMirrorDisplay(it))
}
+ .flowOn(backgroundCoroutineDispatcher)
.map {} // map to Unit
// Provides the pending display only if the lockscreen is unlocked
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStateController.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStateController.java
index c9748f954670..0e333f21dd14 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStateController.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStateController.java
@@ -31,11 +31,15 @@ import com.android.systemui.flags.Flags;
import com.android.systemui.log.LogBuffer;
import com.android.systemui.log.dagger.DreamLog;
import com.android.systemui.statusbar.policy.CallbackController;
+import com.android.systemui.util.annotations.WeaklyReferencedCallback;
+import com.android.systemui.util.reference.WeakReferenceFactory;
+import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
+import java.util.Iterator;
import java.util.Objects;
import java.util.concurrent.Executor;
import java.util.function.Consumer;
@@ -68,7 +72,10 @@ public class DreamOverlayStateController implements
/**
* Callback for dream overlay events.
+ * NOTE: Caller should maintain a strong reference to this themselves so the callback does
+ * not get garbage collected.
*/
+ @WeaklyReferencedCallback
public interface Callback {
/**
* Called when the composition of complications changes.
@@ -97,7 +104,7 @@ public class DreamOverlayStateController implements
private final Executor mExecutor;
private final boolean mOverlayEnabled;
- private final ArrayList<Callback> mCallbacks = new ArrayList<>();
+ private final ArrayList<WeakReference<Callback>> mCallbacks = new ArrayList<>();
@Complication.ComplicationType
private int mAvailableComplicationTypes = Complication.COMPLICATION_TYPE_NONE;
@@ -107,6 +114,7 @@ public class DreamOverlayStateController implements
private final Collection<Complication> mComplications = new HashSet();
private final FeatureFlags mFeatureFlags;
+ private final WeakReferenceFactory mWeakReferenceFactory;
private final int mSupportedTypes;
@@ -117,11 +125,13 @@ public class DreamOverlayStateController implements
public DreamOverlayStateController(@Main Executor executor,
@Named(DREAM_OVERLAY_ENABLED) boolean overlayEnabled,
FeatureFlags featureFlags,
- @DreamLog LogBuffer logBuffer) {
+ @DreamLog LogBuffer logBuffer,
+ WeakReferenceFactory weakReferenceFactory) {
mExecutor = executor;
mOverlayEnabled = overlayEnabled;
mLogger = new DreamLogger(logBuffer, TAG);
mFeatureFlags = featureFlags;
+ mWeakReferenceFactory = weakReferenceFactory;
if (mFeatureFlags.isEnabled(Flags.ALWAYS_SHOW_HOME_CONTROLS_ON_DREAMS)) {
mSupportedTypes = Complication.COMPLICATION_TYPE_NONE
| Complication.COMPLICATION_TYPE_HOME_CONTROLS;
@@ -143,7 +153,7 @@ public class DreamOverlayStateController implements
mExecutor.execute(() -> {
if (mComplications.add(complication)) {
mLogger.logAddComplication(complication.toString());
- mCallbacks.stream().forEach(callback -> callback.onComplicationsChanged());
+ notifyCallbacksLocked(Callback::onComplicationsChanged);
}
});
}
@@ -160,7 +170,7 @@ public class DreamOverlayStateController implements
mExecutor.execute(() -> {
if (mComplications.remove(complication)) {
mLogger.logRemoveComplication(complication.toString());
- mCallbacks.stream().forEach(callback -> callback.onComplicationsChanged());
+ notifyCallbacksLocked(Callback::onComplicationsChanged);
}
});
}
@@ -199,22 +209,33 @@ public class DreamOverlayStateController implements
}
private void notifyCallbacks(Consumer<Callback> callbackConsumer) {
- mExecutor.execute(() -> {
- for (Callback callback : mCallbacks) {
+ mExecutor.execute(() -> notifyCallbacksLocked(callbackConsumer));
+ }
+
+ private void notifyCallbacksLocked(Consumer<Callback> callbackConsumer) {
+ final Iterator<WeakReference<Callback>> iterator = mCallbacks.iterator();
+ while (iterator.hasNext()) {
+ final Callback callback = iterator.next().get();
+ // Remove any callbacks which have been GC'd
+ if (callback == null) {
+ iterator.remove();
+ } else {
callbackConsumer.accept(callback);
}
- });
+ }
}
@Override
public void addCallback(@NonNull Callback callback) {
mExecutor.execute(() -> {
Objects.requireNonNull(callback, "Callback must not be null. b/128895449");
- if (mCallbacks.contains(callback)) {
+ final boolean containsCallback = mCallbacks.stream()
+ .anyMatch(reference -> reference.get() == callback);
+ if (containsCallback) {
return;
}
- mCallbacks.add(callback);
+ mCallbacks.add(mWeakReferenceFactory.create(callback));
if (mComplications.isEmpty()) {
return;
@@ -228,7 +249,13 @@ public class DreamOverlayStateController implements
public void removeCallback(@NonNull Callback callback) {
mExecutor.execute(() -> {
Objects.requireNonNull(callback, "Callback must not be null. b/128895449");
- mCallbacks.remove(callback);
+ final Iterator<WeakReference<Callback>> iterator = mCallbacks.iterator();
+ while (iterator.hasNext()) {
+ final Callback cb = iterator.next().get();
+ if (cb == null || cb == callback) {
+ iterator.remove();
+ }
+ }
});
}
@@ -318,7 +345,7 @@ public class DreamOverlayStateController implements
if (isLowLightActive() && !active) {
// Notify that we're exiting low light only on the transition from active to not active.
- mCallbacks.forEach(Callback::onExitLowLight);
+ notifyCallbacks(Callback::onExitLowLight);
}
modifyState(active ? OP_SET_STATE : OP_CLEAR_STATE, STATE_LOW_LIGHT_ACTIVE);
}
@@ -375,7 +402,7 @@ public class DreamOverlayStateController implements
mExecutor.execute(() -> {
mLogger.logAvailableComplicationTypes(types);
mAvailableComplicationTypes = types;
- mCallbacks.forEach(Callback::onAvailableComplicationTypesChanged);
+ notifyCallbacksLocked(Callback::onAvailableComplicationTypesChanged);
});
}
@@ -393,7 +420,7 @@ public class DreamOverlayStateController implements
mExecutor.execute(() -> {
mLogger.logShouldShowComplications(shouldShowComplications);
mShouldShowComplications = shouldShowComplications;
- mCallbacks.forEach(Callback::onAvailableComplicationTypesChanged);
+ notifyCallbacksLocked(Callback::onAvailableComplicationTypesChanged);
});
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/view/KeyboardBacklightDialog.kt b/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/view/KeyboardBacklightDialog.kt
index 1e9be09bc3f3..e16bb0bb8482 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/view/KeyboardBacklightDialog.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/view/KeyboardBacklightDialog.kt
@@ -30,7 +30,6 @@ import android.view.View
import android.view.ViewGroup.MarginLayoutParams
import android.view.Window
import android.view.WindowManager
-import android.view.accessibility.AccessibilityEvent
import android.widget.FrameLayout
import android.widget.ImageView
import android.widget.LinearLayout
@@ -79,29 +78,23 @@ class KeyboardBacklightDialog(
private lateinit var stepProperties: StepViewProperties
@ColorInt
- private val filledRectangleColor =
- getColorFromStyle(com.android.internal.R.attr.materialColorPrimary)
+ var filledRectangleColor = getColorFromStyle(com.android.internal.R.attr.materialColorPrimary)
@ColorInt
- private val emptyRectangleColor =
+ var emptyRectangleColor =
getColorFromStyle(com.android.internal.R.attr.materialColorOutlineVariant)
@ColorInt
- private val backgroundColor =
- getColorFromStyle(com.android.internal.R.attr.materialColorSurfaceBright)
+ var backgroundColor = getColorFromStyle(com.android.internal.R.attr.materialColorSurfaceBright)
@ColorInt
- private val defaultIconColor =
- getColorFromStyle(com.android.internal.R.attr.materialColorOnPrimary)
+ var defaultIconColor = getColorFromStyle(com.android.internal.R.attr.materialColorOnPrimary)
@ColorInt
- private val defaultIconBackgroundColor =
+ var defaultIconBackgroundColor =
getColorFromStyle(com.android.internal.R.attr.materialColorPrimary)
@ColorInt
- private val dimmedIconColor =
- getColorFromStyle(com.android.internal.R.attr.materialColorOnSurface)
+ var dimmedIconColor = getColorFromStyle(com.android.internal.R.attr.materialColorOnSurface)
@ColorInt
- private val dimmedIconBackgroundColor =
+ var dimmedIconBackgroundColor =
getColorFromStyle(com.android.internal.R.attr.materialColorSurfaceDim)
- private val levelContentDescription = context.getString(R.string.keyboard_backlight_value)
-
init {
currentLevel = initialCurrentLevel
maxLevel = initialMaxLevel
@@ -110,8 +103,6 @@ class KeyboardBacklightDialog(
override fun onCreate(savedInstanceState: Bundle?) {
setUpWindowProperties(this)
setWindowPosition()
- // title is used for a11y announcement
- window?.setTitle(context.getString(R.string.keyboard_backlight_dialog_title))
updateResources()
rootView = buildRootView()
setContentView(rootView)
@@ -168,12 +159,6 @@ class KeyboardBacklightDialog(
currentLevel = current
updateIconTile()
updateStepColors()
- updateAccessibilityInfo()
- }
-
- private fun updateAccessibilityInfo() {
- rootView.contentDescription = String.format(levelContentDescription, currentLevel, maxLevel)
- rootView.sendAccessibilityEvent(AccessibilityEvent.CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION)
}
private fun updateIconTile() {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/BiometricSettingsRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/BiometricSettingsRepository.kt
index 654f2d106206..f5f5571dbb1b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/BiometricSettingsRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/BiometricSettingsRepository.kt
@@ -66,7 +66,7 @@ import kotlinx.coroutines.flow.transformLatest
/**
* Acts as source of truth for biometric authentication related settings like enrollments, device
- * policy, etc.
+ * policy specifically for device entry usage.
*
* Abstracts-away data sources and their schemas so the rest of the app doesn't need to worry about
* upstream changes.
@@ -74,7 +74,8 @@ import kotlinx.coroutines.flow.transformLatest
interface BiometricSettingsRepository {
/**
* If the current user can enter the device using fingerprint. This is true if user has enrolled
- * fingerprints and fingerprint auth is not disabled through settings/device policy
+ * fingerprints and fingerprint auth is not disabled for device entry through settings and
+ * device policy
*/
val isFingerprintEnrolledAndEnabled: StateFlow<Boolean>
@@ -247,9 +248,11 @@ constructor(
}
}
- private val isFaceEnabledByBiometricsManagerForCurrentUser: Flow<Boolean> =
+ private val areBiometricsEnabledForCurrentUser: Flow<Boolean> =
userRepository.selectedUserInfo.flatMapLatest { userInfo ->
- isFaceEnabledByBiometricsManager.map { biometricsEnabledForUser[userInfo.id] ?: false }
+ areBiometricsEnabledForDeviceEntryFromUserSetting.map {
+ biometricsEnabledForUser[userInfo.id] ?: false
+ }
}
private val isFaceEnabledByDevicePolicy: Flow<Boolean> =
@@ -263,13 +266,13 @@ constructor(
.distinctUntilChanged()
private val isFaceAuthenticationEnabled: Flow<Boolean> =
- combine(isFaceEnabledByBiometricsManagerForCurrentUser, isFaceEnabledByDevicePolicy) {
+ combine(areBiometricsEnabledForCurrentUser, isFaceEnabledByDevicePolicy) {
biometricsManagerSetting,
devicePolicySetting ->
biometricsManagerSetting && devicePolicySetting
}
- private val isFaceEnabledByBiometricsManager: Flow<Pair<Int, Boolean>> =
+ private val areBiometricsEnabledForDeviceEntryFromUserSetting: Flow<Pair<Int, Boolean>> =
conflatedCallbackFlow {
val callback =
object : IBiometricEnabledOnKeyguardCallback.Stub() {
@@ -340,6 +343,7 @@ constructor(
override val isFingerprintEnrolledAndEnabled: StateFlow<Boolean> =
isFingerprintEnrolled
+ .and(areBiometricsEnabledForCurrentUser)
.and(isFingerprintEnabledByDevicePolicy)
.stateIn(scope, SharingStarted.Eagerly, false)
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/KeyguardMediaController.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/KeyguardMediaController.kt
index 83a6e58cc444..773c292befcf 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/KeyguardMediaController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/KeyguardMediaController.kt
@@ -23,11 +23,14 @@ import android.net.Uri
import android.os.Handler
import android.os.UserHandle
import android.provider.Settings
+import android.util.Log
import android.view.View
import android.view.ViewGroup
import androidx.annotation.VisibleForTesting
+import com.android.systemui.Dumpable
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.dump.DumpManager
import com.android.systemui.media.dagger.MediaModule.KEYGUARD
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.statusbar.StatusBarState
@@ -36,7 +39,11 @@ import com.android.systemui.statusbar.notification.stack.MediaContainerView
import com.android.systemui.statusbar.phone.KeyguardBypassController
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.statusbar.policy.SplitShadeStateController
+import com.android.systemui.util.asIndenting
+import com.android.systemui.util.println
import com.android.systemui.util.settings.SecureSettings
+import com.android.systemui.util.withIncreasedIndent
+import java.io.PrintWriter
import javax.inject.Inject
import javax.inject.Named
@@ -55,13 +62,18 @@ constructor(
private val secureSettings: SecureSettings,
@Main private val handler: Handler,
configurationController: ConfigurationController,
- private val splitShadeStateController: SplitShadeStateController
-) {
+ private val splitShadeStateController: SplitShadeStateController,
+ dumpManager: DumpManager,
+) : Dumpable {
+ /** It's added for debugging purpose to directly see last received StatusBarState. */
+ private var lastReceivedStatusBarState = -1
init {
+ dumpManager.registerDumpable(this)
statusBarStateController.addCallback(
object : StatusBarStateController.StateListener {
override fun onStateChanged(newState: Int) {
+ lastReceivedStatusBarState = newState
refreshMediaPosition()
}
@@ -206,7 +218,17 @@ constructor(
}
fun refreshMediaPosition() {
- val keyguardOrUserSwitcher = (statusBarStateController.state == StatusBarState.KEYGUARD)
+ val currentState = statusBarStateController.state
+ if (lastReceivedStatusBarState != -1 && currentState != lastReceivedStatusBarState) {
+ Log.wtfStack(
+ TAG,
+ "currentState[${StatusBarState.toString(currentState)}] is " +
+ "different from the last " +
+ "received one[${StatusBarState.toString(lastReceivedStatusBarState)}]."
+ )
+ }
+
+ val keyguardOrUserSwitcher = (currentState == StatusBarState.KEYGUARD)
// mediaHost.visible required for proper animations handling
visible =
mediaHost.visible &&
@@ -263,4 +285,34 @@ constructor(
visibilityChangedListener?.invoke(newVisibility == View.VISIBLE)
}
}
+
+ override fun dump(pw: PrintWriter, args: Array<out String>) {
+ pw.asIndenting().run {
+ println("KeyguardMediaController")
+ withIncreasedIndent {
+ println("Self", this@KeyguardMediaController)
+ println("visible", visible)
+ println("useSplitShade", useSplitShade)
+ println("allowMediaPlayerOnLockScreen", allowMediaPlayerOnLockScreen)
+ println("bypassController.bypassEnabled", bypassController.bypassEnabled)
+ println("isDozeWakeUpAnimationWaiting", isDozeWakeUpAnimationWaiting)
+ println("singlePaneContainer", singlePaneContainer)
+ println("splitShadeContainer", splitShadeContainer)
+ if (lastReceivedStatusBarState != -1) {
+ println(
+ "lastReceivedStatusBarState",
+ StatusBarState.toString(lastReceivedStatusBarState)
+ )
+ }
+ println(
+ "statusBarStateController.state",
+ StatusBarState.toString(statusBarStateController.state)
+ )
+ }
+ }
+ }
+
+ private companion object {
+ private const val TAG = "KeyguardMediaController"
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/BaseScreenSharePermissionDialog.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/BaseMediaProjectionPermissionDialogDelegate.kt
index eea369f15a16..654fffe89471 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/BaseScreenSharePermissionDialog.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/BaseMediaProjectionPermissionDialogDelegate.kt
@@ -15,6 +15,7 @@
*/
package com.android.systemui.mediaprojection.permission
+import android.app.AlertDialog
import android.content.Context
import android.os.Bundle
import android.view.Gravity
@@ -28,36 +29,36 @@ import android.widget.ArrayAdapter
import android.widget.ImageView
import android.widget.Spinner
import android.widget.TextView
+import androidx.annotation.CallSuper
import androidx.annotation.ColorRes
import androidx.annotation.DrawableRes
import androidx.annotation.LayoutRes
import androidx.annotation.StringRes
import com.android.systemui.mediaprojection.MediaProjectionMetricsLogger
import com.android.systemui.res.R
-import com.android.systemui.statusbar.phone.SystemUIDialog
+import com.android.systemui.statusbar.phone.DialogDelegate
/** Base permission dialog for screen share and recording */
-open class BaseScreenSharePermissionDialog(
- context: Context,
+abstract class BaseMediaProjectionPermissionDialogDelegate<T : AlertDialog>(
private val screenShareOptions: List<ScreenShareOption>,
private val appName: String?,
private val hostUid: Int,
private val mediaProjectionMetricsLogger: MediaProjectionMetricsLogger,
@DrawableRes private val dialogIconDrawable: Int? = null,
@ColorRes private val dialogIconTint: Int? = null,
-) : SystemUIDialog(context), AdapterView.OnItemSelectedListener {
+) : DialogDelegate<T>, AdapterView.OnItemSelectedListener {
private lateinit var dialogTitle: TextView
private lateinit var startButton: TextView
private lateinit var cancelButton: TextView
private lateinit var warning: TextView
private lateinit var screenShareModeSpinner: Spinner
private var hasCancelBeenLogged: Boolean = false
+ protected lateinit var dialog: AlertDialog
var selectedScreenShareOption: ScreenShareOption = screenShareOptions.first()
- override fun dismiss() {
- super.dismiss()
-
- // Dismiss can be called multiple times and we only want to log once.
+ @CallSuper
+ override fun onStop(dialog: T) {
+ // onStop can be called multiple times and we only want to log once.
if (hasCancelBeenLogged) {
return
}
@@ -66,42 +67,43 @@ open class BaseScreenSharePermissionDialog(
hasCancelBeenLogged = true
}
- public override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- window?.addPrivateFlags(WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS)
- window?.setGravity(Gravity.CENTER)
- setContentView(R.layout.screen_share_dialog)
- dialogTitle = requireViewById(R.id.screen_share_dialog_title)
- warning = requireViewById(R.id.text_warning)
- startButton = requireViewById(android.R.id.button1)
- cancelButton = requireViewById(android.R.id.button2)
+ @CallSuper
+ override fun onCreate(dialog: T, savedInstanceState: Bundle?) {
+ this.dialog = dialog
+ dialog.window?.addPrivateFlags(WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS)
+ dialog.window?.setGravity(Gravity.CENTER)
+ dialog.setContentView(R.layout.screen_share_dialog)
+ dialogTitle = dialog.requireViewById(R.id.screen_share_dialog_title)
+ warning = dialog.requireViewById(R.id.text_warning)
+ startButton = dialog.requireViewById(android.R.id.button1)
+ cancelButton = dialog.requireViewById(android.R.id.button2)
updateIcon()
initScreenShareOptions()
createOptionsView(getOptionsViewLayoutId())
}
private fun updateIcon() {
- val icon = requireViewById<ImageView>(R.id.screen_share_dialog_icon)
+ val icon = dialog.requireViewById<ImageView>(R.id.screen_share_dialog_icon)
if (dialogIconTint != null) {
- icon.setColorFilter(context.getColor(dialogIconTint))
+ icon.setColorFilter(dialog.context.getColor(dialogIconTint))
}
if (dialogIconDrawable != null) {
- icon.setImageDrawable(context.getDrawable(dialogIconDrawable))
+ icon.setImageDrawable(dialog.context.getDrawable(dialogIconDrawable))
}
}
- protected fun initScreenShareOptions() {
+ private fun initScreenShareOptions() {
selectedScreenShareOption = screenShareOptions.first()
warning.text = warningText
initScreenShareSpinner()
}
private val warningText: String
- get() = context.getString(selectedScreenShareOption.warningText, appName)
+ get() = dialog.context.getString(selectedScreenShareOption.warningText, appName)
private fun initScreenShareSpinner() {
- val adapter = OptionsAdapter(context.applicationContext, screenShareOptions)
- screenShareModeSpinner = requireViewById(R.id.screen_share_mode_spinner)
+ val adapter = OptionsAdapter(dialog.context.applicationContext, screenShareOptions)
+ screenShareModeSpinner = dialog.requireViewById(R.id.screen_share_mode_spinner)
screenShareModeSpinner.adapter = adapter
screenShareModeSpinner.onItemSelectedListener = this
}
@@ -115,7 +117,7 @@ open class BaseScreenSharePermissionDialog(
/** Protected methods for the text updates & functionality */
protected fun setDialogTitle(@StringRes stringId: Int) {
- val title = context.getString(stringId, appName)
+ val title = dialog.context.getString(stringId, appName)
dialogTitle.text = title
}
@@ -137,7 +139,7 @@ open class BaseScreenSharePermissionDialog(
private fun createOptionsView(@LayoutRes layoutId: Int?) {
if (layoutId == null) return
- val stub = requireViewById<View>(R.id.options_stub) as ViewStub
+ val stub = dialog.requireViewById<View>(R.id.options_stub) as ViewStub
stub.layoutResource = layoutId
stub.inflate()
}
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java b/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java
index eacfa578ac44..039372d87835 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java
@@ -60,6 +60,7 @@ import com.android.systemui.mediaprojection.appselector.MediaProjectionAppSelect
import com.android.systemui.mediaprojection.devicepolicy.ScreenCaptureDevicePolicyResolver;
import com.android.systemui.mediaprojection.devicepolicy.ScreenCaptureDisabledDialog;
import com.android.systemui.res.R;
+import com.android.systemui.statusbar.phone.AlertDialogWithDelegate;
import com.android.systemui.statusbar.phone.SystemUIDialog;
import com.android.systemui.util.Utils;
@@ -222,27 +223,30 @@ public class MediaProjectionPermissionActivity extends Activity
// the correct screen width when in split screen.
Context dialogContext = getApplicationContext();
if (isPartialScreenSharingEnabled()) {
- mDialog = new MediaProjectionPermissionDialog(
- dialogContext,
- getMediaProjectionConfig(),
- () -> {
- MediaProjectionPermissionDialog dialog =
- (MediaProjectionPermissionDialog) mDialog;
- ScreenShareOption selectedOption = dialog.getSelectedScreenShareOption();
- grantMediaProjectionPermission(selectedOption.getMode());
- },
- () -> finish(RECORD_CANCEL, /* projection= */ null),
- appName,
- mUid,
- mMediaProjectionMetricsLogger);
+ MediaProjectionPermissionDialogDelegate delegate =
+ new MediaProjectionPermissionDialogDelegate(
+ dialogContext,
+ getMediaProjectionConfig(),
+ dialog -> {
+ ScreenShareOption selectedOption =
+ dialog.getSelectedScreenShareOption();
+ grantMediaProjectionPermission(selectedOption.getMode());
+ },
+ () -> finish(RECORD_CANCEL, /* projection= */ null),
+ appName,
+ mUid,
+ mMediaProjectionMetricsLogger);
+ mDialog =
+ new AlertDialogWithDelegate(
+ dialogContext, R.style.Theme_SystemUI_Dialog, delegate);
} else {
- AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(dialogContext,
- R.style.Theme_SystemUI_Dialog)
- .setTitle(dialogTitle)
- .setIcon(R.drawable.ic_media_projection_permission)
- .setMessage(dialogText)
- .setPositiveButton(R.string.media_projection_action_text, this)
- .setNeutralButton(android.R.string.cancel, this);
+ AlertDialog.Builder dialogBuilder =
+ new AlertDialog.Builder(dialogContext, R.style.Theme_SystemUI_Dialog)
+ .setTitle(dialogTitle)
+ .setIcon(R.drawable.ic_media_projection_permission)
+ .setMessage(dialogText)
+ .setPositiveButton(R.string.media_projection_action_text, this)
+ .setNeutralButton(android.R.string.cancel, this);
mDialog = dialogBuilder.create();
}
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionDialog.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionDialogDelegate.kt
index cff22b0dc019..8453af19d26f 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionDialog.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionDialogDelegate.kt
@@ -15,31 +15,32 @@
*/
package com.android.systemui.mediaprojection.permission
+import android.app.AlertDialog
import android.content.Context
import android.media.projection.MediaProjectionConfig
import android.os.Bundle
import com.android.systemui.mediaprojection.MediaProjectionMetricsLogger
import com.android.systemui.res.R
+import java.util.function.Consumer
/** Dialog to select screen recording options */
-class MediaProjectionPermissionDialog(
+class MediaProjectionPermissionDialogDelegate(
context: Context,
mediaProjectionConfig: MediaProjectionConfig?,
- private val onStartRecordingClicked: Runnable,
+ private val onStartRecordingClicked: Consumer<MediaProjectionPermissionDialogDelegate>,
private val onCancelClicked: Runnable,
private val appName: String?,
hostUid: Int,
mediaProjectionMetricsLogger: MediaProjectionMetricsLogger,
) :
- BaseScreenSharePermissionDialog(
- context,
+ BaseMediaProjectionPermissionDialogDelegate<AlertDialog>(
createOptionList(context, appName, mediaProjectionConfig),
appName,
hostUid,
mediaProjectionMetricsLogger
) {
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
+ override fun onCreate(dialog: AlertDialog, savedInstanceState: Bundle?) {
+ super.onCreate(dialog, savedInstanceState)
// TODO(b/270018943): Handle the case of System sharing (not recording nor casting)
if (appName == null) {
setDialogTitle(R.string.media_projection_entry_cast_permission_dialog_title)
@@ -51,12 +52,12 @@ class MediaProjectionPermissionDialog(
setStartButtonOnClickListener {
// Note that it is important to run this callback before dismissing, so that the
// callback can disable the dialog exit animation if it wants to.
- onStartRecordingClicked.run()
- dismiss()
+ onStartRecordingClicked.accept(this)
+ dialog.dismiss()
}
setCancelButtonOnClickListener {
onCancelClicked.run()
- dismiss()
+ dialog.dismiss()
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanelController.kt b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanelController.kt
index c77f3f49a77c..fa03dc245745 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanelController.kt
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanelController.kt
@@ -22,7 +22,6 @@ import android.graphics.Paint
import android.graphics.Point
import android.os.Handler
import android.os.SystemClock
-import android.os.VibrationEffect
import android.util.Log
import android.util.MathUtils
import android.view.Gravity
@@ -37,8 +36,6 @@ import androidx.core.view.isVisible
import androidx.dynamicanimation.animation.DynamicAnimation
import com.android.internal.util.LatencyTracker
import com.android.systemui.dagger.qualifiers.Main
-import com.android.systemui.flags.FeatureFlags
-import com.android.systemui.flags.Flags.ONE_WAY_HAPTICS_API_MIGRATION
import com.android.systemui.plugins.NavigationEdgeBackPlugin
import com.android.systemui.statusbar.VibratorHelper
import com.android.systemui.statusbar.policy.ConfigurationController
@@ -78,12 +75,6 @@ private const val POP_ON_ENTRY_TO_ACTIVE_VELOCITY = 4.5f
private const val POP_ON_INACTIVE_TO_ACTIVE_VELOCITY = 4.7f
private const val POP_ON_INACTIVE_VELOCITY = -1.5f
-internal val VIBRATE_ACTIVATED_EFFECT =
- VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK)
-
-internal val VIBRATE_DEACTIVATED_EFFECT =
- VibrationEffect.createPredefined(VibrationEffect.EFFECT_TICK)
-
private const val DEBUG = false
class BackPanelController
@@ -95,7 +86,6 @@ internal constructor(
private val vibratorHelper: VibratorHelper,
private val configurationController: ConfigurationController,
private val latencyTracker: LatencyTracker,
- private val featureFlags: FeatureFlags
) : ViewController<BackPanel>(BackPanel(context, latencyTracker)), NavigationEdgeBackPlugin {
/**
@@ -113,7 +103,6 @@ internal constructor(
private val vibratorHelper: VibratorHelper,
private val configurationController: ConfigurationController,
private val latencyTracker: LatencyTracker,
- private val featureFlags: FeatureFlags
) {
/** Construct a [BackPanelController]. */
fun create(context: Context): BackPanelController {
@@ -126,7 +115,6 @@ internal constructor(
vibratorHelper,
configurationController,
latencyTracker,
- featureFlags
)
backPanelController.init()
return backPanelController
@@ -992,35 +980,22 @@ internal constructor(
val springForceOnCancelled =
params.cancelledIndicator.arrowDimens.alphaSpring?.get(0f)?.value
mView.popArrowAlpha(0f, springForceOnCancelled)
- if (!featureFlags.isEnabled(ONE_WAY_HAPTICS_API_MIGRATION))
- mainHandler.postDelayed(10L) { vibratorHelper.cancel() }
}
}
}
private fun performDeactivatedHapticFeedback() {
- if (featureFlags.isEnabled(ONE_WAY_HAPTICS_API_MIGRATION)) {
- vibratorHelper.performHapticFeedback(
- mView,
- HapticFeedbackConstants.GESTURE_THRESHOLD_DEACTIVATE
- )
- } else {
- vibratorHelper.vibrate(VIBRATE_DEACTIVATED_EFFECT)
- }
+ vibratorHelper.performHapticFeedback(
+ mView,
+ HapticFeedbackConstants.GESTURE_THRESHOLD_DEACTIVATE
+ )
}
private fun performActivatedHapticFeedback() {
- if (featureFlags.isEnabled(ONE_WAY_HAPTICS_API_MIGRATION)) {
- vibratorHelper.performHapticFeedback(
- mView,
- HapticFeedbackConstants.GESTURE_THRESHOLD_ACTIVATE
- )
- } else {
- vibratorHelper.cancel()
- mainHandler.postDelayed(10L) {
- vibratorHelper.vibrate(VIBRATE_ACTIVATED_EFFECT)
- }
- }
+ vibratorHelper.performHapticFeedback(
+ mView,
+ HapticFeedbackConstants.GESTURE_THRESHOLD_ACTIVATE
+ )
}
private fun convertVelocityToAnimationFactor(
diff --git a/packages/SystemUI/src/com/android/systemui/power/data/repository/PowerRepository.kt b/packages/SystemUI/src/com/android/systemui/power/data/repository/PowerRepository.kt
index 934f31040ce1..82420875e0de 100644
--- a/packages/SystemUI/src/com/android/systemui/power/data/repository/PowerRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/power/data/repository/PowerRepository.kt
@@ -32,12 +32,12 @@ import com.android.systemui.power.shared.model.WakeSleepReason
import com.android.systemui.power.shared.model.WakefulnessModel
import com.android.systemui.power.shared.model.WakefulnessState
import com.android.systemui.util.time.SystemClock
+import javax.inject.Inject
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
-import javax.inject.Inject
/** Defines interface for classes that act as source of truth for power-related data. */
interface PowerRepository {
@@ -67,15 +67,22 @@ interface PowerRepository {
/** Wakes up the device. */
fun wakeUp(why: String, @PowerManager.WakeReason wakeReason: Int)
- /** Notifies the power repository that a user touch happened. */
- fun userTouch()
+ /**
+ * Notifies the power repository that a user touch happened.
+ *
+ * @param noChangeLights If true, does not cause the keyboard backlight to turn on because of
+ * this event. This is set when the power key is pressed. We want the device to stay on while
+ * the button is down, but we're about to turn off the screen so we don't want the keyboard
+ * backlight to turn on again. Otherwise the lights flash on and then off and it looks weird.
+ */
+ fun userTouch(noChangeLights: Boolean = false)
/** Updates the wakefulness state, keeping previous values by default. */
fun updateWakefulness(
- rawState: WakefulnessState = wakefulness.value.internalWakefulnessState,
- lastWakeReason: WakeSleepReason = wakefulness.value.lastWakeReason,
- lastSleepReason: WakeSleepReason = wakefulness.value.lastSleepReason,
- powerButtonLaunchGestureTriggered: Boolean =
+ rawState: WakefulnessState = wakefulness.value.internalWakefulnessState,
+ lastWakeReason: WakeSleepReason = wakefulness.value.lastWakeReason,
+ lastSleepReason: WakeSleepReason = wakefulness.value.lastSleepReason,
+ powerButtonLaunchGestureTriggered: Boolean =
wakefulness.value.powerButtonLaunchGestureTriggered,
)
@@ -121,10 +128,10 @@ constructor(
override val wakefulness = _wakefulness.asStateFlow()
override fun updateWakefulness(
- rawState: WakefulnessState,
- lastWakeReason: WakeSleepReason,
- lastSleepReason: WakeSleepReason,
- powerButtonLaunchGestureTriggered: Boolean,
+ rawState: WakefulnessState,
+ lastWakeReason: WakeSleepReason,
+ lastSleepReason: WakeSleepReason,
+ powerButtonLaunchGestureTriggered: Boolean,
) {
_wakefulness.value =
WakefulnessModel(
@@ -150,11 +157,11 @@ constructor(
)
}
- override fun userTouch() {
+ override fun userTouch(noChangeLights: Boolean) {
manager.userActivity(
systemClock.uptimeMillis(),
PowerManager.USER_ACTIVITY_EVENT_TOUCH,
- /* flags= */ 0,
+ if (noChangeLights) PowerManager.USER_ACTIVITY_FLAG_NO_CHANGE_LIGHTS else 0,
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java
index 05f125f6f531..bff0b93dccb0 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java
@@ -46,6 +46,7 @@ import com.android.systemui.mediaprojection.devicepolicy.ScreenCaptureDisabledDi
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.settings.UserContextProvider;
import com.android.systemui.settings.UserTracker;
+import com.android.systemui.statusbar.phone.SystemUIDialog;
import com.android.systemui.statusbar.policy.CallbackController;
import dagger.Lazy;
@@ -75,6 +76,7 @@ public class RecordingController
private final UserContextProvider mUserContextProvider;
private final UserTracker mUserTracker;
private final MediaProjectionMetricsLogger mMediaProjectionMetricsLogger;
+ private final SystemUIDialog.Factory mDialogFactory;
protected static final String INTENT_UPDATE_STATE =
"com.android.systemui.screenrecord.UPDATE_STATE";
@@ -120,7 +122,8 @@ public class RecordingController
UserContextProvider userContextProvider,
Lazy<ScreenCaptureDevicePolicyResolver> devicePolicyResolver,
UserTracker userTracker,
- MediaProjectionMetricsLogger mediaProjectionMetricsLogger) {
+ MediaProjectionMetricsLogger mediaProjectionMetricsLogger,
+ SystemUIDialog.Factory dialogFactory) {
mMainExecutor = mainExecutor;
mContext = context;
mFlags = flags;
@@ -129,6 +132,7 @@ public class RecordingController
mUserContextProvider = userContextProvider;
mUserTracker = userTracker;
mMediaProjectionMetricsLogger = mediaProjectionMetricsLogger;
+ mDialogFactory = dialogFactory;
BroadcastOptions options = BroadcastOptions.makeBasic();
options.setInteractive(true);
@@ -166,15 +170,14 @@ public class RecordingController
getHostUid(), SessionCreationSource.SYSTEM_UI_SCREEN_RECORDER);
return flags.isEnabled(Flags.WM_ENABLE_PARTIAL_SCREEN_SHARING)
- ? new ScreenRecordPermissionDialog(
- context,
- getHostUserHandle(),
- getHostUid(),
- /* controller= */ this,
- activityStarter,
- mUserContextProvider,
- onStartRecordingClicked,
- mMediaProjectionMetricsLogger)
+ ? mDialogFactory.create(new ScreenRecordPermissionDialogDelegate(
+ getHostUserHandle(),
+ getHostUid(),
+ /* controller= */ this,
+ activityStarter,
+ mUserContextProvider,
+ onStartRecordingClicked,
+ mMediaProjectionMetricsLogger))
: new ScreenRecordDialog(
context,
/* controller= */ this,
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialog.kt b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialogDelegate.kt
index f74234bc2e21..e57a0fddc936 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialog.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialogDelegate.kt
@@ -17,7 +17,6 @@ package com.android.systemui.screenrecord
import android.app.Activity
import android.app.PendingIntent
-import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.os.Handler
@@ -35,17 +34,17 @@ import androidx.annotation.LayoutRes
import com.android.systemui.mediaprojection.MediaProjectionCaptureTarget
import com.android.systemui.mediaprojection.MediaProjectionMetricsLogger
import com.android.systemui.mediaprojection.appselector.MediaProjectionAppSelectorActivity
-import com.android.systemui.mediaprojection.permission.BaseScreenSharePermissionDialog
+import com.android.systemui.mediaprojection.permission.BaseMediaProjectionPermissionDialogDelegate
import com.android.systemui.mediaprojection.permission.ENTIRE_SCREEN
import com.android.systemui.mediaprojection.permission.SINGLE_APP
import com.android.systemui.mediaprojection.permission.ScreenShareOption
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.res.R
import com.android.systemui.settings.UserContextProvider
+import com.android.systemui.statusbar.phone.SystemUIDialog
/** Dialog to select screen recording options */
-class ScreenRecordPermissionDialog(
- context: Context,
+class ScreenRecordPermissionDialogDelegate(
private val hostUserHandle: UserHandle,
private val hostUid: Int,
private val controller: RecordingController,
@@ -54,8 +53,7 @@ class ScreenRecordPermissionDialog(
private val onStartRecordingClicked: Runnable?,
mediaProjectionMetricsLogger: MediaProjectionMetricsLogger,
) :
- BaseScreenSharePermissionDialog(
- context,
+ BaseMediaProjectionPermissionDialogDelegate<SystemUIDialog>(
createOptionList(),
appName = null,
hostUid = hostUid,
@@ -68,10 +66,10 @@ class ScreenRecordPermissionDialog(
private lateinit var audioSwitch: Switch
private lateinit var options: Spinner
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
+ override fun onCreate(dialog: SystemUIDialog, savedInstanceState: Bundle?) {
+ super.onCreate(dialog, savedInstanceState)
setDialogTitle(R.string.screenrecord_permission_dialog_title)
- setTitle(R.string.screenrecord_title)
+ dialog.setTitle(R.string.screenrecord_title)
setStartButtonText(R.string.screenrecord_permission_dialog_continue)
setStartButtonOnClickListener { v: View? ->
onStartRecordingClicked?.run()
@@ -79,7 +77,7 @@ class ScreenRecordPermissionDialog(
requestScreenCapture(/* captureTarget= */ null)
}
if (selectedScreenShareOption.mode == SINGLE_APP) {
- val intent = Intent(context, MediaProjectionAppSelectorActivity::class.java)
+ val intent = Intent(dialog.context, MediaProjectionAppSelectorActivity::class.java)
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
// We can't start activity for result here so we use result receiver to get
@@ -96,22 +94,26 @@ class ScreenRecordPermissionDialog(
intent.putExtra(MediaProjectionAppSelectorActivity.EXTRA_HOST_APP_UID, hostUid)
activityStarter.startActivity(intent, /* dismissShade= */ true)
}
- dismiss()
+ dialog.dismiss()
}
- setCancelButtonOnClickListener { dismiss() }
+ setCancelButtonOnClickListener { dialog.dismiss() }
initRecordOptionsView()
}
@LayoutRes override fun getOptionsViewLayoutId(): Int = R.layout.screen_record_options
private fun initRecordOptionsView() {
- audioSwitch = requireViewById(R.id.screenrecord_audio_switch)
- tapsSwitch = requireViewById(R.id.screenrecord_taps_switch)
- tapsView = requireViewById(R.id.show_taps)
+ audioSwitch = dialog.requireViewById(R.id.screenrecord_audio_switch)
+ tapsSwitch = dialog.requireViewById(R.id.screenrecord_taps_switch)
+ tapsView = dialog.requireViewById(R.id.show_taps)
updateTapsViewVisibility()
- options = requireViewById(R.id.screen_recording_options)
+ options = dialog.requireViewById(R.id.screen_recording_options)
val a: ArrayAdapter<*> =
- ScreenRecordingAdapter(context, android.R.layout.simple_spinner_dropdown_item, MODES)
+ ScreenRecordingAdapter(
+ dialog.context,
+ android.R.layout.simple_spinner_dropdown_item,
+ MODES
+ )
a.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
options.adapter = a
options.setOnItemClickListenerInt { _: AdapterView<*>?, _: View?, _: Int, _: Long ->
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconContainerViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconContainerViewBinder.kt
index 65b798a14e0b..62c3e9e486b4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconContainerViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconContainerViewBinder.kt
@@ -18,7 +18,6 @@ package com.android.systemui.statusbar.notification.icon.ui.viewbinder
import android.graphics.Color
import android.graphics.Rect
import android.view.View
-import android.view.ViewGroup
import android.widget.FrameLayout
import androidx.annotation.ColorInt
import androidx.collection.ArrayMap
@@ -32,7 +31,6 @@ import com.android.systemui.statusbar.StatusBarIconView
import com.android.systemui.statusbar.notification.NotificationUtils
import com.android.systemui.statusbar.notification.collection.NotifCollection
import com.android.systemui.statusbar.notification.icon.ui.viewbinder.NotificationIconContainerViewBinder.IconViewStore
-import com.android.systemui.statusbar.notification.icon.ui.viewmodel.NotificationIconColorLookup
import com.android.systemui.statusbar.notification.icon.ui.viewmodel.NotificationIconColors
import com.android.systemui.statusbar.notification.icon.ui.viewmodel.NotificationIconContainerAlwaysOnDisplayViewModel
import com.android.systemui.statusbar.notification.icon.ui.viewmodel.NotificationIconContainerShelfViewModel
@@ -52,6 +50,7 @@ import com.android.systemui.util.ui.stopAnimating
import com.android.systemui.util.ui.value
import javax.inject.Inject
import kotlinx.coroutines.DisposableHandle
+import kotlinx.coroutines.Job
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.StateFlow
@@ -88,14 +87,17 @@ object NotificationIconContainerViewBinder {
return view.repeatWhenAttached {
lifecycleScope.run {
launch {
+ val iconColors =
+ viewModel.iconColors.mapNotNull { it.iconColors(view.viewBounds) }
viewModel.icons.bindIcons(
view,
configuration,
configurationController,
- viewStore
- )
+ viewStore,
+ ) { _, sbiv ->
+ iconColors.collect { sbiv.updateTintForIcon(it, contrastColorUtil) }
+ }
}
- launch { viewModel.iconColors.bindIconColors(view, contrastColorUtil) }
launch { viewModel.bindIsolatedIcon(view, viewStore) }
launch { viewModel.animationsEnabled.bindAnimationsEnabled(view) }
}
@@ -119,15 +121,17 @@ object NotificationIconContainerViewBinder {
configuration,
configurationController,
viewStore,
- )
+ ) { _, sbiv ->
+ configuration
+ .getColorAttr(R.attr.wallpaperTextColor, DEFAULT_AOD_ICON_COLOR)
+ .collect { tint ->
+ sbiv.staticDrawableColor = tint
+ sbiv.setDecorColor(tint)
+ }
+ }
}
launch { viewModel.animationsEnabled.bindAnimationsEnabled(view) }
launch { viewModel.isDozing.bindIsDozing(view, dozeParameters) }
- launch {
- configuration
- .getColorAttr(R.attr.wallpaperTextColor, DEFAULT_AOD_ICON_COLOR)
- .bindIconColors(view)
- }
}
}
}
@@ -137,31 +141,6 @@ object NotificationIconContainerViewBinder {
collect(view::setAnimationsEnabled)
}
- /**
- * Binds to the [StatusBarIconView.setStaticDrawableColor] and [StatusBarIconView.setDecorColor]
- * of the [children] of an [NotificationIconContainer].
- */
- private suspend fun Flow<NotificationIconColorLookup>.bindIconColors(
- view: NotificationIconContainer,
- contrastColorUtil: ContrastColorUtil,
- ) {
- mapNotNull { lookup -> lookup.iconColors(view.viewBounds) }
- .collect { iconLookup -> view.applyTint(iconLookup, contrastColorUtil) }
- }
-
- /**
- * Binds to the [StatusBarIconView.setStaticDrawableColor] and [StatusBarIconView.setDecorColor]
- * of the [children] of an [NotificationIconContainer].
- */
- private suspend fun Flow<Int>.bindIconColors(view: NotificationIconContainer) {
- collect { tint ->
- view.children.filterIsInstance<StatusBarIconView>().forEach { icon ->
- icon.staticDrawableColor = tint
- icon.setDecorColor(tint)
- }
- }
- }
-
private suspend fun Flow<AnimatedValue<Boolean>>.bindIsDozing(
view: NotificationIconContainer,
dozeParameters: DozeParameters,
@@ -208,12 +187,19 @@ object NotificationIconContainerViewBinder {
}
}
- /** Binds [NotificationIconsViewData] to a [NotificationIconContainer]'s [children]. */
+ /**
+ * Binds [NotificationIconsViewData] to a [NotificationIconContainer]'s [children].
+ *
+ * [bindIcon] will be invoked to bind a child [StatusBarIconView] to an icon associated with the
+ * given `iconKey`. The parent [Job] of this coroutine will be cancelled automatically when the
+ * view is to be unbound.
+ */
private suspend fun Flow<NotificationIconsViewData>.bindIcons(
view: NotificationIconContainer,
configuration: ConfigurationState,
configurationController: ConfigurationController,
viewStore: IconViewStore,
+ bindIcon: suspend (iconKey: String, view: StatusBarIconView) -> Unit = { _, _ -> },
): Unit = coroutineScope {
val iconSizeFlow: Flow<Int> =
configuration.getDimensionPixelSize(
@@ -242,6 +228,7 @@ object NotificationIconContainerViewBinder {
}
}
+ val iconBindings = mutableMapOf<String, Job>()
var prevIcons = NotificationIconsViewData()
sample(layoutParams, ::Pair).collect {
(iconsData: NotificationIconsViewData, layoutParams: FrameLayout.LayoutParams),
@@ -261,15 +248,20 @@ object NotificationIconContainerViewBinder {
}
iconsDiff.removed
- .mapNotNull { key -> childrenByNotifKey[key] }
- .forEach { child -> view.removeView(child) }
+ .mapNotNull { key -> childrenByNotifKey[key]?.let { key to it } }
+ .forEach { (key, child) ->
+ view.removeView(child)
+ iconBindings.remove(key)?.cancel()
+ }
- val toAdd = iconsDiff.added.map { viewStore.iconView(it.notifKey) }
- for ((i, sbiv) in toAdd.withIndex()) {
+ val toAdd = iconsDiff.added.map { it.notifKey to viewStore.iconView(it.notifKey) }
+ for ((i, keyAndView) in toAdd.withIndex()) {
+ val (key, sbiv) = keyAndView
// The view might still be transiently added if it was just removed
// and added again
view.removeTransientView(sbiv)
view.addView(sbiv, i, layoutParams)
+ iconBindings[key] = launch { bindIcon(key, sbiv) }
}
view.setChangingViewPositions(true)
@@ -292,16 +284,6 @@ object NotificationIconContainerViewBinder {
// TODO(b/305739416): Once StatusBarIconView has its own Recommended Architecture stack, this
// can be moved there and cleaned up.
- private fun ViewGroup.applyTint(
- iconColors: NotificationIconColors,
- contrastColorUtil: ContrastColorUtil,
- ) {
- children
- .filterIsInstance<StatusBarIconView>()
- .filter { it.width != 0 }
- .forEach { iv -> iv.updateTintForIcon(iconColors, contrastColorUtil) }
- }
-
private fun StatusBarIconView.updateTintForIcon(
iconColors: NotificationIconColors,
contrastColorUtil: ContrastColorUtil,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionsRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionsRepository.kt
index 13c99647f00b..9471574fc755 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionsRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionsRepository.kt
@@ -100,6 +100,17 @@ interface MobileConnectionsRepository {
val isAnySimSecure: Flow<Boolean>
/**
+ * Returns whether any active SIM on the device is in
+ * [android.telephony.TelephonyManager.SIM_STATE_PIN_REQUIRED] or
+ * [android.telephony.TelephonyManager.SIM_STATE_PUK_REQUIRED] or
+ * [android.telephony.TelephonyManager.SIM_STATE_PERM_DISABLED].
+ *
+ * Note: Unfortunately, we cannot name this [isAnySimSecure] due to a conflict with the flow
+ * name above (Java code-gen is having issues with it).
+ */
+ fun getIsAnySimSecure(): Boolean
+
+ /**
* Checks if any subscription has [android.telephony.TelephonyManager.getEmergencyCallbackMode]
* == true
*/
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcher.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcher.kt
index 87dd17ec4865..8a8e33efbcef 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcher.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcher.kt
@@ -152,6 +152,7 @@ constructor(
activeRepo.flatMapLatest { it.defaultMobileIconGroup }
override val isAnySimSecure: Flow<Boolean> = activeRepo.flatMapLatest { it.isAnySimSecure }
+ override fun getIsAnySimSecure(): Boolean = activeRepo.value.getIsAnySimSecure()
override val defaultDataSubId: StateFlow<Int> =
activeRepo
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepository.kt
index 2ecd435177ee..2b3c6326032c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepository.kt
@@ -136,7 +136,8 @@ constructor(
override val defaultMobileIconGroup = flowOf(TelephonyIcons.THREE_G)
- override val isAnySimSecure: Flow<Boolean> = flowOf(false)
+ override val isAnySimSecure: Flow<Boolean> = flowOf(getIsAnySimSecure())
+ override fun getIsAnySimSecure(): Boolean = false
override val defaultMobileIconMapping = MutableStateFlow(TelephonyIcons.ICON_NAME_TO_ICON)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt
index cf7bf86504fb..2a510e41ec9c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt
@@ -262,7 +262,7 @@ constructor(
object : KeyguardUpdateMonitorCallback() {
override fun onSimStateChanged(subId: Int, slotId: Int, simState: Int) {
logger.logOnSimStateChanged()
- trySend(keyguardUpdateMonitor.isSimPinSecure)
+ trySend(getIsAnySimSecure())
}
}
keyguardUpdateMonitor.registerCallback(callback)
@@ -277,6 +277,8 @@ constructor(
)
.distinctUntilChanged()
+ override fun getIsAnySimSecure() = keyguardUpdateMonitor.isSimPinSecure
+
override fun getRepoForSubId(subId: Int): FullMobileConnectionRepository =
getOrCreateRepoForSubId(subId)
diff --git a/packages/SystemUI/src/com/android/systemui/telephony/data/repository/TelephonyRepository.kt b/packages/SystemUI/src/com/android/systemui/telephony/data/repository/TelephonyRepository.kt
index 3b300249aac2..b1b6014bfbde 100644
--- a/packages/SystemUI/src/com/android/systemui/telephony/data/repository/TelephonyRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/telephony/data/repository/TelephonyRepository.kt
@@ -17,23 +17,40 @@
package com.android.systemui.telephony.data.repository
+import android.annotation.SuppressLint
import android.content.Context
import android.content.pm.PackageManager
+import android.telecom.TelecomManager
import android.telephony.Annotation
import android.telephony.TelephonyCallback
import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.telephony.TelephonyListenerManager
import javax.inject.Inject
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.stateIn
+import kotlinx.coroutines.withContext
/** Defines interface for classes that encapsulate _some_ telephony-related state. */
interface TelephonyRepository {
/** The state of the current call. */
@Annotation.CallState val callState: Flow<Int>
+ /**
+ * Whether there is an ongoing phone call (can be in dialing, ringing, active or holding states)
+ * originating from either a manager or self-managed {@link ConnectionService}.
+ */
+ val isInCall: StateFlow<Boolean>
+
/** Whether the device has a radio that can be used for telephony. */
val hasTelephonyRadio: Boolean
}
@@ -49,18 +66,35 @@ interface TelephonyRepository {
class TelephonyRepositoryImpl
@Inject
constructor(
+ @Application private val applicationScope: CoroutineScope,
@Application private val applicationContext: Context,
+ @Background private val backgroundDispatcher: CoroutineDispatcher,
private val manager: TelephonyListenerManager,
+ private val telecomManager: TelecomManager?,
) : TelephonyRepository {
+
@Annotation.CallState
override val callState: Flow<Int> = conflatedCallbackFlow {
- val listener = TelephonyCallback.CallStateListener { state -> trySend(state) }
+ val listener = TelephonyCallback.CallStateListener(::trySend)
manager.addCallStateListener(listener)
awaitClose { manager.removeCallStateListener(listener) }
}
- override val hasTelephonyRadio: Boolean
- get() = applicationContext.packageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)
+ @SuppressLint("MissingPermission")
+ override val isInCall: StateFlow<Boolean> =
+ if (telecomManager == null) {
+ flowOf(false)
+ } else {
+ callState.map { withContext(backgroundDispatcher) { telecomManager.isInCall } }
+ }
+ .stateIn(
+ applicationScope,
+ SharingStarted.WhileSubscribed(),
+ initialValue = false,
+ )
+
+ override val hasTelephonyRadio =
+ applicationContext.packageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)
}
diff --git a/packages/SystemUI/src/com/android/systemui/telephony/domain/interactor/TelephonyInteractor.kt b/packages/SystemUI/src/com/android/systemui/telephony/domain/interactor/TelephonyInteractor.kt
index 4642f552615a..4b0e5d188ffa 100644
--- a/packages/SystemUI/src/com/android/systemui/telephony/domain/interactor/TelephonyInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/telephony/domain/interactor/TelephonyInteractor.kt
@@ -22,17 +22,18 @@ import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.telephony.data.repository.TelephonyRepository
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.StateFlow
/** Hosts business logic related to telephony. */
@SysUISingleton
class TelephonyInteractor
@Inject
constructor(
- private val repository: TelephonyRepository,
+ repository: TelephonyRepository,
) {
@Annotation.CallState val callState: Flow<Int> = repository.callState
- /** Whether the device has a radio that can be used for telephony. */
- val hasTelephonyRadio: Boolean
- get() = repository.hasTelephonyRadio
+ val isInCall: StateFlow<Boolean> = repository.isInCall
+
+ val hasTelephonyRadio: Boolean = repository.hasTelephonyRadio
}
diff --git a/packages/SystemUI/src/com/android/systemui/user/domain/interactor/SelectedUserInteractor.kt b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/SelectedUserInteractor.kt
index 78fb7a491534..3ed05aac3e10 100644
--- a/packages/SystemUI/src/com/android/systemui/user/domain/interactor/SelectedUserInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/SelectedUserInteractor.kt
@@ -34,10 +34,10 @@ constructor(
@UserIdInt
@JvmOverloads
fun getSelectedUserId(bypassFlag: Boolean = false): Int {
- if (bypassFlag || flags.isEnabled(REFACTOR_GETCURRENTUSER)) {
- return repository.getSelectedUserInfo().id
+ return if (bypassFlag || flags.isEnabled(REFACTOR_GETCURRENTUSER)) {
+ repository.getSelectedUserInfo().id
} else {
- return KeyguardUpdateMonitor.getCurrentUser()
+ KeyguardUpdateMonitor.getCurrentUser()
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/util/reference/ReferenceModule.kt b/packages/SystemUI/src/com/android/systemui/util/reference/ReferenceModule.kt
new file mode 100644
index 000000000000..e7a91e505e47
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/reference/ReferenceModule.kt
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2023 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.systemui.util.reference
+
+import dagger.Binds
+import dagger.Module
+
+@Module
+abstract class ReferenceModule {
+ @Binds
+ abstract fun bindWeakReferenceFactory(impl: WeakReferenceFactoryImpl): WeakReferenceFactory
+}
diff --git a/packages/SystemUI/src/com/android/systemui/util/reference/WeakReferenceFactory.kt b/packages/SystemUI/src/com/android/systemui/util/reference/WeakReferenceFactory.kt
new file mode 100644
index 000000000000..658f0404aa84
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/reference/WeakReferenceFactory.kt
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2023 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.systemui.util.reference
+
+import java.lang.ref.WeakReference
+import javax.inject.Inject
+
+interface WeakReferenceFactory {
+ fun <T> create(referent: T): WeakReference<T>
+}
+
+class WeakReferenceFactoryImpl @Inject constructor() : WeakReferenceFactory {
+ override fun <T> create(referent: T): WeakReference<T> {
+ return WeakReference(referent)
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/EmergencyButtonControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/EmergencyButtonControllerTest.kt
index c61b11ae7336..9a95b17fc7d1 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/EmergencyButtonControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/EmergencyButtonControllerTest.kt
@@ -48,7 +48,6 @@ import org.mockito.MockitoAnnotations
@RunWith(AndroidTestingRunner::class)
@TestableLooper.RunWithLooper
class EmergencyButtonControllerTest : SysuiTestCase() {
- lateinit var underTest: EmergencyButtonController
@Mock lateinit var emergencyButton: EmergencyButton
@Mock lateinit var configurationController: ConfigurationController
@Mock lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
@@ -61,10 +60,13 @@ class EmergencyButtonControllerTest : SysuiTestCase() {
@Mock lateinit var lockPatternUtils: LockPatternUtils
@Mock lateinit var packageManager: PackageManager
@Mock lateinit var mSelectedUserInteractor: SelectedUserInteractor
+
val fakeSystemClock = FakeSystemClock()
val mainExecutor = FakeExecutor(fakeSystemClock)
val backgroundExecutor = FakeExecutor(fakeSystemClock)
+ lateinit var underTest: EmergencyButtonController
+
@Before
fun setup() {
MockitoAnnotations.initMocks(this)
@@ -73,7 +75,6 @@ class EmergencyButtonControllerTest : SysuiTestCase() {
emergencyButton,
configurationController,
keyguardUpdateMonitor,
- telephonyManager,
powerManager,
activityTaskManager,
shadeController,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/data/repository/KeyguardBouncerRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/data/repository/KeyguardBouncerRepositoryTest.kt
index a04919185350..44c57f34fa1b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/data/repository/KeyguardBouncerRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/data/repository/KeyguardBouncerRepositoryTest.kt
@@ -2,15 +2,13 @@ package com.android.systemui.bouncer.data.repository
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
-import com.android.keyguard.ViewMediatorCallback
import com.android.systemui.SysuiTestCase
import com.android.systemui.log.table.TableLogBuffer
+import com.android.systemui.scene.SceneTestUtils
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.eq
import com.android.systemui.util.time.SystemClock
-import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.runBlocking
-import kotlinx.coroutines.test.TestCoroutineScope
+import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -18,32 +16,34 @@ import org.mockito.Mock
import org.mockito.Mockito
import org.mockito.MockitoAnnotations
-@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
@RunWith(AndroidJUnit4::class)
class KeyguardBouncerRepositoryTest : SysuiTestCase() {
@Mock private lateinit var systemClock: SystemClock
- @Mock private lateinit var viewMediatorCallback: ViewMediatorCallback
@Mock private lateinit var bouncerLogger: TableLogBuffer
+
+ private val utils = SceneTestUtils(this)
+ private val testScope = utils.testScope
+
lateinit var underTest: KeyguardBouncerRepository
@Before
fun setup() {
MockitoAnnotations.initMocks(this)
- val testCoroutineScope = TestCoroutineScope()
underTest =
KeyguardBouncerRepositoryImpl(
systemClock,
- testCoroutineScope,
+ testScope.backgroundScope,
bouncerLogger,
)
}
@Test
- fun changingFlowValueTriggersLogging() = runBlocking {
- underTest.setPrimaryShow(true)
- Mockito.verify(bouncerLogger)
- .logChange(eq(""), eq("PrimaryBouncerShow"), value = eq(false), any())
- }
+ fun changingFlowValueTriggersLogging() =
+ testScope.runTest {
+ underTest.setPrimaryShow(true)
+ Mockito.verify(bouncerLogger)
+ .logChange(eq(""), eq("PrimaryBouncerShow"), value = eq(false), any())
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModelTest.kt
index 2c97809bf367..c159b66c10a0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModelTest.kt
@@ -45,6 +45,7 @@ class BouncerViewModelTest : SysuiTestCase() {
private val utils = SceneTestUtils(this)
private val testScope = utils.testScope
private val authenticationInteractor = utils.authenticationInteractor()
+ private val actionButtonInteractor = utils.bouncerActionButtonInteractor()
private val deviceEntryInteractor =
utils.deviceEntryInteractor(
authenticationInteractor = authenticationInteractor,
@@ -60,6 +61,7 @@ class BouncerViewModelTest : SysuiTestCase() {
utils.bouncerViewModel(
bouncerInteractor = bouncerInteractor,
authenticationInteractor = authenticationInteractor,
+ actionButtonInteractor = actionButtonInteractor,
)
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/KeyguardBouncerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/KeyguardBouncerViewModelTest.kt
index b75f3e0876ff..2cc8f0a47955 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/KeyguardBouncerViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/KeyguardBouncerViewModelTest.kt
@@ -52,8 +52,7 @@ import org.mockito.MockitoAnnotations
@RunWith(AndroidJUnit4::class)
@kotlinx.coroutines.ExperimentalCoroutinesApi
class KeyguardBouncerViewModelTest : SysuiTestCase() {
- lateinit var underTest: KeyguardBouncerViewModel
- lateinit var bouncerInteractor: PrimaryBouncerInteractor
+
@Mock lateinit var bouncerView: BouncerView
@Mock private lateinit var keyguardStateController: KeyguardStateController
@Mock private lateinit var keyguardSecurityModel: KeyguardSecurityModel
@@ -62,9 +61,13 @@ class KeyguardBouncerViewModelTest : SysuiTestCase() {
@Mock private lateinit var dismissCallbackRegistry: DismissCallbackRegistry
@Mock private lateinit var mSelectedUserInteractor: SelectedUserInteractor
@Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
+
+ lateinit var bouncerInteractor: PrimaryBouncerInteractor
private val mainHandler = FakeHandler(Looper.getMainLooper())
val repository = FakeKeyguardBouncerRepository()
+ lateinit var underTest: KeyguardBouncerViewModel
+
@Before
fun setup() {
MockitoAnnotations.initMocks(this)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModelTest.kt
index ba8dcef683c7..390742031381 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModelTest.kt
@@ -61,7 +61,9 @@ class PasswordBouncerViewModelTest : SysuiTestCase() {
utils.bouncerViewModel(
bouncerInteractor = bouncerInteractor,
authenticationInteractor = authenticationInteractor,
+ actionButtonInteractor = utils.bouncerActionButtonInteractor(),
)
+
private val underTest =
PasswordBouncerViewModel(
viewModelScope = testScope.backgroundScope,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModelTest.kt
index bfaa6edefdca..47db4f8faeca 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModelTest.kt
@@ -64,6 +64,7 @@ class PatternBouncerViewModelTest : SysuiTestCase() {
utils.bouncerViewModel(
bouncerInteractor = bouncerInteractor,
authenticationInteractor = authenticationInteractor,
+ actionButtonInteractor = utils.bouncerActionButtonInteractor(),
)
private val underTest =
PatternBouncerViewModel(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt
index 7873899f2d35..3ddac7e1ad1d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt
@@ -63,6 +63,7 @@ class PinBouncerViewModelTest : SysuiTestCase() {
utils.bouncerViewModel(
bouncerInteractor = bouncerInteractor,
authenticationInteractor = authenticationInteractor,
+ actionButtonInteractor = utils.bouncerActionButtonInteractor(),
)
private val underTest =
PinBouncerViewModel(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/communal/data/repository/CommunalMediaRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/communal/data/repository/CommunalMediaRepositoryImplTest.kt
new file mode 100644
index 000000000000..455f9865edf3
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/communal/data/repository/CommunalMediaRepositoryImplTest.kt
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2023 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.systemui.communal.data.repository
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.media.controls.models.player.MediaData
+import com.android.systemui.media.controls.pipeline.MediaDataManager
+import com.android.systemui.util.mockito.KotlinArgumentCaptor
+import com.android.systemui.util.mockito.whenever
+import com.google.common.truth.Truth.assertThat
+import kotlin.test.Test
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.StandardTestDispatcher
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class CommunalMediaRepositoryImplTest : SysuiTestCase() {
+ @Mock private lateinit var mediaDataManager: MediaDataManager
+ @Mock private lateinit var mediaData: MediaData
+
+ private val mediaDataListenerCaptor: KotlinArgumentCaptor<MediaDataManager.Listener> by lazy {
+ KotlinArgumentCaptor(MediaDataManager.Listener::class.java)
+ }
+
+ private lateinit var mediaRepository: CommunalMediaRepository
+
+ private val testDispatcher = StandardTestDispatcher()
+ private val testScope = TestScope(testDispatcher)
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ }
+
+ @Test
+ fun mediaPlaying_defaultsToFalse() =
+ testScope.runTest {
+ mediaRepository = CommunalMediaRepositoryImpl(mediaDataManager)
+
+ val isMediaPlaying = collectLastValue(mediaRepository.mediaPlaying)
+ runCurrent()
+ assertThat(isMediaPlaying()).isFalse()
+ }
+
+ @Test
+ fun mediaPlaying_emitsInitialValue() =
+ testScope.runTest {
+ // Start with media available.
+ whenever(mediaDataManager.hasAnyMediaOrRecommendation()).thenReturn(true)
+
+ mediaRepository = CommunalMediaRepositoryImpl(mediaDataManager)
+
+ val isMediaPlaying = collectLastValue(mediaRepository.mediaPlaying)
+ runCurrent()
+ assertThat(isMediaPlaying()).isTrue()
+ }
+
+ @Test
+ fun mediaPlaying_updatesWhenMediaDataLoaded() =
+ testScope.runTest {
+ mediaRepository = CommunalMediaRepositoryImpl(mediaDataManager)
+
+ // Initial value is false.
+ var isMediaPlaying = collectLastValue(mediaRepository.mediaPlaying)
+ runCurrent()
+ assertThat(isMediaPlaying()).isFalse()
+
+ // Listener is added
+ verify(mediaDataManager).addListener(mediaDataListenerCaptor.capture())
+
+ // Change to media available and notify the listener.
+ whenever(mediaDataManager.hasAnyMediaOrRecommendation()).thenReturn(true)
+ mediaDataListenerCaptor.value.onMediaDataLoaded("key", null, mediaData)
+
+ // mediaPlaying now returns true.
+ isMediaPlaying = collectLastValue(mediaRepository.mediaPlaying)
+ runCurrent()
+ assertThat(isMediaPlaying()).isTrue()
+ }
+
+ @Test
+ fun mediaPlaying_updatesWhenMediaDataRemoved() =
+ testScope.runTest {
+ // Start with media available.
+ whenever(mediaDataManager.hasAnyMediaOrRecommendation()).thenReturn(true)
+
+ mediaRepository = CommunalMediaRepositoryImpl(mediaDataManager)
+
+ // Initial value is true.
+ var isMediaPlaying = collectLastValue(mediaRepository.mediaPlaying)
+ runCurrent()
+ assertThat(isMediaPlaying()).isTrue()
+
+ // Listener is added.
+ verify(mediaDataManager).addListener(mediaDataListenerCaptor.capture())
+
+ // Change to media unavailable and notify the listener.
+ whenever(mediaDataManager.hasAnyMediaOrRecommendation()).thenReturn(false)
+ mediaDataListenerCaptor.value.onMediaDataLoaded("key", null, mediaData)
+
+ // mediaPlaying now returns false.
+ isMediaPlaying = collectLastValue(mediaRepository.mediaPlaying)
+ runCurrent()
+ assertThat(isMediaPlaying()).isFalse()
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt
index 5460a1b8ce9f..08d54c001d11 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt
@@ -24,6 +24,7 @@ import android.widget.RemoteViews
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.communal.data.repository.FakeCommunalMediaRepository
import com.android.systemui.communal.data.repository.FakeCommunalRepository
import com.android.systemui.communal.data.repository.FakeCommunalTutorialRepository
import com.android.systemui.communal.data.repository.FakeCommunalWidgetRepository
@@ -58,6 +59,7 @@ class CommunalInteractorTest : SysuiTestCase() {
private lateinit var tutorialRepository: FakeCommunalTutorialRepository
private lateinit var communalRepository: FakeCommunalRepository
+ private lateinit var mediaRepository: FakeCommunalMediaRepository
private lateinit var widgetRepository: FakeCommunalWidgetRepository
private lateinit var smartspaceRepository: FakeSmartspaceRepository
private lateinit var keyguardRepository: FakeKeyguardRepository
@@ -74,6 +76,7 @@ class CommunalInteractorTest : SysuiTestCase() {
tutorialRepository = withDeps.tutorialRepository
communalRepository = withDeps.communalRepository
+ mediaRepository = withDeps.mediaRepository
widgetRepository = withDeps.widgetRepository
smartspaceRepository = withDeps.smartspaceRepository
keyguardRepository = withDeps.keyguardRepository
@@ -237,6 +240,66 @@ class CommunalInteractorTest : SysuiTestCase() {
}
@Test
+ fun umo_mediaPlaying_showsUmo() =
+ testScope.runTest {
+ // Tutorial completed.
+ tutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED)
+
+ // Media is playing.
+ mediaRepository.mediaPlaying.value = true
+
+ val communalContent by collectLastValue(underTest.communalContent)
+
+ assertThat(communalContent?.size).isEqualTo(1)
+ assertThat(communalContent?.get(0)).isInstanceOf(CommunalContentModel.Umo::class.java)
+ assertThat(communalContent?.get(0)?.key).isEqualTo(CommunalContentModel.UMO_KEY)
+ }
+
+ @Test
+ fun contentOrdering() =
+ testScope.runTest {
+ tutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED)
+
+ // Widgets available.
+ val widgets =
+ listOf(
+ CommunalWidgetContentModel(
+ appWidgetId = 0,
+ priority = 30,
+ providerInfo = mock(),
+ ),
+ CommunalWidgetContentModel(
+ appWidgetId = 1,
+ priority = 20,
+ providerInfo = mock(),
+ ),
+ )
+ widgetRepository.setCommunalWidgets(widgets)
+
+ // Smartspace available.
+ val target = mock(SmartspaceTarget::class.java)
+ whenever(target.smartspaceTargetId).thenReturn("target")
+ whenever(target.featureType).thenReturn(SmartspaceTarget.FEATURE_TIMER)
+ whenever(target.remoteViews).thenReturn(mock(RemoteViews::class.java))
+ smartspaceRepository.setLockscreenSmartspaceTargets(listOf(target))
+
+ // Media playing.
+ mediaRepository.mediaPlaying.value = true
+
+ val communalContent by collectLastValue(underTest.communalContent)
+
+ // Order is smart space, then UMO, then widget content.
+ assertThat(communalContent?.size).isEqualTo(4)
+ assertThat(communalContent?.get(0))
+ .isInstanceOf(CommunalContentModel.Smartspace::class.java)
+ assertThat(communalContent?.get(1)).isInstanceOf(CommunalContentModel.Umo::class.java)
+ assertThat(communalContent?.get(2))
+ .isInstanceOf(CommunalContentModel.Widget::class.java)
+ assertThat(communalContent?.get(3))
+ .isInstanceOf(CommunalContentModel.Widget::class.java)
+ }
+
+ @Test
fun listensToSceneChange() =
testScope.runTest {
var desiredScene = collectLastValue(underTest.desiredScene)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/complication/ComplicationCollectionLiveDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/complication/ComplicationCollectionLiveDataTest.java
index 40f0ed3626db..288f3b651a3c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/complication/ComplicationCollectionLiveDataTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/complication/ComplicationCollectionLiveDataTest.java
@@ -33,6 +33,7 @@ import com.android.systemui.flags.FakeFeatureFlags;
import com.android.systemui.flags.Flags;
import com.android.systemui.log.core.FakeLogBuffer;
import com.android.systemui.util.concurrency.FakeExecutor;
+import com.android.systemui.util.reference.FakeWeakReferenceFactory;
import com.android.systemui.util.time.FakeSystemClock;
import org.junit.Before;
@@ -68,7 +69,8 @@ public class ComplicationCollectionLiveDataTest extends SysuiTestCase {
mExecutor,
/* overlayEnabled= */ true,
mFeatureFlags,
- FakeLogBuffer.Factory.Companion.create());
+ FakeLogBuffer.Factory.Companion.create(),
+ new FakeWeakReferenceFactory());
mLiveData = new ComplicationCollectionLiveData(mStateController);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/display/domain/interactor/ConnectedDisplayInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/display/domain/interactor/ConnectedDisplayInteractorTest.kt
index 0db3de2ce0dd..1f18705edfdb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/display/domain/interactor/ConnectedDisplayInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/display/domain/interactor/ConnectedDisplayInteractorTest.kt
@@ -63,7 +63,8 @@ class ConnectedDisplayInteractorTest : SysuiTestCase() {
ConnectedDisplayInteractorImpl(
virtualDeviceManager,
fakeKeyguardRepository,
- fakeDisplayRepository
+ fakeDisplayRepository,
+ UnconfinedTestDispatcher(),
)
private val testScope = TestScope(UnconfinedTestDispatcher())
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStateControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStateControllerTest.java
index 365f67b5e566..6d5cd49b8af6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStateControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStateControllerTest.java
@@ -36,6 +36,7 @@ import com.android.systemui.flags.Flags;
import com.android.systemui.log.LogBuffer;
import com.android.systemui.log.core.FakeLogBuffer;
import com.android.systemui.util.concurrency.FakeExecutor;
+import com.android.systemui.util.reference.FakeWeakReferenceFactory;
import com.android.systemui.util.time.FakeSystemClock;
import org.junit.Before;
@@ -63,6 +64,8 @@ public class DreamOverlayStateControllerTest extends SysuiTestCase {
final FakeExecutor mExecutor = new FakeExecutor(new FakeSystemClock());
+ final FakeWeakReferenceFactory mWeakReferenceFactory = new FakeWeakReferenceFactory();
+
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
@@ -407,12 +410,36 @@ public class DreamOverlayStateControllerTest extends SysuiTestCase {
assertThat(stateController.getComplications()).contains(homeControlsComplication);
}
+ @Test
+ public void testCallbacksIgnoredWhenWeakReferenceCleared() {
+ final DreamOverlayStateController.Callback callback1 = Mockito.mock(
+ DreamOverlayStateController.Callback.class);
+ final DreamOverlayStateController.Callback callback2 = Mockito.mock(
+ DreamOverlayStateController.Callback.class);
+
+ final DreamOverlayStateController stateController = getDreamOverlayStateController(true);
+ stateController.addCallback(callback1);
+ stateController.addCallback(callback2);
+ mExecutor.runAllReady();
+
+ // Simulate callback1 getting GC'd by clearing the reference
+ mWeakReferenceFactory.clear(callback1);
+ stateController.setOverlayActive(true);
+ mExecutor.runAllReady();
+
+ // Callback2 should still be called, but never callback1
+ verify(callback1, never()).onStateChanged();
+ verify(callback2).onStateChanged();
+ assertThat(stateController.isOverlayActive()).isTrue();
+ }
+
private DreamOverlayStateController getDreamOverlayStateController(boolean overlayEnabled) {
return new DreamOverlayStateController(
mExecutor,
overlayEnabled,
mFeatureFlags,
- mLogBuffer
+ mLogBuffer,
+ mWeakReferenceFactory
);
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyboard/backlight/ui/view/KeyboardBacklightDialogTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyboard/backlight/ui/view/KeyboardBacklightDialogTest.kt
deleted file mode 100644
index 8b572eb3d906..000000000000
--- a/packages/SystemUI/tests/src/com/android/systemui/keyboard/backlight/ui/view/KeyboardBacklightDialogTest.kt
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright (C) 2023 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.systemui.keyboard.backlight.ui.view
-
-import android.testing.TestableLooper.RunWithLooper
-import android.view.View
-import android.view.accessibility.AccessibilityEvent
-import androidx.test.filters.SmallTest
-import com.android.systemui.SysuiTestCase
-import com.android.systemui.res.R
-import com.google.common.truth.Truth.assertThat
-import org.junit.Before
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
-
-@RunWithLooper
-@SmallTest
-@RunWith(JUnit4::class)
-class KeyboardBacklightDialogTest : SysuiTestCase() {
-
- private lateinit var dialog: KeyboardBacklightDialog
- private lateinit var rootView: View
- private val descriptionString = context.getString(R.string.keyboard_backlight_value)
-
- @Before
- fun setUp() {
- dialog =
- KeyboardBacklightDialog(context, initialCurrentLevel = 0, initialMaxLevel = MAX_LEVEL)
- dialog.show()
- rootView = dialog.requireViewById(R.id.keyboard_backlight_dialog_container)
- }
-
- @Test
- fun rootViewContentDescription_containsInitialLevel() {
- assertThat(rootView.contentDescription).isEqualTo(contentDescriptionForLevel(INITIAL_LEVEL))
- }
-
- @Test
- fun contentDescriptionUpdated_afterEveryLevelUpdate() {
- val events = startCollectingAccessibilityEvents(rootView)
-
- dialog.updateState(current = 1, max = MAX_LEVEL)
-
- assertThat(rootView.contentDescription).isEqualTo(contentDescriptionForLevel(1))
- assertThat(events).contains(AccessibilityEvent.CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION)
- }
-
- private fun contentDescriptionForLevel(level: Int): String {
- return String.format(descriptionString, level, MAX_LEVEL)
- }
-
- private fun startCollectingAccessibilityEvents(rootView: View): MutableList<Int> {
- val events = mutableListOf<Int>()
- rootView.accessibilityDelegate =
- object : View.AccessibilityDelegate() {
- override fun sendAccessibilityEvent(host: View, eventType: Int) {
- super.sendAccessibilityEvent(host, eventType)
- events.add(eventType)
- }
- }
- return events
- }
-
- companion object {
- private const val MAX_LEVEL = 5
- private const val INITIAL_LEVEL = 0
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/BiometricSettingsRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/BiometricSettingsRepositoryTest.kt
index 90fd6523ec12..4587ea6dbdc8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/BiometricSettingsRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/BiometricSettingsRepositoryTest.kt
@@ -154,6 +154,7 @@ class BiometricSettingsRepositoryTest : SysuiTestCase() {
fun fingerprintEnrollmentChange() =
testScope.runTest {
createBiometricSettingsRepository()
+ biometricsAreEnabledBySettings()
val fingerprintAllowed = collectLastValue(underTest.isFingerprintEnrolledAndEnabled)
runCurrent()
@@ -170,11 +171,34 @@ class BiometricSettingsRepositoryTest : SysuiTestCase() {
}
@Test
+ fun fingerprintEnabledStateChange() =
+ testScope.runTest {
+ createBiometricSettingsRepository()
+ biometricsAreEnabledBySettings()
+ val fingerprintAllowed = collectLastValue(underTest.isFingerprintEnrolledAndEnabled)
+ runCurrent()
+
+ // start state
+ whenever(authController.isFingerprintEnrolled(anyInt())).thenReturn(true)
+ enrollmentChange(UNDER_DISPLAY_FINGERPRINT, PRIMARY_USER_ID, true)
+ assertThat(fingerprintAllowed()).isTrue()
+
+ // when biometrics are not enabled by settings
+ biometricsAreNotEnabledBySettings()
+ assertThat(fingerprintAllowed()).isFalse()
+
+ // when biometrics are enabled by settings
+ biometricsAreEnabledBySettings()
+ assertThat(fingerprintAllowed()).isTrue()
+ }
+
+ @Test
fun strongBiometricAllowedChange() =
testScope.runTest {
fingerprintIsEnrolled()
doNotDisableKeyguardAuthFeatures()
createBiometricSettingsRepository()
+ biometricsAreEnabledBySettings()
val strongBiometricAllowed by
collectLastValue(underTest.isFingerprintAuthCurrentlyAllowed)
@@ -197,7 +221,7 @@ class BiometricSettingsRepositoryTest : SysuiTestCase() {
createBiometricSettingsRepository()
val convenienceFaceAuthAllowed by collectLastValue(underTest.isFaceAuthCurrentlyAllowed)
doNotDisableKeyguardAuthFeatures()
- faceAuthIsEnabledByBiometricManager()
+ biometricsAreEnabledBySettings()
onStrongAuthChanged(STRONG_AUTH_NOT_REQUIRED, PRIMARY_USER_ID)
onNonStrongAuthChanged(true, PRIMARY_USER_ID)
@@ -238,6 +262,7 @@ class BiometricSettingsRepositoryTest : SysuiTestCase() {
faceAuthIsNonStrongBiometric()
faceAuthIsEnrolled()
doNotDisableKeyguardAuthFeatures()
+ biometricsAreEnabledBySettings()
val convenienceBiometricAllowed = collectLastValue(underTest.isFaceAuthCurrentlyAllowed)
runCurrent()
@@ -258,7 +283,7 @@ class BiometricSettingsRepositoryTest : SysuiTestCase() {
faceAuthIsEnrolled()
createBiometricSettingsRepository()
doNotDisableKeyguardAuthFeatures()
- faceAuthIsEnabledByBiometricManager()
+ biometricsAreEnabledBySettings()
runCurrent()
val convenienceBiometricAllowed by
@@ -291,6 +316,7 @@ class BiometricSettingsRepositoryTest : SysuiTestCase() {
testScope.runTest {
fingerprintIsEnrolled(PRIMARY_USER_ID)
createBiometricSettingsRepository()
+ biometricsAreEnabledBySettings()
val fingerprintEnabledByDevicePolicy =
collectLastValue(underTest.isFingerprintEnrolledAndEnabled)
@@ -316,7 +342,7 @@ class BiometricSettingsRepositoryTest : SysuiTestCase() {
createBiometricSettingsRepository()
val faceAuthAllowed = collectLastValue(underTest.isFaceAuthEnrolledAndEnabled)
- faceAuthIsEnabledByBiometricManager()
+ biometricsAreEnabledBySettings()
doNotDisableKeyguardAuthFeatures(PRIMARY_USER_ID)
@@ -351,12 +377,18 @@ class BiometricSettingsRepositoryTest : SysuiTestCase() {
assertThat(faceAuthAllowed()).isTrue()
}
- private fun faceAuthIsEnabledByBiometricManager(userId: Int = PRIMARY_USER_ID) {
+ private fun biometricsAreEnabledBySettings(userId: Int = PRIMARY_USER_ID) {
verify(biometricManager, atLeastOnce())
.registerEnabledOnKeyguardCallback(biometricManagerCallback.capture())
biometricManagerCallback.value.onChanged(true, userId)
}
+ private fun biometricsAreNotEnabledBySettings(userId: Int = PRIMARY_USER_ID) {
+ verify(biometricManager, atLeastOnce())
+ .registerEnabledOnKeyguardCallback(biometricManagerCallback.capture())
+ biometricManagerCallback.value.onChanged(false, userId)
+ }
+
@Test
fun faceEnrollmentStatusOfNewUserUponUserSwitch() =
testScope.runTest {
@@ -427,7 +459,7 @@ class BiometricSettingsRepositoryTest : SysuiTestCase() {
faceAuthIsEnrolled()
createBiometricSettingsRepository()
- faceAuthIsEnabledByBiometricManager()
+ biometricsAreEnabledBySettings()
doNotDisableKeyguardAuthFeatures()
mobileConnectionsRepository.isAnySimSecure.value = false
runCurrent()
@@ -454,7 +486,7 @@ class BiometricSettingsRepositoryTest : SysuiTestCase() {
deviceIsInPostureThatSupportsFaceAuth()
doNotDisableKeyguardAuthFeatures()
faceAuthIsStrongBiometric()
- faceAuthIsEnabledByBiometricManager()
+ biometricsAreEnabledBySettings()
mobileConnectionsRepository.isAnySimSecure.value = false
onStrongAuthChanged(STRONG_AUTH_NOT_REQUIRED, PRIMARY_USER_ID)
@@ -636,7 +668,7 @@ class BiometricSettingsRepositoryTest : SysuiTestCase() {
deviceIsInPostureThatSupportsFaceAuth()
doNotDisableKeyguardAuthFeatures()
faceAuthIsStrongBiometric()
- faceAuthIsEnabledByBiometricManager()
+ biometricsAreEnabledBySettings()
onStrongAuthChanged(STRONG_AUTH_NOT_REQUIRED, PRIMARY_USER_ID)
onNonStrongAuthChanged(false, PRIMARY_USER_ID)
@@ -660,7 +692,7 @@ class BiometricSettingsRepositoryTest : SysuiTestCase() {
deviceIsInPostureThatSupportsFaceAuth()
doNotDisableKeyguardAuthFeatures()
faceAuthIsNonStrongBiometric()
- faceAuthIsEnabledByBiometricManager()
+ biometricsAreEnabledBySettings()
onStrongAuthChanged(STRONG_AUTH_NOT_REQUIRED, PRIMARY_USER_ID)
onNonStrongAuthChanged(false, PRIMARY_USER_ID)
@@ -682,6 +714,7 @@ class BiometricSettingsRepositoryTest : SysuiTestCase() {
fun fpAuthCurrentlyAllowed_dependsOnNonStrongAuthBiometricSetting_ifFpIsNotStrong() =
testScope.runTest {
createBiometricSettingsRepository()
+ biometricsAreEnabledBySettings()
val isFingerprintCurrentlyAllowed by
collectLastValue(underTest.isFingerprintAuthCurrentlyAllowed)
@@ -723,6 +756,7 @@ class BiometricSettingsRepositoryTest : SysuiTestCase() {
fun fpAuthCurrentlyAllowed_dependsOnStrongAuthBiometricSetting_ifFpIsStrong() =
testScope.runTest {
createBiometricSettingsRepository()
+ biometricsAreEnabledBySettings()
val isFingerprintCurrentlyAllowed by
collectLastValue(underTest.isFingerprintAuthCurrentlyAllowed)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/KeyguardMediaControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/KeyguardMediaControllerTest.kt
index 7ad2ce8ae110..f4293f035cd1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/KeyguardMediaControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/KeyguardMediaControllerTest.kt
@@ -24,6 +24,7 @@ import android.view.View.GONE
import android.view.View.VISIBLE
import android.widget.FrameLayout
import com.android.systemui.SysuiTestCase
+import com.android.systemui.dump.DumpManager
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.statusbar.StatusBarState
import com.android.systemui.statusbar.SysuiStatusBarStateController
@@ -32,6 +33,7 @@ import com.android.systemui.statusbar.phone.KeyguardBypassController
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.statusbar.policy.ResourcesSplitShadeStateController
import com.android.systemui.util.animation.UniqueObjectHostView
+import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
import com.android.systemui.util.settings.FakeSettings
import com.android.systemui.utils.os.FakeHandler
@@ -91,7 +93,8 @@ class KeyguardMediaControllerTest : SysuiTestCase() {
settings,
fakeHandler,
configurationController,
- ResourcesSplitShadeStateController()
+ ResourcesSplitShadeStateController(),
+ mock<DumpManager>()
)
keyguardMediaController.attachSinglePaneContainer(mediaContainerView)
keyguardMediaController.useSplitShade = false
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/gestural/BackPanelControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/gestural/BackPanelControllerTest.kt
index 2d3dc585ac70..f93d52b2c35c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/gestural/BackPanelControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/gestural/BackPanelControllerTest.kt
@@ -30,8 +30,6 @@ import android.view.WindowManager
import androidx.test.filters.SmallTest
import com.android.internal.util.LatencyTracker
import com.android.systemui.SysuiTestCase
-import com.android.systemui.flags.FakeFeatureFlags
-import com.android.systemui.flags.Flags.ONE_WAY_HAPTICS_API_MIGRATION
import com.android.systemui.plugins.NavigationEdgeBackPlugin
import com.android.systemui.statusbar.VibratorHelper
import com.android.systemui.statusbar.policy.ConfigurationController
@@ -63,7 +61,6 @@ class BackPanelControllerTest : SysuiTestCase() {
@Mock private lateinit var latencyTracker: LatencyTracker
@Mock private lateinit var layoutParams: WindowManager.LayoutParams
@Mock private lateinit var backCallback: NavigationEdgeBackPlugin.BackCallback
- private val featureFlags = FakeFeatureFlags()
@Before
fun setup() {
@@ -77,7 +74,6 @@ class BackPanelControllerTest : SysuiTestCase() {
vibratorHelper,
configurationController,
latencyTracker,
- featureFlags
)
mBackPanelController.setLayoutParams(layoutParams)
mBackPanelController.setBackCallback(backCallback)
@@ -106,32 +102,6 @@ class BackPanelControllerTest : SysuiTestCase() {
@Test
fun handlesBackCommitted() {
- featureFlags.set(ONE_WAY_HAPTICS_API_MIGRATION, false)
- startTouch()
- // Move once to cross the touch slop
- continueTouch(START_X + touchSlop.toFloat() + 1)
- // Move again to cross the back trigger threshold
- continueTouch(START_X + touchSlop + triggerThreshold + 1)
- // Wait threshold duration and hold touch past trigger threshold
- Thread.sleep((MAX_DURATION_ENTRY_BEFORE_ACTIVE_ANIMATION + 1).toLong())
- continueTouch(START_X + touchSlop + triggerThreshold + 1)
-
- assertThat(mBackPanelController.currentState)
- .isEqualTo(BackPanelController.GestureState.ACTIVE)
- verify(backCallback).setTriggerBack(true)
- testableLooper.moveTimeForward(100)
- testableLooper.processAllMessages()
- verify(vibratorHelper).vibrate(VIBRATE_ACTIVATED_EFFECT)
-
- finishTouchActionUp(START_X + touchSlop + triggerThreshold + 1)
- assertThat(mBackPanelController.currentState)
- .isEqualTo(BackPanelController.GestureState.COMMITTED)
- verify(backCallback).triggerBack()
- }
-
- @Test
- fun handlesBackCommitted_withOneWayHapticsAPI() {
- featureFlags.set(ONE_WAY_HAPTICS_API_MIGRATION, true)
startTouch()
// Move once to cross the touch slop
continueTouch(START_X + touchSlop.toFloat() + 1)
@@ -148,7 +118,6 @@ class BackPanelControllerTest : SysuiTestCase() {
testableLooper.processAllMessages()
verify(vibratorHelper)
.performHapticFeedback(any(), eq(HapticFeedbackConstants.GESTURE_THRESHOLD_ACTIVATE))
-
finishTouchActionUp(START_X + touchSlop + triggerThreshold + 1)
assertThat(mBackPanelController.currentState)
.isEqualTo(BackPanelController.GestureState.COMMITTED)
@@ -157,38 +126,6 @@ class BackPanelControllerTest : SysuiTestCase() {
@Test
fun handlesBackCancelled() {
- featureFlags.set(ONE_WAY_HAPTICS_API_MIGRATION, false)
- startTouch()
- // Move once to cross the touch slop
- continueTouch(START_X + touchSlop.toFloat() + 1)
- // Move again to cross the back trigger threshold
- continueTouch(
- START_X + touchSlop + triggerThreshold -
- mBackPanelController.params.deactivationTriggerThreshold
- )
- // Wait threshold duration and hold touch before trigger threshold
- Thread.sleep((MAX_DURATION_ENTRY_BEFORE_ACTIVE_ANIMATION + 1).toLong())
- continueTouch(
- START_X + touchSlop + triggerThreshold -
- mBackPanelController.params.deactivationTriggerThreshold
- )
- clearInvocations(backCallback)
- Thread.sleep(MIN_DURATION_ACTIVE_BEFORE_INACTIVE_ANIMATION)
- // Move in the opposite direction to cross the deactivation threshold and cancel back
- continueTouch(START_X)
-
- assertThat(mBackPanelController.currentState)
- .isEqualTo(BackPanelController.GestureState.INACTIVE)
- verify(backCallback).setTriggerBack(false)
- verify(vibratorHelper).vibrate(VIBRATE_DEACTIVATED_EFFECT)
-
- finishTouchActionUp(START_X)
- verify(backCallback).cancelBack()
- }
-
- @Test
- fun handlesBackCancelled_withOneWayHapticsAPI() {
- featureFlags.set(ONE_WAY_HAPTICS_API_MIGRATION, true)
startTouch()
// Move once to cross the touch slop
continueTouch(START_X + touchSlop.toFloat() + 1)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/power/data/repository/PowerRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/power/data/repository/PowerRepositoryImplTest.kt
index f566efe6f176..f3b114d662b5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/power/data/repository/PowerRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/power/data/repository/PowerRepositoryImplTest.kt
@@ -210,6 +210,22 @@ class PowerRepositoryImplTest : SysuiTestCase() {
assertThat(flagsCaptor.value).isNotEqualTo(PowerManager.USER_ACTIVITY_FLAG_INDIRECT)
}
+ @Test
+ fun userActivity_notifiesPowerManager_noChangeLightsTrue() {
+ systemClock.setUptimeMillis(345000)
+
+ underTest.userTouch(noChangeLights = true)
+
+ val flagsCaptor = argumentCaptor<Int>()
+ verify(manager)
+ .userActivity(
+ eq(345000L),
+ eq(PowerManager.USER_ACTIVITY_EVENT_TOUCH),
+ capture(flagsCaptor)
+ )
+ assertThat(flagsCaptor.value).isEqualTo(PowerManager.USER_ACTIVITY_FLAG_NO_CHANGE_LIGHTS)
+ }
+
private fun verifyRegistered() {
// We must verify with all arguments, even those that are optional because they have default
// values because Mockito is forcing us to. Once we can use mockito-kotlin, we should be
diff --git a/packages/SystemUI/tests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt b/packages/SystemUI/tests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt
index 3feb5bfd088a..e84d274b4763 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt
@@ -18,17 +18,23 @@
package com.android.systemui.scene
+import android.telecom.TelecomManager
+import android.telephony.TelephonyManager
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
+import com.android.internal.R
+import com.android.internal.util.EmergencyAffordanceManager
import com.android.systemui.SysuiTestCase
import com.android.systemui.authentication.data.repository.FakeAuthenticationRepository
import com.android.systemui.authentication.domain.model.AuthenticationMethodModel as DomainLayerAuthenticationMethodModel
+import com.android.systemui.bouncer.domain.interactor.BouncerActionButtonInteractor
+import com.android.systemui.bouncer.ui.viewmodel.BouncerViewModel
import com.android.systemui.bouncer.ui.viewmodel.PinBouncerViewModel
import com.android.systemui.coroutines.collectLastValue
-import com.android.systemui.flags.FakeFeatureFlagsClassic
import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.ui.viewmodel.KeyguardLongPressViewModel
import com.android.systemui.keyguard.ui.viewmodel.LockscreenSceneViewModel
+import com.android.systemui.log.table.TableLogBuffer
import com.android.systemui.model.SysUiState
import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setAsleepForTest
import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setAwakeForTest
@@ -49,7 +55,9 @@ import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.FakeMobi
import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.MobileIconsViewModel
import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy
import com.android.systemui.statusbar.pipeline.shared.data.repository.FakeConnectivityRepository
+import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
import com.google.common.truth.Truth.assertWithMessage
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -63,6 +71,10 @@ import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.times
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
/**
* Integration test cases for the Scene Framework.
@@ -87,6 +99,10 @@ import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
class SceneFrameworkIntegrationTest : SysuiTestCase() {
+ @Mock private lateinit var emergencyAffordanceManager: EmergencyAffordanceManager
+ @Mock private lateinit var tableLogger: TableLogBuffer
+ @Mock private lateinit var telecomManager: TelecomManager
+
private val utils = SceneTestUtils(this)
private val testScope = utils.testScope
private val sceneContainerConfig = utils.fakeSceneContainerConfig()
@@ -123,11 +139,10 @@ class SceneFrameworkIntegrationTest : SysuiTestCase() {
authenticationInteractor = authenticationInteractor,
sceneInteractor = sceneInteractor,
)
- private val bouncerViewModel =
- utils.bouncerViewModel(
- bouncerInteractor = bouncerInteractor,
- authenticationInteractor = authenticationInteractor,
- )
+
+ private lateinit var mobileConnectionsRepository: FakeMobileConnectionsRepository
+ private lateinit var bouncerActionButtonInteractor: BouncerActionButtonInteractor
+ private lateinit var bouncerViewModel: BouncerViewModel
private val lockscreenSceneViewModel =
LockscreenSceneViewModel(
@@ -141,7 +156,6 @@ class SceneFrameworkIntegrationTest : SysuiTestCase() {
)
private val mobileIconsInteractor = FakeMobileIconsInteractor(FakeMobileMappingsProxy(), mock())
- private val flags = FakeFeatureFlagsClassic().also { it.set(Flags.NEW_NETWORK_SLICE_UI, false) }
private var mobileIconsViewModel: MobileIconsViewModel =
MobileIconsViewModel(
@@ -155,7 +169,7 @@ class SceneFrameworkIntegrationTest : SysuiTestCase() {
FakeMobileConnectionsRepository(),
),
constants = mock(),
- flags,
+ utils.featureFlags,
scope = testScope.backgroundScope,
)
@@ -173,6 +187,39 @@ class SceneFrameworkIntegrationTest : SysuiTestCase() {
@Before
fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ overrideResource(R.bool.config_enable_emergency_call_while_sim_locked, true)
+ whenever(telecomManager.isInCall).thenReturn(false)
+ whenever(emergencyAffordanceManager.needsEmergencyAffordance()).thenReturn(true)
+
+ utils.featureFlags.apply {
+ set(Flags.NEW_NETWORK_SLICE_UI, false)
+ set(Flags.REFACTOR_GETCURRENTUSER, true)
+ }
+
+ mobileConnectionsRepository =
+ FakeMobileConnectionsRepository(FakeMobileMappingsProxy(), tableLogger)
+ mobileConnectionsRepository.isAnySimSecure.value = true
+
+ utils.telephonyRepository.apply {
+ setHasTelephonyRadio(true)
+ setCallState(TelephonyManager.CALL_STATE_IDLE)
+ setIsInCall(false)
+ }
+
+ bouncerActionButtonInteractor =
+ utils.bouncerActionButtonInteractor(
+ mobileConnectionsRepository = mobileConnectionsRepository,
+ telecomManager = telecomManager,
+ emergencyAffordanceManager = emergencyAffordanceManager,
+ )
+ bouncerViewModel =
+ utils.bouncerViewModel(
+ bouncerInteractor = bouncerInteractor,
+ authenticationInteractor = authenticationInteractor,
+ actionButtonInteractor = bouncerActionButtonInteractor,
+ )
+
shadeHeaderViewModel =
ShadeHeaderViewModel(
applicationScope = testScope.backgroundScope,
@@ -395,6 +442,45 @@ class SceneFrameworkIntegrationTest : SysuiTestCase() {
emulateUiSceneTransition()
}
+ @Test
+ fun bouncerActionButtonClick_opensEmergencyServicesDialer() =
+ testScope.runTest {
+ setAuthMethod(DomainLayerAuthenticationMethodModel.Password)
+ val upDestinationSceneKey by
+ collectLastValue(lockscreenSceneViewModel.upDestinationSceneKey)
+ assertThat(upDestinationSceneKey).isEqualTo(SceneKey.Bouncer)
+ emulateUserDrivenTransition(to = upDestinationSceneKey)
+
+ val bouncerActionButton by collectLastValue(bouncerViewModel.actionButton)
+ assertWithMessage("Bouncer action button not visible")
+ .that(bouncerActionButton)
+ .isNotNull()
+ bouncerActionButton?.onClick?.invoke()
+ runCurrent()
+
+ // TODO(b/298026988): Assert that an activity was started once we use ActivityStarter.
+ }
+
+ @Test
+ fun bouncerActionButtonClick_duringCall_returnsToCall() =
+ testScope.runTest {
+ setAuthMethod(DomainLayerAuthenticationMethodModel.Password)
+ startPhoneCall()
+ val upDestinationSceneKey by
+ collectLastValue(lockscreenSceneViewModel.upDestinationSceneKey)
+ assertThat(upDestinationSceneKey).isEqualTo(SceneKey.Bouncer)
+ emulateUserDrivenTransition(to = upDestinationSceneKey)
+
+ val bouncerActionButton by collectLastValue(bouncerViewModel.actionButton)
+ assertWithMessage("Bouncer action button not visible during call")
+ .that(bouncerActionButton)
+ .isNotNull()
+ bouncerActionButton?.onClick?.invoke()
+ runCurrent()
+
+ verify(telecomManager).showInCallScreen(any())
+ }
+
/**
* Asserts that the current scene in the view-model matches what's expected.
*
@@ -438,6 +524,17 @@ class SceneFrameworkIntegrationTest : SysuiTestCase() {
runCurrent()
}
+ /** Emulates a phone call in progress. */
+ private fun TestScope.startPhoneCall() {
+ whenever(telecomManager.isInCall).thenReturn(true)
+ utils.telephonyRepository.apply {
+ setHasTelephonyRadio(true)
+ setIsInCall(true)
+ setCallState(TelephonyManager.CALL_STATE_OFFHOOK)
+ }
+ runCurrent()
+ }
+
/**
* Emulates a complete transition in the UI from whatever the current scene is in the UI to
* whatever the current scene should be, based on the value in
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingControllerTest.java
index 49049bc51460..1b4ba6433ded 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingControllerTest.java
@@ -36,20 +36,27 @@ import android.content.Intent;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
+import androidx.annotation.Nullable;
import androidx.test.filters.SmallTest;
+import com.android.systemui.Dependency;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.animation.DialogLaunchAnimator;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.flags.FakeFeatureFlags;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
import com.android.systemui.mediaprojection.MediaProjectionMetricsLogger;
import com.android.systemui.mediaprojection.SessionCreationSource;
import com.android.systemui.mediaprojection.devicepolicy.ScreenCaptureDevicePolicyResolver;
import com.android.systemui.mediaprojection.devicepolicy.ScreenCaptureDisabledDialog;
+import com.android.systemui.model.SysUiState;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.settings.UserContextProvider;
import com.android.systemui.settings.UserTracker;
+import com.android.systemui.statusbar.phone.DialogDelegate;
+import com.android.systemui.statusbar.phone.SystemUIDialog;
+import com.android.systemui.statusbar.phone.SystemUIDialogManager;
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.time.FakeSystemClock;
@@ -92,6 +99,7 @@ public class RecordingControllerTest extends SysuiTestCase {
private FakeFeatureFlags mFeatureFlags;
private RecordingController mController;
+ private TestSystemUIDialogFactory mDialogFactory;
private static final int USER_ID = 10;
@@ -103,6 +111,15 @@ public class RecordingControllerTest extends SysuiTestCase {
when(mUserContextProvider.getUserContext()).thenReturn(spiedContext);
+ mDialogFactory = new TestSystemUIDialogFactory(
+ mContext,
+ mFeatureFlags,
+ Dependency.get(SystemUIDialogManager.class),
+ Dependency.get(SysUiState.class),
+ Dependency.get(BroadcastDispatcher.class),
+ Dependency.get(DialogLaunchAnimator.class)
+ );
+
mFeatureFlags = new FakeFeatureFlags();
mController = new RecordingController(
mMainExecutor,
@@ -112,7 +129,8 @@ public class RecordingControllerTest extends SysuiTestCase {
mUserContextProvider,
() -> mDevicePolicyResolver,
mUserTracker,
- mMediaProjectionMetricsLogger);
+ mMediaProjectionMetricsLogger,
+ mDialogFactory);
mController.addCallback(mCallback);
}
@@ -218,10 +236,17 @@ public class RecordingControllerTest extends SysuiTestCase {
mFeatureFlags.set(Flags.WM_ENABLE_PARTIAL_SCREEN_SHARING_ENTERPRISE_POLICIES, false);
when(mDevicePolicyResolver.isScreenCaptureCompletelyDisabled((any()))).thenReturn(true);
- Dialog dialog = mController.createScreenRecordDialog(mContext, mFeatureFlags,
- mDialogLaunchAnimator, mActivityStarter, /* onStartRecordingClicked= */ null);
-
- assertThat(dialog).isInstanceOf(ScreenRecordPermissionDialog.class);
+ Dialog dialog =
+ mController.createScreenRecordDialog(
+ mContext,
+ mFeatureFlags,
+ mDialogLaunchAnimator,
+ mActivityStarter,
+ /* onStartRecordingClicked= */ null);
+
+ assertThat(dialog).isSameInstanceAs(mDialogFactory.mLastCreatedDialog);
+ assertThat(mDialogFactory.mLastDelegate)
+ .isInstanceOf(ScreenRecordPermissionDialogDelegate.class);
}
@Test
@@ -253,10 +278,17 @@ public class RecordingControllerTest extends SysuiTestCase {
mFeatureFlags.set(Flags.WM_ENABLE_PARTIAL_SCREEN_SHARING_ENTERPRISE_POLICIES, true);
when(mDevicePolicyResolver.isScreenCaptureCompletelyDisabled((any()))).thenReturn(false);
- Dialog dialog = mController.createScreenRecordDialog(mContext, mFeatureFlags,
- mDialogLaunchAnimator, mActivityStarter, /* onStartRecordingClicked= */ null);
-
- assertThat(dialog).isInstanceOf(ScreenRecordPermissionDialog.class);
+ Dialog dialog =
+ mController.createScreenRecordDialog(
+ mContext,
+ mFeatureFlags,
+ mDialogLaunchAnimator,
+ mActivityStarter,
+ /* onStartRecordingClicked= */ null);
+
+ assertThat(dialog).isSameInstanceAs(mDialogFactory.mLastCreatedDialog);
+ assertThat(mDialogFactory.mLastDelegate)
+ .isInstanceOf(ScreenRecordPermissionDialogDelegate.class);
}
@Test
@@ -273,4 +305,34 @@ public class RecordingControllerTest extends SysuiTestCase {
/* hostUid= */ myUid(),
SessionCreationSource.SYSTEM_UI_SCREEN_RECORDER);
}
+
+ private static class TestSystemUIDialogFactory extends SystemUIDialog.Factory {
+
+ @Nullable private DialogDelegate<SystemUIDialog> mLastDelegate;
+ @Nullable private SystemUIDialog mLastCreatedDialog;
+
+ TestSystemUIDialogFactory(
+ Context context,
+ FeatureFlags featureFlags,
+ SystemUIDialogManager systemUIDialogManager,
+ SysUiState sysUiState,
+ BroadcastDispatcher broadcastDispatcher,
+ DialogLaunchAnimator dialogLaunchAnimator) {
+ super(
+ context,
+ featureFlags,
+ systemUIDialogManager,
+ sysUiState,
+ broadcastDispatcher,
+ dialogLaunchAnimator);
+ }
+
+ @Override
+ public SystemUIDialog create(DialogDelegate<SystemUIDialog> delegate) {
+ SystemUIDialog dialog = super.create(delegate);
+ mLastDelegate = delegate;
+ mLastCreatedDialog = dialog;
+ return dialog;
+ }
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialogTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialogDelegateTest.kt
index fd381392c3e9..c848287aa53e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialogTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialogDelegateTest.kt
@@ -23,16 +23,22 @@ import android.testing.TestableLooper
import android.view.View
import android.widget.Spinner
import androidx.test.filters.SmallTest
+import com.android.systemui.Dependency
import com.android.systemui.SysuiTestCase
+import com.android.systemui.animation.DialogLaunchAnimator
+import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
import com.android.systemui.mediaprojection.MediaProjectionMetricsLogger
import com.android.systemui.mediaprojection.appselector.MediaProjectionAppSelectorActivity
import com.android.systemui.mediaprojection.permission.ENTIRE_SCREEN
import com.android.systemui.mediaprojection.permission.SINGLE_APP
+import com.android.systemui.model.SysUiState
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.res.R
import com.android.systemui.settings.UserContextProvider
+import com.android.systemui.statusbar.phone.SystemUIDialog
+import com.android.systemui.statusbar.phone.SystemUIDialogManager
import com.android.systemui.util.mockito.argumentCaptor
import com.android.systemui.util.mockito.mock
import com.google.common.truth.Truth.assertThat
@@ -50,7 +56,7 @@ import org.mockito.MockitoAnnotations
@SmallTest
@RunWith(AndroidTestingRunner::class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
-class ScreenRecordPermissionDialogTest : SysuiTestCase() {
+class ScreenRecordPermissionDialogDelegateTest : SysuiTestCase() {
@Mock private lateinit var starter: ActivityStarter
@Mock private lateinit var controller: RecordingController
@@ -59,15 +65,23 @@ class ScreenRecordPermissionDialogTest : SysuiTestCase() {
@Mock private lateinit var onStartRecordingClicked: Runnable
@Mock private lateinit var mediaProjectionMetricsLogger: MediaProjectionMetricsLogger
- private lateinit var dialog: ScreenRecordPermissionDialog
+ private lateinit var dialog: SystemUIDialog
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
- dialog =
- ScreenRecordPermissionDialog(
+ val systemUIDialogFactory =
+ SystemUIDialog.Factory(
context,
+ Dependency.get(FeatureFlags::class.java),
+ Dependency.get(SystemUIDialogManager::class.java),
+ Dependency.get(SysUiState::class.java),
+ Dependency.get(BroadcastDispatcher::class.java),
+ Dependency.get(DialogLaunchAnimator::class.java),
+ )
+ val delegate =
+ ScreenRecordPermissionDialogDelegate(
UserHandle.of(0),
TEST_HOST_UID,
controller,
@@ -76,20 +90,21 @@ class ScreenRecordPermissionDialogTest : SysuiTestCase() {
onStartRecordingClicked,
mediaProjectionMetricsLogger,
)
- dialog.onCreate(null)
+ dialog = systemUIDialogFactory.create(delegate)
+ delegate.onCreate(dialog, savedInstanceState = null)
whenever(flags.isEnabled(Flags.WM_ENABLE_PARTIAL_SCREEN_SHARING)).thenReturn(true)
}
@After
fun teardown() {
if (::dialog.isInitialized) {
- dialog.dismiss()
+ dismissDialog()
}
}
@Test
fun testShowDialog_partialScreenSharingEnabled_optionsSpinnerIsVisible() {
- dialog.show()
+ showDialog()
val visibility = dialog.requireViewById<Spinner>(R.id.screen_share_mode_spinner).visibility
assertThat(visibility).isEqualTo(View.VISIBLE)
@@ -97,7 +112,7 @@ class ScreenRecordPermissionDialogTest : SysuiTestCase() {
@Test
fun testShowDialog_singleAppSelected_showTapsIsGone() {
- dialog.show()
+ showDialog()
onSpinnerItemSelected(SINGLE_APP)
val visibility = dialog.requireViewById<View>(R.id.show_taps).visibility
@@ -106,7 +121,7 @@ class ScreenRecordPermissionDialogTest : SysuiTestCase() {
@Test
fun testShowDialog_entireScreenSelected_showTapsIsVisible() {
- dialog.show()
+ showDialog()
onSpinnerItemSelected(ENTIRE_SCREEN)
val visibility = dialog.requireViewById<View>(R.id.show_taps).visibility
@@ -115,7 +130,7 @@ class ScreenRecordPermissionDialogTest : SysuiTestCase() {
@Test
fun startClicked_singleAppSelected_passesHostUidToAppSelector() {
- dialog.show()
+ showDialog()
onSpinnerItemSelected(SINGLE_APP)
clickOnStart()
@@ -128,14 +143,14 @@ class ScreenRecordPermissionDialogTest : SysuiTestCase() {
@Test
fun showDialog_dialogIsShowing() {
- dialog.show()
+ showDialog()
assertThat(dialog.isShowing).isTrue()
}
@Test
fun showDialog_singleAppIsDefault() {
- dialog.show()
+ showDialog()
val spinner = dialog.requireViewById<Spinner>(R.id.screen_share_mode_spinner)
val singleApp = context.getString(R.string.screen_share_permission_dialog_option_single_app)
@@ -144,7 +159,7 @@ class ScreenRecordPermissionDialogTest : SysuiTestCase() {
@Test
fun showDialog_cancelClicked_dialogIsDismissed() {
- dialog.show()
+ showDialog()
clickOnCancel()
@@ -153,7 +168,7 @@ class ScreenRecordPermissionDialogTest : SysuiTestCase() {
@Test
fun showDialog_cancelClickedMultipleTimes_projectionRequestCancelledIsLoggedOnce() {
- dialog.show()
+ showDialog()
clickOnCancel()
clickOnCancel()
@@ -163,16 +178,22 @@ class ScreenRecordPermissionDialogTest : SysuiTestCase() {
@Test
fun dismissDialog_dismissCalledMultipleTimes_projectionRequestCancelledIsLoggedOnce() {
- dialog.show()
+ showDialog()
- TestableLooper.get(this).runWithLooper {
- dialog.dismiss()
- dialog.dismiss()
- }
+ dismissDialog()
+ dismissDialog()
verify(mediaProjectionMetricsLogger).notifyProjectionRequestCancelled(TEST_HOST_UID)
}
+ private fun showDialog() {
+ dialog.show()
+ }
+
+ private fun dismissDialog() {
+ dialog.dismiss()
+ }
+
private fun clickOnCancel() {
dialog.requireViewById<View>(android.R.id.button2).performClick()
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionsRepository.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionsRepository.kt
index 74b2723e870e..cce038f4ffc1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionsRepository.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionsRepository.kt
@@ -94,6 +94,7 @@ class FakeMobileConnectionsRepository(
override val defaultMobileIconGroup = _defaultMobileIconGroup
override val isAnySimSecure = MutableStateFlow(false)
+ override fun getIsAnySimSecure(): Boolean = isAnySimSecure.value
private var isInEcmMode: Boolean = false
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt
index ac75d4f189cc..03f300542a6f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt
@@ -92,7 +92,6 @@ import org.mockito.MockitoAnnotations
// to run the callback and this makes the looper place nicely with TestScope etc.
@TestableLooper.RunWithLooper
class MobileConnectionsRepositoryTest : SysuiTestCase() {
- private lateinit var underTest: MobileConnectionsRepositoryImpl
private lateinit var connectionFactory: MobileConnectionRepositoryImpl.Factory
private lateinit var carrierMergedFactory: CarrierMergedConnectionRepository.Factory
@@ -101,6 +100,7 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() {
private lateinit var airplaneModeRepository: FakeAirplaneModeRepository
private lateinit var wifiRepository: WifiRepository
private lateinit var carrierConfigRepository: CarrierConfigRepository
+
@Mock private lateinit var connectivityManager: ConnectivityManager
@Mock private lateinit var subscriptionManager: SubscriptionManager
@Mock private lateinit var telephonyManager: TelephonyManager
@@ -115,6 +115,8 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() {
private val dispatcher = StandardTestDispatcher()
private val testScope = TestScope(dispatcher)
+ private lateinit var underTest: MobileConnectionsRepositoryImpl
+
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
@@ -1179,6 +1181,16 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() {
}
@Test
+ fun getIsAnySimSecure_delegatesCallToKeyguardUpdateMonitor() =
+ testScope.runTest {
+ assertThat(underTest.getIsAnySimSecure()).isFalse()
+
+ whenever(updateMonitor.isSimPinSecure).thenReturn(true)
+
+ assertThat(underTest.getIsAnySimSecure()).isTrue()
+ }
+
+ @Test
fun noSubscriptionsInEcmMode_notInEcmMode() =
testScope.runTest {
whenever(telephonyManager.emergencyCallbackMode).thenReturn(false)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BatteryControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BatteryControllerTest.java
index 58d93c98f015..2f79955c4f5b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BatteryControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BatteryControllerTest.java
@@ -294,6 +294,6 @@ public class BatteryControllerTest extends SysuiTestCase {
when(mUsbPort.supportsComplianceWarnings()).thenReturn(true);
when(mUsbPortStatus.isConnected()).thenReturn(true);
when(mUsbPortStatus.getComplianceWarnings())
- .thenReturn(new int[]{UsbPortStatus.COMPLIANCE_WARNING_OTHER});
+ .thenReturn(new int[]{UsbPortStatus.COMPLIANCE_WARNING_DEBUG_ACCESSORY});
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserSwitcherInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserSwitcherInteractorTest.kt
index 1968d75a7964..017eefe38f2a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserSwitcherInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserSwitcherInteractorTest.kt
@@ -38,16 +38,14 @@ import com.android.systemui.SysuiTestCase
import com.android.systemui.animation.Expandable
import com.android.systemui.common.shared.model.Text
import com.android.systemui.coroutines.collectLastValue
-import com.android.systemui.flags.FakeFeatureFlags
import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractorFactory
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.qs.user.UserSwitchDialogController
import com.android.systemui.res.R
+import com.android.systemui.scene.SceneTestUtils
import com.android.systemui.statusbar.policy.DeviceProvisionedController
-import com.android.systemui.telephony.data.repository.FakeTelephonyRepository
-import com.android.systemui.telephony.domain.interactor.TelephonyInteractor
import com.android.systemui.user.data.model.UserSwitcherSettingsModel
import com.android.systemui.user.data.repository.FakeUserRepository
import com.android.systemui.user.data.source.UserRecord
@@ -65,9 +63,6 @@ import junit.framework.Assert.assertNotNull
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
-import kotlinx.coroutines.test.StandardTestDispatcher
-import kotlinx.coroutines.test.TestDispatcher
-import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Before
@@ -102,18 +97,16 @@ class UserSwitcherInteractorTest : SysuiTestCase() {
@Mock private lateinit var resetOrExitSessionReceiver: GuestResetOrExitSessionReceiver
@Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
- private lateinit var underTest: UserSwitcherInteractor
-
+ private val utils = SceneTestUtils(this)
+ private val testScope = utils.testScope
private lateinit var spyContext: Context
- private lateinit var testScope: TestScope
private lateinit var userRepository: FakeUserRepository
private lateinit var keyguardReply: KeyguardInteractorFactory.WithDependencies
private lateinit var keyguardRepository: FakeKeyguardRepository
- private lateinit var telephonyRepository: FakeTelephonyRepository
- private lateinit var testDispatcher: TestDispatcher
- private lateinit var featureFlags: FakeFeatureFlags
private lateinit var refreshUsersScheduler: RefreshUsersScheduler
+ private lateinit var underTest: UserSwitcherInteractor
+
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
@@ -127,22 +120,17 @@ class UserSwitcherInteractorTest : SysuiTestCase() {
SUPERVISED_USER_CREATION_APP_PACKAGE,
)
- featureFlags =
- FakeFeatureFlags().apply {
- set(Flags.FULL_SCREEN_USER_SWITCHER, false)
- set(Flags.FACE_AUTH_REFACTOR, true)
- }
+ utils.featureFlags.set(Flags.FULL_SCREEN_USER_SWITCHER, false)
+ utils.featureFlags.set(Flags.FACE_AUTH_REFACTOR, true)
+
spyContext = spy(context)
- keyguardReply = KeyguardInteractorFactory.create(featureFlags = featureFlags)
+ keyguardReply = KeyguardInteractorFactory.create(featureFlags = utils.featureFlags)
keyguardRepository = keyguardReply.repository
userRepository = FakeUserRepository()
- telephonyRepository = FakeTelephonyRepository()
- testDispatcher = StandardTestDispatcher()
- testScope = TestScope(testDispatcher)
refreshUsersScheduler =
RefreshUsersScheduler(
applicationScope = testScope.backgroundScope,
- mainDispatcher = testDispatcher,
+ mainDispatcher = utils.testDispatcher,
repository = userRepository,
)
}
@@ -372,7 +360,7 @@ class UserSwitcherInteractorTest : SysuiTestCase() {
fun actions_deviceUnlocked_fullScreen() {
createUserInteractor()
testScope.runTest {
- featureFlags.set(Flags.FULL_SCREEN_USER_SWITCHER, true)
+ utils.featureFlags.set(Flags.FULL_SCREEN_USER_SWITCHER, true)
val userInfos = createUserInfos(count = 2, includeGuest = false)
userRepository.setUserInfos(userInfos)
@@ -456,7 +444,7 @@ class UserSwitcherInteractorTest : SysuiTestCase() {
fun actions_deviceLockedAddFromLockscreenSet_fullList_fullScreen() {
createUserInteractor()
testScope.runTest {
- featureFlags.set(Flags.FULL_SCREEN_USER_SWITCHER, true)
+ utils.featureFlags.set(Flags.FULL_SCREEN_USER_SWITCHER, true)
val userInfos = createUserInfos(count = 2, includeGuest = false)
userRepository.setUserInfos(userInfos)
userRepository.setSelectedUserInfo(userInfos[0])
@@ -649,7 +637,7 @@ class UserSwitcherInteractorTest : SysuiTestCase() {
val refreshUsersCallCount = userRepository.refreshUsersCallCount
- telephonyRepository.setCallState(1)
+ utils.telephonyRepository.setCallState(1)
runCurrent()
assertThat(userRepository.refreshUsersCallCount).isEqualTo(refreshUsersCallCount + 1)
@@ -801,7 +789,7 @@ class UserSwitcherInteractorTest : SysuiTestCase() {
fun userRecordsFullScreen() {
createUserInteractor()
testScope.runTest {
- featureFlags.set(Flags.FULL_SCREEN_USER_SWITCHER, true)
+ utils.featureFlags.set(Flags.FULL_SCREEN_USER_SWITCHER, true)
val userInfos = createUserInfos(count = 3, includeGuest = false)
userRepository.setSettings(UserSwitcherSettingsModel(isUserSwitcherEnabled = true))
userRepository.setUserInfos(userInfos)
@@ -910,7 +898,7 @@ class UserSwitcherInteractorTest : SysuiTestCase() {
fun showUserSwitcher_fullScreenEnabled_launchesFullScreenDialog() {
createUserInteractor()
testScope.runTest {
- featureFlags.set(Flags.FULL_SCREEN_USER_SWITCHER, true)
+ utils.featureFlags.set(Flags.FULL_SCREEN_USER_SWITCHER, true)
val expandable = mock<Expandable>()
underTest.showUserSwitcher(expandable)
@@ -1125,21 +1113,18 @@ class UserSwitcherInteractorTest : SysuiTestCase() {
manager = manager,
headlessSystemUserMode = headlessSystemUserMode,
applicationScope = testScope.backgroundScope,
- telephonyInteractor =
- TelephonyInteractor(
- repository = telephonyRepository,
- ),
+ telephonyInteractor = utils.telephonyInteractor(),
broadcastDispatcher = fakeBroadcastDispatcher,
keyguardUpdateMonitor = keyguardUpdateMonitor,
- backgroundDispatcher = testDispatcher,
+ backgroundDispatcher = utils.testDispatcher,
activityManager = activityManager,
refreshUsersScheduler = refreshUsersScheduler,
guestUserInteractor =
GuestUserInteractor(
applicationContext = spyContext,
applicationScope = testScope.backgroundScope,
- mainDispatcher = testDispatcher,
- backgroundDispatcher = testDispatcher,
+ mainDispatcher = utils.testDispatcher,
+ backgroundDispatcher = utils.testDispatcher,
manager = manager,
repository = userRepository,
deviceProvisionedController = deviceProvisionedController,
@@ -1150,7 +1135,7 @@ class UserSwitcherInteractorTest : SysuiTestCase() {
resetOrExitSessionReceiver = resetOrExitSessionReceiver,
),
uiEventLogger = uiEventLogger,
- featureFlags = featureFlags,
+ featureFlags = utils.featureFlags,
userRestrictionChecker = mock(),
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/common/ui/data/repository/FakeConfigurationRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/common/ui/data/repository/FakeConfigurationRepository.kt
index 8353cf78d983..d0fa27e3b79a 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/common/ui/data/repository/FakeConfigurationRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/common/ui/data/repository/FakeConfigurationRepository.kt
@@ -20,6 +20,7 @@ import com.android.systemui.dagger.SysUISingleton
import dagger.Binds
import dagger.Module
import javax.inject.Inject
+import kotlinx.coroutines.channels.BufferOverflow
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
@@ -31,16 +32,23 @@ class FakeConfigurationRepository @Inject constructor() : ConfigurationRepositor
private val _onAnyConfigurationChange = MutableSharedFlow<Unit>()
override val onAnyConfigurationChange: Flow<Unit> = _onAnyConfigurationChange.asSharedFlow()
+ private val _onConfigurationChange =
+ MutableSharedFlow<Unit>(replay = 1, onBufferOverflow = BufferOverflow.DROP_OLDEST)
+ override val onConfigurationChange: Flow<Unit> = _onConfigurationChange.asSharedFlow()
+
private val _scaleForResolution = MutableStateFlow(1f)
override val scaleForResolution: Flow<Float> = _scaleForResolution.asStateFlow()
private val pixelSizes = mutableMapOf<Int, MutableStateFlow<Int>>()
- private val colors = mutableMapOf<Int, MutableStateFlow<Int>>()
fun onAnyConfigurationChange() {
_onAnyConfigurationChange.tryEmit(Unit)
}
+ fun onConfigurationChange() {
+ _onConfigurationChange.tryEmit(Unit)
+ }
+
fun setScaleForResolution(scale: Float) {
_scaleForResolution.value = scale
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/FakeCommunalMediaRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/FakeCommunalMediaRepository.kt
new file mode 100644
index 000000000000..3ab1b6c11e02
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/FakeCommunalMediaRepository.kt
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2023 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.systemui.communal.data.repository
+
+import kotlinx.coroutines.flow.MutableStateFlow
+
+class FakeCommunalMediaRepository(
+ override val mediaPlaying: MutableStateFlow<Boolean> = MutableStateFlow(false)
+) : CommunalMediaRepository
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalInteractorFactory.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalInteractorFactory.kt
index 6c3882fd70f6..0c821eab65e0 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalInteractorFactory.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalInteractorFactory.kt
@@ -18,6 +18,7 @@
package com.android.systemui.communal.domain.interactor
import android.appwidget.AppWidgetHost
+import com.android.systemui.communal.data.repository.FakeCommunalMediaRepository
import com.android.systemui.communal.data.repository.FakeCommunalRepository
import com.android.systemui.communal.data.repository.FakeCommunalTutorialRepository
import com.android.systemui.communal.data.repository.FakeCommunalWidgetRepository
@@ -35,6 +36,7 @@ object CommunalInteractorFactory {
testScope: TestScope = TestScope(),
communalRepository: FakeCommunalRepository = FakeCommunalRepository(),
widgetRepository: FakeCommunalWidgetRepository = FakeCommunalWidgetRepository(),
+ mediaRepository: FakeCommunalMediaRepository = FakeCommunalMediaRepository(),
smartspaceRepository: FakeSmartspaceRepository = FakeSmartspaceRepository(),
tutorialRepository: FakeCommunalTutorialRepository = FakeCommunalTutorialRepository(),
appWidgetHost: AppWidgetHost = mock(),
@@ -48,6 +50,7 @@ object CommunalInteractorFactory {
return WithDependencies(
communalRepository,
widgetRepository,
+ mediaRepository,
smartspaceRepository,
tutorialRepository,
withDeps.keyguardRepository,
@@ -57,6 +60,7 @@ object CommunalInteractorFactory {
CommunalInteractor(
communalRepository,
widgetRepository,
+ mediaRepository,
smartspaceRepository,
withDeps.communalTutorialInteractor,
appWidgetHost,
@@ -67,6 +71,7 @@ object CommunalInteractorFactory {
data class WithDependencies(
val communalRepository: FakeCommunalRepository,
val widgetRepository: FakeCommunalWidgetRepository,
+ val mediaRepository: FakeCommunalMediaRepository,
val smartspaceRepository: FakeSmartspaceRepository,
val tutorialRepository: FakeCommunalTutorialRepository,
val keyguardRepository: FakeKeyguardRepository,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/power/data/repository/FakePowerRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/power/data/repository/FakePowerRepository.kt
index 957fbbd8680f..ace650020a9d 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/power/data/repository/FakePowerRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/power/data/repository/FakePowerRepository.kt
@@ -18,11 +18,11 @@
package com.android.systemui.power.data.repository
import android.os.PowerManager
+import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.power.shared.model.ScreenPowerState
import com.android.systemui.power.shared.model.WakeSleepReason
import com.android.systemui.power.shared.model.WakefulnessModel
import com.android.systemui.power.shared.model.WakefulnessState
-import com.android.systemui.dagger.SysUISingleton
import dagger.Binds
import dagger.Module
import javax.inject.Inject
@@ -55,15 +55,15 @@ class FakePowerRepository @Inject constructor() : PowerRepository {
lastWakeReason = wakeReason
}
- override fun userTouch() {
+ override fun userTouch(noChangeLights: Boolean) {
userTouchRegistered = true
}
override fun updateWakefulness(
- rawState: WakefulnessState,
- lastWakeReason: WakeSleepReason,
- lastSleepReason: WakeSleepReason,
- powerButtonLaunchGestureTriggered: Boolean
+ rawState: WakefulnessState,
+ lastWakeReason: WakeSleepReason,
+ lastSleepReason: WakeSleepReason,
+ powerButtonLaunchGestureTriggered: Boolean
) {
_wakefulness.value =
WakefulnessModel(
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt
index 14c4b8670060..36ec18fc4de4 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt
@@ -16,10 +16,15 @@
package com.android.systemui.scene
+import android.app.ActivityTaskManager
import android.content.Context
+import android.content.Intent
import android.content.pm.UserInfo
import android.graphics.Bitmap
import android.graphics.drawable.BitmapDrawable
+import android.telecom.TelecomManager
+import com.android.internal.logging.MetricsLogger
+import com.android.internal.util.EmergencyAffordanceManager
import com.android.systemui.SysuiTestCase
import com.android.systemui.authentication.data.model.AuthenticationMethodModel as DataLayerAuthenticationMethodModel
import com.android.systemui.authentication.data.repository.AuthenticationRepository
@@ -27,8 +32,11 @@ import com.android.systemui.authentication.data.repository.FakeAuthenticationRep
import com.android.systemui.authentication.domain.interactor.AuthenticationInteractor
import com.android.systemui.authentication.domain.model.AuthenticationMethodModel as DomainLayerAuthenticationMethodModel
import com.android.systemui.bouncer.data.repository.BouncerRepository
+import com.android.systemui.bouncer.data.repository.EmergencyServicesRepository
import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository
+import com.android.systemui.bouncer.domain.interactor.BouncerActionButtonInteractor
import com.android.systemui.bouncer.domain.interactor.BouncerInteractor
+import com.android.systemui.bouncer.domain.interactor.EmergencyDialerIntentFactory
import com.android.systemui.bouncer.ui.viewmodel.BouncerViewModel
import com.android.systemui.classifier.FalsingCollector
import com.android.systemui.classifier.FalsingCollectorFake
@@ -41,6 +49,7 @@ import com.android.systemui.communal.domain.interactor.CommunalInteractorFactory
import com.android.systemui.deviceentry.data.repository.DeviceEntryRepository
import com.android.systemui.deviceentry.data.repository.FakeDeviceEntryRepository
import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor
+import com.android.systemui.doze.DozeLogger
import com.android.systemui.flags.FakeFeatureFlagsClassic
import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.data.repository.DeviceEntryFaceAuthRepository
@@ -62,10 +71,13 @@ import com.android.systemui.scene.shared.flag.FakeSceneContainerFlags
import com.android.systemui.scene.shared.model.SceneContainerConfig
import com.android.systemui.scene.shared.model.SceneKey
import com.android.systemui.shade.data.repository.FakeShadeRepository
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionsRepository
import com.android.systemui.telephony.data.repository.FakeTelephonyRepository
+import com.android.systemui.telephony.data.repository.TelephonyRepository
import com.android.systemui.telephony.domain.interactor.TelephonyInteractor
import com.android.systemui.user.data.repository.FakeUserRepository
import com.android.systemui.user.data.repository.UserRepository
+import com.android.systemui.user.domain.interactor.SelectedUserInteractor
import com.android.systemui.user.ui.viewmodel.UserActionViewModel
import com.android.systemui.user.ui.viewmodel.UserViewModel
import com.android.systemui.util.mockito.mock
@@ -102,12 +114,23 @@ class SceneTestUtils(
currentTime = { testScope.currentTime },
)
}
+ val configurationRepository: FakeConfigurationRepository by lazy {
+ FakeConfigurationRepository()
+ }
+ private val emergencyServicesRepository: EmergencyServicesRepository by lazy {
+ EmergencyServicesRepository(
+ applicationScope = applicationScope(),
+ resources = context.resources,
+ configurationRepository = configurationRepository,
+ )
+ }
+ val telephonyRepository: FakeTelephonyRepository by lazy { FakeTelephonyRepository() }
val communalRepository: FakeCommunalRepository by lazy { FakeCommunalRepository() }
val keyguardRepository: FakeKeyguardRepository by lazy { FakeKeyguardRepository() }
val powerRepository: FakePowerRepository by lazy { FakePowerRepository() }
- private val userRepository: UserRepository by lazy {
+ val userRepository: UserRepository by lazy {
FakeUserRepository().apply {
val users = listOf(UserInfo(/* id= */ 0, "name", /* flags= */ 0))
setUserInfos(users)
@@ -183,7 +206,7 @@ class SceneTestUtils(
featureFlags = featureFlags,
sceneContainerFlags = sceneContainerFlags,
bouncerRepository = FakeKeyguardBouncerRepository(),
- configurationRepository = FakeConfigurationRepository(),
+ configurationRepository = configurationRepository,
shadeRepository = FakeShadeRepository(),
sceneInteractorProvider = { sceneInteractor() },
powerInteractor = PowerInteractorFactory.create().powerInteractor,
@@ -217,6 +240,7 @@ class SceneTestUtils(
fun bouncerViewModel(
bouncerInteractor: BouncerInteractor,
authenticationInteractor: AuthenticationInteractor,
+ actionButtonInteractor: BouncerActionButtonInteractor,
users: List<UserViewModel> = createUsers(),
): BouncerViewModel {
return BouncerViewModel(
@@ -229,13 +253,16 @@ class SceneTestUtils(
selectedUser = flowOf(users.first { it.isSelectionMarkerVisible }),
users = flowOf(users),
userSwitcherMenu = flowOf(createMenuActions()),
- telephonyInteractor =
- TelephonyInteractor(
- repository = FakeTelephonyRepository(),
- ),
+ actionButtonInteractor = actionButtonInteractor,
)
}
+ fun telephonyInteractor(
+ repository: TelephonyRepository = telephonyRepository,
+ ): TelephonyInteractor {
+ return TelephonyInteractor(repository = repository)
+ }
+
fun falsingInteractor(collector: FalsingCollector = falsingCollector()): FalsingInteractor {
return falsingInteractor ?: FalsingInteractor(collector).also { falsingInteractor = it }
}
@@ -285,6 +312,40 @@ class SceneTestUtils(
}
}
+ fun selectedUserInteractor(): SelectedUserInteractor {
+ return SelectedUserInteractor(userRepository, featureFlags)
+ }
+
+ fun bouncerActionButtonInteractor(
+ mobileConnectionsRepository: MobileConnectionsRepository = mock(),
+ activityTaskManager: ActivityTaskManager = mock(),
+ telecomManager: TelecomManager? = null,
+ emergencyAffordanceManager: EmergencyAffordanceManager =
+ EmergencyAffordanceManager(context),
+ emergencyDialerIntentFactory: EmergencyDialerIntentFactory =
+ object : EmergencyDialerIntentFactory {
+ override fun invoke(): Intent = Intent()
+ },
+ metricsLogger: MetricsLogger = mock(),
+ dozeLogger: DozeLogger = mock(),
+ ): BouncerActionButtonInteractor {
+ return BouncerActionButtonInteractor(
+ applicationContext = context,
+ backgroundDispatcher = testDispatcher,
+ repository = emergencyServicesRepository,
+ mobileConnectionsRepository = mobileConnectionsRepository,
+ telephonyInteractor = telephonyInteractor(),
+ authenticationInteractor = authenticationInteractor(),
+ selectedUserInteractor = selectedUserInteractor(),
+ activityTaskManager = activityTaskManager,
+ telecomManager = telecomManager,
+ emergencyAffordanceManager = emergencyAffordanceManager,
+ emergencyDialerIntentFactory = emergencyDialerIntentFactory,
+ metricsLogger = metricsLogger,
+ dozeLogger = dozeLogger,
+ )
+ }
+
companion object {
fun DomainLayerAuthenticationMethodModel.toDataLayer(): DataLayerAuthenticationMethodModel {
return when (this) {
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/telephony/data/repository/FakeTelephonyRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/telephony/data/repository/FakeTelephonyRepository.kt
index 992ac62fe3c4..5cde3868199b 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/telephony/data/repository/FakeTelephonyRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/telephony/data/repository/FakeTelephonyRepository.kt
@@ -23,6 +23,7 @@ import dagger.Module
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
@SysUISingleton
@@ -31,6 +32,9 @@ class FakeTelephonyRepository @Inject constructor() : TelephonyRepository {
private val _callState = MutableStateFlow(0)
override val callState: Flow<Int> = _callState.asStateFlow()
+ private val _isInCall = MutableStateFlow(false)
+ override val isInCall: StateFlow<Boolean> = _isInCall.asStateFlow()
+
override var hasTelephonyRadio: Boolean = true
private set
@@ -38,8 +42,12 @@ class FakeTelephonyRepository @Inject constructor() : TelephonyRepository {
_callState.value = value
}
- fun setHasRadio(hasRadio: Boolean) {
- this.hasTelephonyRadio = hasRadio
+ fun setIsInCall(isInCall: Boolean) {
+ _isInCall.value = isInCall
+ }
+
+ fun setHasTelephonyRadio(hasTelephonyRadio: Boolean) {
+ this.hasTelephonyRadio = hasTelephonyRadio
}
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/util/reference/FakeWeakReferenceFactory.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/util/reference/FakeWeakReferenceFactory.kt
new file mode 100644
index 000000000000..f0a8fd0abf3d
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/util/reference/FakeWeakReferenceFactory.kt
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2023 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.systemui.util.reference
+
+import java.lang.ref.WeakReference
+
+class FakeWeakReferenceFactory : WeakReferenceFactory {
+ private val managedReferents = mutableListOf<WeakReference<*>>()
+
+ override fun <T> create(referent: T): WeakReference<T> {
+ val weakRef = WeakReference(referent)
+ managedReferents.add(weakRef)
+ return weakRef
+ }
+
+ /**
+ * Clears any [WeakReference] objects pointing to this object. If argument is null, clears all
+ * references.
+ */
+ fun <T> clear(referent: T) {
+ managedReferents.filter { it.get() == referent }.forEach { it.clear() }
+ }
+}
diff --git a/ravenwood/Android.bp b/ravenwood/Android.bp
index d0e442e7058d..5c9bf1828347 100644
--- a/ravenwood/Android.bp
+++ b/ravenwood/Android.bp
@@ -32,3 +32,14 @@ java_library {
host_supported: true,
visibility: ["//visibility:public"],
}
+
+java_library {
+ name: "ravenwood-junit",
+ srcs: ["junit-src/**/*.java"],
+ libs: [
+ "junit",
+ ],
+ sdk_version: "core_current",
+ host_supported: true,
+ visibility: ["//visibility:public"],
+}
diff --git a/ravenwood/junit-src/android/platform/test/annotations/IgnoreUnderRavenwood.java b/ravenwood/junit-src/android/platform/test/annotations/IgnoreUnderRavenwood.java
new file mode 100644
index 000000000000..0aac084dd4ce
--- /dev/null
+++ b/ravenwood/junit-src/android/platform/test/annotations/IgnoreUnderRavenwood.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2023 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.platform.test.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * THIS ANNOTATION IS EXPERIMENTAL. REACH OUT TO g/ravenwood BEFORE USING IT, OR YOU HAVE ANY
+ * QUESTIONS ABOUT IT.
+ *
+ * @hide
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface IgnoreUnderRavenwood {
+}
diff --git a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java
new file mode 100644
index 000000000000..a6b3f668efa6
--- /dev/null
+++ b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2023 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.platform.test.ravenwood;
+
+import android.platform.test.annotations.IgnoreUnderRavenwood;
+
+import org.junit.Assume;
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+/**
+ * THIS RULE IS EXPERIMENTAL. REACH OUT TO g/ravenwood BEFORE USING IT, OR YOU HAVE ANY
+ * QUESTIONS ABOUT IT.
+ *
+ * @hide
+ */
+public class RavenwoodRule implements TestRule {
+ public boolean isUnderRavenwood() {
+ // TODO: give ourselves a better environment signal
+ return System.getProperty("java.class.path").contains("ravenwood");
+ }
+
+ @Override
+ public Statement apply(Statement base, Description description) {
+ return new Statement() {
+ @Override
+ public void evaluate() throws Throwable {
+ if (description.getAnnotation(IgnoreUnderRavenwood.class) != null) {
+ Assume.assumeFalse(isUnderRavenwood());
+ }
+ base.evaluate();
+ }
+ };
+ }
+}
diff --git a/services/autofill/bugfixes.aconfig b/services/autofill/bugfixes.aconfig
index b37bbd6ea27f..ab678d93c665 100644
--- a/services/autofill/bugfixes.aconfig
+++ b/services/autofill/bugfixes.aconfig
@@ -20,3 +20,10 @@ flag {
description: "Mitigation for relayout issue"
bug: "294330426"
}
+
+flag {
+ name: "ignore_view_state_reset_to_empty"
+ namespace: "autofill"
+ description: "Mitigation for view state reset to empty causing no save dialog to show issue"
+ bug: "297976948"
+}
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 02235096ac15..15fc2dc15d02 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -61,7 +61,6 @@ import android.app.KeyguardManager;
import android.app.PendingIntent;
import android.app.admin.SecurityLog;
import android.app.usage.StorageStatsManager;
-import android.content.AttributionSource;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -2139,13 +2138,8 @@ class StorageManagerService extends IStorageManager.Stub
| MATCH_DIRECT_BOOT_UNAWARE | MATCH_UNINSTALLED_PACKAGES | MATCH_ANY_USER,
userId, Process.myUid())) {
try {
- final AttributionSource attributionSource = new AttributionSource.Builder(ai.uid)
- .setPackageName(ai.packageName)
- .build();
- boolean hasLegacy =
- mIAppOpsService.checkOperationWithState(
- OP_LEGACY_STORAGE, attributionSource.asState())
- == MODE_ALLOWED;
+ boolean hasLegacy = mIAppOpsService.checkOperation(OP_LEGACY_STORAGE, ai.uid,
+ ai.packageName) == MODE_ALLOWED;
updateLegacyStorageApps(ai.packageName, ai.uid, hasLegacy);
} catch (RemoteException e) {
Slog.e(TAG, "Failed to check legacy op for package " + ai.packageName, e);
@@ -4546,11 +4540,8 @@ class StorageManagerService extends IStorageManager.Stub
// sharing the uid and allow same level of storage access for all packages even if
// one of the packages has the appop granted.
for (String uidPackageName : packagesForUid) {
- final AttributionSource attributionSource =
- new AttributionSource.Builder(uid).setPackageName(uidPackageName).build();
- if (mIAppOpsService.checkOperationWithState(
- OP_REQUEST_INSTALL_PACKAGES, attributionSource.asState())
- == MODE_ALLOWED) {
+ if (mIAppOpsService.checkOperation(
+ OP_REQUEST_INSTALL_PACKAGES, uid, uidPackageName) == MODE_ALLOWED) {
hasInstallOp = true;
break;
}
@@ -4847,11 +4838,8 @@ class StorageManagerService extends IStorageManager.Stub
@Override
public boolean hasExternalStorageAccess(int uid, String packageName) {
try {
- final AttributionSource attributionSource =
- new AttributionSource.Builder(uid).setPackageName(packageName).build();
- final int opMode =
- mIAppOpsService.checkOperationWithState(
- OP_MANAGE_EXTERNAL_STORAGE, attributionSource.asState());
+ final int opMode = mIAppOpsService.checkOperation(
+ OP_MANAGE_EXTERNAL_STORAGE, uid, packageName);
if (opMode == AppOpsManager.MODE_DEFAULT) {
return mIPackageManager.checkUidPermission(
MANAGE_EXTERNAL_STORAGE, uid) == PERMISSION_GRANTED;
diff --git a/services/core/java/com/android/server/TEST_MAPPING b/services/core/java/com/android/server/TEST_MAPPING
index afc0dd188c3c..cd9c53bb92b9 100644
--- a/services/core/java/com/android/server/TEST_MAPPING
+++ b/services/core/java/com/android/server/TEST_MAPPING
@@ -83,6 +83,9 @@
}
],
"file_patterns": ["VpnManagerService\\.java"]
+ },
+ {
+ "name": "FrameworksNetTests"
}
],
"presubmit-large": [
@@ -124,9 +127,6 @@
},
{
"name": "CtsSuspendAppsTestCases"
- },
- {
- "name": "FrameworksNetTests"
}
]
}
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 4bdb4da97144..5f1a7e7e8123 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -167,7 +167,6 @@ import android.compat.annotation.ChangeId;
import android.compat.annotation.EnabledAfter;
import android.compat.annotation.EnabledSince;
import android.compat.annotation.Overridable;
-import android.content.AttributionSource;
import android.content.ComponentName;
import android.content.ComponentName.WithComponentName;
import android.content.Context;
@@ -1101,12 +1100,8 @@ public final class ActiveServices {
SystemClock.uptimeMillis()); // Use current time, not lastActivity.
}
}
- final AttributionSource attributionSource = new AttributionSource.Builder(r.appInfo.uid)
- .setPackageName(r.packageName)
- .build();
- mAm.mAppOpsService.startOperationWithState(AppOpsManager.getToken(mAm.mAppOpsService),
- AppOpsManager.OP_START_FOREGROUND,
- attributionSource.asState(),
+ mAm.mAppOpsService.startOperation(AppOpsManager.getToken(mAm.mAppOpsService),
+ AppOpsManager.OP_START_FOREGROUND, r.appInfo.uid, r.packageName, null,
true, false, null, false, AppOpsManager.ATTRIBUTION_FLAGS_NONE,
AppOpsManager.ATTRIBUTION_CHAIN_ID_NONE);
}
@@ -2456,15 +2451,10 @@ public final class ActiveServices {
stopProcStatsOp = false;
}
- final AttributionSource attributionSource = new AttributionSource
- .Builder(r.appInfo.uid)
- .setPackageName(r.packageName)
- .build();
- mAm.mAppOpsService.startOperationWithState(
+ mAm.mAppOpsService.startOperation(
AppOpsManager.getToken(mAm.mAppOpsService),
- AppOpsManager.OP_START_FOREGROUND, attributionSource.asState(),
- true, false, "", false,
- AppOpsManager.ATTRIBUTION_FLAGS_NONE,
+ AppOpsManager.OP_START_FOREGROUND, r.appInfo.uid, r.packageName,
+ null, true, false, "", false, AppOpsManager.ATTRIBUTION_FLAGS_NONE,
AppOpsManager.ATTRIBUTION_CHAIN_ID_NONE);
registerAppOpCallbackLocked(r);
mAm.updateForegroundServiceUsageStats(r.name, r.userId, true);
@@ -2524,13 +2514,10 @@ public final class ActiveServices {
if (alreadyStartedOp) {
// If we had previously done a start op for direct foreground start,
// we have cleared the flag so can now drop it.
- final AttributionSource attributionSource = new AttributionSource
- .Builder(r.appInfo.uid)
- .setPackageName(r.packageName)
- .build();
- mAm.mAppOpsService.finishOperationWithState(
+ mAm.mAppOpsService.finishOperation(
AppOpsManager.getToken(mAm.mAppOpsService),
- AppOpsManager.OP_START_FOREGROUND, attributionSource.asState());
+ AppOpsManager.OP_START_FOREGROUND, r.appInfo.uid, r.packageName,
+ null);
}
}
} else {
@@ -2573,13 +2560,9 @@ public final class ActiveServices {
SystemClock.uptimeMillis());
}
}
- final AttributionSource attributionSource =
- new AttributionSource.Builder(r.appInfo.uid)
- .setPackageName(r.packageName)
- .build();
- mAm.mAppOpsService.finishOperationWithState(
+ mAm.mAppOpsService.finishOperation(
AppOpsManager.getToken(mAm.mAppOpsService),
- AppOpsManager.OP_START_FOREGROUND, attributionSource.asState());
+ AppOpsManager.OP_START_FOREGROUND, r.appInfo.uid, r.packageName, null);
unregisterAppOpCallbackLocked(r);
logFGSStateChangeLocked(r,
FOREGROUND_SERVICE_STATE_CHANGED__STATE__EXIT,
@@ -5721,12 +5704,8 @@ public final class ActiveServices {
SystemClock.uptimeMillis());
}
}
- final AttributionSource attributionSource = new AttributionSource
- .Builder(r.appInfo.uid)
- .setPackageName(r.packageName)
- .build();
- mAm.mAppOpsService.finishOperationWithState(AppOpsManager.getToken(mAm.mAppOpsService),
- AppOpsManager.OP_START_FOREGROUND, attributionSource.asState());
+ mAm.mAppOpsService.finishOperation(AppOpsManager.getToken(mAm.mAppOpsService),
+ AppOpsManager.OP_START_FOREGROUND, r.appInfo.uid, r.packageName, null);
mServiceFGAnrTimer.cancel(r);
if (r.app != null) {
Message msg = mAm.mHandler.obtainMessage(
@@ -5791,13 +5770,9 @@ public final class ActiveServices {
SystemClock.uptimeMillis());
}
}
- final AttributionSource attributionSource = new AttributionSource
- .Builder(r.appInfo.uid)
- .setPackageName(r.packageName)
- .build();
- mAm.mAppOpsService.finishOperationWithState(
+ mAm.mAppOpsService.finishOperation(
AppOpsManager.getToken(mAm.mAppOpsService),
- AppOpsManager.OP_START_FOREGROUND, attributionSource.asState());
+ AppOpsManager.OP_START_FOREGROUND, r.appInfo.uid, r.packageName, null);
unregisterAppOpCallbackLocked(r);
r.mFgsExitTime = SystemClock.uptimeMillis();
logFGSStateChangeLocked(r,
@@ -8516,11 +8491,8 @@ public final class ActiveServices {
mAm.mBatteryStatsService.noteServiceStartRunning(callingUid, callingPackage,
cn.getClassName());
- final AttributionSource attributionSource = new AttributionSource.Builder(r.appInfo.uid)
- .setPackageName(r.packageName)
- .build();
- mAm.mAppOpsService.startOperationWithState(AppOpsManager.getToken(mAm.mAppOpsService),
- AppOpsManager.OP_START_FOREGROUND, attributionSource.asState(),
+ mAm.mAppOpsService.startOperation(AppOpsManager.getToken(mAm.mAppOpsService),
+ AppOpsManager.OP_START_FOREGROUND, r.appInfo.uid, r.packageName, null,
true, false, null, false,
AppOpsManager.ATTRIBUTION_FLAGS_NONE, AppOpsManager.ATTRIBUTION_CHAIN_ID_NONE);
registerAppOpCallbackLocked(r);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index a0a5f99c1152..b99a98fe6e8b 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -429,11 +429,10 @@ import com.android.internal.util.FastPrintWriter;
import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.util.MemInfoReader;
import com.android.internal.util.Preconditions;
+import com.android.internal.util.function.HeptFunction;
import com.android.internal.util.function.HexFunction;
-import com.android.internal.util.function.NonaFunction;
import com.android.internal.util.function.QuadFunction;
import com.android.internal.util.function.QuintFunction;
-import com.android.internal.util.function.TriFunction;
import com.android.internal.util.function.UndecFunction;
import com.android.server.AlarmManagerInternal;
import com.android.server.BootReceiver;
@@ -3152,11 +3151,8 @@ public class ActivityManagerService extends IActivityManager.Stub
}
private boolean hasUsageStatsPermission(String callingPackage, int callingUid, int callingPid) {
- final AttributionSource attributionSource = new AttributionSource.Builder(callingUid)
- .setPackageName(callingPackage)
- .build();
- final int mode = mAppOpsService.noteOperationWithState(AppOpsManager.OP_GET_USAGE_STATS,
- attributionSource.asState(), false, "", false).getOpMode();
+ final int mode = mAppOpsService.noteOperation(AppOpsManager.OP_GET_USAGE_STATS,
+ callingUid, callingPackage, null, false, "", false).getOpMode();
if (mode == AppOpsManager.MODE_DEFAULT) {
return checkPermission(Manifest.permission.PACKAGE_USAGE_STATS, callingPid, callingUid)
== PackageManager.PERMISSION_GRANTED;
@@ -5896,18 +5892,9 @@ public class ActivityManagerService extends IActivityManager.Stub
@Override
public int noteOp(String op, int uid, String packageName) {
// TODO moltmann: Allow to specify featureId
- final AttributionSource attributionSource = new AttributionSource.Builder(uid)
- .setPackageName(packageName)
- .build();
- return mActivityManagerService
- .mAppOpsService
- .noteOperationWithState(
- AppOpsManager.strOpToOp(op),
- attributionSource.asState(),
- false,
- "",
- false)
- .getOpMode();
+ return mActivityManagerService.mAppOpsService
+ .noteOperation(AppOpsManager.strOpToOp(op), uid, packageName, null,
+ false, "", false).getOpMode();
}
@Override
@@ -20121,26 +20108,20 @@ public class ActivityManagerService extends IActivityManager.Stub
}
@Override
- public int checkOperation(int code, AttributionSource attributionSource, boolean raw,
- TriFunction<Integer, AttributionSource, Boolean, Integer> superImpl) {
- final int uid = attributionSource.getUid();
-
+ public int checkOperation(int code, int uid, String packageName,
+ String attributionTag, boolean raw,
+ QuintFunction<Integer, Integer, String, String, Boolean, Integer> superImpl) {
if (uid == mTargetUid && isTargetOp(code)) {
final int shellUid = UserHandle.getUid(UserHandle.getUserId(uid),
Process.SHELL_UID);
- final AttributionSource shellAttributionSource =
- new AttributionSource.Builder(shellUid)
- .setPackageName("com.android.shell")
- .build();
-
final long identity = Binder.clearCallingIdentity();
try {
- return superImpl.apply(code, shellAttributionSource, raw);
+ return superImpl.apply(code, shellUid, "com.android.shell", null, raw);
} finally {
Binder.restoreCallingIdentity(identity);
}
}
- return superImpl.apply(code, attributionSource, raw);
+ return superImpl.apply(code, uid, packageName, attributionTag, raw);
}
@Override
@@ -20160,30 +20141,23 @@ public class ActivityManagerService extends IActivityManager.Stub
}
@Override
- public SyncNotedAppOp noteOperation(int code, AttributionSource attributionSource,
- boolean shouldCollectAsyncNotedOp,
+ public SyncNotedAppOp noteOperation(int code, int uid, @Nullable String packageName,
+ @Nullable String featureId, boolean shouldCollectAsyncNotedOp,
@Nullable String message, boolean shouldCollectMessage,
- @NonNull QuintFunction<Integer, AttributionSource, Boolean, String, Boolean,
+ @NonNull HeptFunction<Integer, Integer, String, String, Boolean, String, Boolean,
SyncNotedAppOp> superImpl) {
- final int uid = attributionSource.getUid();
- final String attributionTag = attributionSource.getAttributionTag();
if (uid == mTargetUid && isTargetOp(code)) {
final int shellUid = UserHandle.getUid(UserHandle.getUserId(uid),
Process.SHELL_UID);
final long identity = Binder.clearCallingIdentity();
- final AttributionSource shellAttributionSource =
- new AttributionSource.Builder(shellUid)
- .setPackageName("com.android.shell")
- .setAttributionTag(attributionTag)
- .build();
try {
- return superImpl.apply(code, shellAttributionSource,
+ return superImpl.apply(code, shellUid, "com.android.shell", featureId,
shouldCollectAsyncNotedOp, message, shouldCollectMessage);
} finally {
Binder.restoreCallingIdentity(identity);
}
}
- return superImpl.apply(code, attributionSource, shouldCollectAsyncNotedOp,
+ return superImpl.apply(code, uid, packageName, featureId, shouldCollectAsyncNotedOp,
message, shouldCollectMessage);
}
@@ -20214,37 +20188,28 @@ public class ActivityManagerService extends IActivityManager.Stub
}
@Override
- public SyncNotedAppOp startOperation(IBinder token, int code,
- AttributionSource attributionSource,
+ public SyncNotedAppOp startOperation(IBinder token, int code, int uid,
+ @Nullable String packageName, @Nullable String attributionTag,
boolean startIfModeDefault, boolean shouldCollectAsyncNotedOp,
@Nullable String message, boolean shouldCollectMessage,
@AttributionFlags int attributionFlags, int attributionChainId,
- @NonNull NonaFunction<IBinder, Integer, AttributionSource, Boolean,
+ @NonNull UndecFunction<IBinder, Integer, Integer, String, String, Boolean,
Boolean, String, Boolean, Integer, Integer, SyncNotedAppOp> superImpl) {
- final int uid = attributionSource.getUid();
- final String attributionTag = attributionSource.getAttributionTag();
-
if (uid == mTargetUid && isTargetOp(code)) {
final int shellUid = UserHandle.getUid(UserHandle.getUserId(uid),
Process.SHELL_UID);
final long identity = Binder.clearCallingIdentity();
try {
- final AttributionSource shellAttributionSource =
- new AttributionSource.Builder(shellUid)
- .setPackageName("com.android.shell")
- .setAttributionTag(attributionTag)
- .build();
-
- return superImpl.apply(token, code, shellAttributionSource,
- startIfModeDefault, shouldCollectAsyncNotedOp, message,
+ return superImpl.apply(token, code, shellUid, "com.android.shell",
+ attributionTag, startIfModeDefault, shouldCollectAsyncNotedOp, message,
shouldCollectMessage, attributionFlags, attributionChainId);
} finally {
Binder.restoreCallingIdentity(identity);
}
}
- return superImpl.apply(token, code, attributionSource, startIfModeDefault,
- shouldCollectAsyncNotedOp, message, shouldCollectMessage, attributionFlags,
- attributionChainId);
+ return superImpl.apply(token, code, uid, packageName, attributionTag,
+ startIfModeDefault, shouldCollectAsyncNotedOp, message, shouldCollectMessage,
+ attributionFlags, attributionChainId);
}
@Override
diff --git a/services/core/java/com/android/server/am/AppPermissionTracker.java b/services/core/java/com/android/server/am/AppPermissionTracker.java
index 947fcd38f5a0..18a91535a34c 100644
--- a/services/core/java/com/android/server/am/AppPermissionTracker.java
+++ b/services/core/java/com/android/server/am/AppPermissionTracker.java
@@ -37,7 +37,6 @@ import static com.android.server.am.BaseAppStateTracker.STATE_TYPE_PERMISSION;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.AppOpsManager;
-import android.content.AttributionSource;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager.OnPermissionsChangedListener;
@@ -193,11 +192,7 @@ final class AppPermissionTracker extends BaseAppStateTracker<AppPermissionPolicy
if (DEBUG_PERMISSION_TRACKER) {
final IAppOpsService appOpsService = mInjector.getIAppOpsService();
try {
- final AttributionSource attributionSource = new AttributionSource.Builder(uid)
- .setPackageName(packageName)
- .build();
- final int mode =
- appOpsService.checkOperationWithState(op, attributionSource.asState());
+ final int mode = appOpsService.checkOperation(op, uid, packageName);
Slog.i(TAG, "onOpChanged: " + opToPublicName(op)
+ " " + UserHandle.formatUid(uid)
+ " " + packageName + " " + mode);
@@ -312,11 +307,7 @@ final class AppPermissionTracker extends BaseAppStateTracker<AppPermissionPolicy
final IAppOpsService appOpsService = mInjector.getIAppOpsService();
for (String pkg : packages) {
try {
- final AttributionSource attributionSource =
- new AttributionSource.Builder(mUid).setPackageName(pkg).build();
- final int mode =
- appOpsService.checkOperationWithState(
- mAppOp, attributionSource.asState());
+ final int mode = appOpsService.checkOperation(mAppOp, mUid, pkg);
if (mode == AppOpsManager.MODE_ALLOWED) {
mAppOpAllowed = true;
return;
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index d6997daaa12b..052b0c2078d1 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -1143,32 +1143,22 @@ public class AppOpsService extends IAppOpsService.Stub {
}
}, RARELY_USED_PACKAGES_INITIALIZATION_DELAY_MILLIS);
- getPackageManagerInternal()
- .setExternalSourcesPolicy(
- new PackageManagerInternal.ExternalSourcesPolicy() {
- @Override
- public int getPackageTrustedToInstallApps(String packageName, int uid) {
- final AttributionSource attributionSource =
- new AttributionSource.Builder(uid)
- .setPackageName(packageName)
- .build();
- int appOpMode =
- checkOperationWithState(
- AppOpsManager.OP_REQUEST_INSTALL_PACKAGES,
- attributionSource.asState());
- switch (appOpMode) {
- case AppOpsManager.MODE_ALLOWED:
- return PackageManagerInternal.ExternalSourcesPolicy
- .USER_TRUSTED;
- case AppOpsManager.MODE_ERRORED:
- return PackageManagerInternal.ExternalSourcesPolicy
- .USER_BLOCKED;
- default:
- return PackageManagerInternal.ExternalSourcesPolicy
- .USER_DEFAULT;
- }
- }
- });
+ getPackageManagerInternal().setExternalSourcesPolicy(
+ new PackageManagerInternal.ExternalSourcesPolicy() {
+ @Override
+ public int getPackageTrustedToInstallApps(String packageName, int uid) {
+ int appOpMode = checkOperation(AppOpsManager.OP_REQUEST_INSTALL_PACKAGES,
+ uid, packageName);
+ switch (appOpMode) {
+ case AppOpsManager.MODE_ALLOWED:
+ return PackageManagerInternal.ExternalSourcesPolicy.USER_TRUSTED;
+ case AppOpsManager.MODE_ERRORED:
+ return PackageManagerInternal.ExternalSourcesPolicy.USER_BLOCKED;
+ default:
+ return PackageManagerInternal.ExternalSourcesPolicy.USER_DEFAULT;
+ }
+ }
+ });
}
@VisibleForTesting
@@ -2544,41 +2534,22 @@ public class AppOpsService extends IAppOpsService.Stub {
}
}
- /** @deprecated Use {@link #checkOperationWithStateRaw} instead. */
@Override
public int checkOperationRaw(int code, int uid, String packageName,
- @Nullable String attributionTag) {
- final AttributionSource attributionSource = new AttributionSource.Builder(uid)
- .setPackageName(packageName).setAttributionTag(attributionTag).build();
- return mCheckOpsDelegateDispatcher.checkOperation(code, attributionSource, true /*raw*/);
- }
-
- @Override
- public int checkOperationWithStateRaw(int code, AttributionSourceState attributionSourceState) {
- final AttributionSource attributionSource = new AttributionSource(attributionSourceState);
- return mCheckOpsDelegateDispatcher.checkOperation(code, attributionSource, true /*raw*/);
+ @Nullable String attributionTag) {
+ return mCheckOpsDelegateDispatcher.checkOperation(code, uid, packageName, attributionTag,
+ true /*raw*/);
}
- /** @deprecated Use {@link #checkOperationWithState} instead. */
@Override
public int checkOperation(int code, int uid, String packageName) {
- final AttributionSource attributionSource = new AttributionSource.Builder(uid)
- .setPackageName(packageName)
- .build();
- return mCheckOpsDelegateDispatcher.checkOperation(code, attributionSource, false /*raw*/);
+ return mCheckOpsDelegateDispatcher.checkOperation(code, uid, packageName, null,
+ false /*raw*/);
}
- @Override
- public int checkOperationWithState(int code, AttributionSourceState attributionSourceState) {
- final AttributionSource attributionSource = new AttributionSource(attributionSourceState);
- return mCheckOpsDelegateDispatcher.checkOperation(code, attributionSource, false /*raw*/);
- }
-
- private int checkOperationImpl(int code, AttributionSource attributionSource, boolean raw) {
+ private int checkOperationImpl(int code, int uid, String packageName,
+ @Nullable String attributionTag, boolean raw) {
verifyIncomingOp(code);
- final String packageName = attributionSource.getPackageName();
- final int uid = attributionSource.getUid();
- final String attributionTag = attributionSource.getAttributionTag();
if (!isIncomingPackageValid(packageName, UserHandle.getUserId(uid))) {
return AppOpsManager.opToDefaultMode(code);
}
@@ -2643,10 +2614,7 @@ public class AppOpsService extends IAppOpsService.Stub {
if (mode != AppOpsManager.MODE_ALLOWED) {
return mode;
}
- final AttributionSource attributionSource = new AttributionSource.Builder(uid)
- .setPackageName(packageName)
- .build();
- return checkOperationWithState(code, attributionSource.asState());
+ return checkOperation(code, uid, packageName);
}
@Override
@@ -2790,38 +2758,17 @@ public class AppOpsService extends IAppOpsService.Stub {
proxiedFlags, shouldCollectAsyncNotedOp, message, shouldCollectMessage);
}
- /** @deprecated Use {@link #noteOperationWithState} instead. */
@Override
public SyncNotedAppOp noteOperation(int code, int uid, String packageName,
String attributionTag, boolean shouldCollectAsyncNotedOp, String message,
boolean shouldCollectMessage) {
- final AttributionSource attributionSource = new AttributionSource.Builder(uid)
- .setPackageName(packageName)
- .setAttributionTag(attributionTag)
- .build();
- return mCheckOpsDelegateDispatcher.noteOperation(code, attributionSource,
- shouldCollectAsyncNotedOp, message, shouldCollectMessage);
- }
-
- @Override
- public SyncNotedAppOp noteOperationWithState(
- int code,
- AttributionSourceState attributionSourceState,
- boolean shouldCollectAsyncNotedOp,
- String message,
- boolean shouldCollectMessage) {
- final AttributionSource attributionSource = new AttributionSource(attributionSourceState);
- return mCheckOpsDelegateDispatcher.noteOperation(
- code, attributionSource, shouldCollectAsyncNotedOp, message, shouldCollectMessage);
+ return mCheckOpsDelegateDispatcher.noteOperation(code, uid, packageName,
+ attributionTag, shouldCollectAsyncNotedOp, message, shouldCollectMessage);
}
- private SyncNotedAppOp noteOperationImpl(int code, AttributionSource attributionSource,
- boolean shouldCollectAsyncNotedOp,
+ private SyncNotedAppOp noteOperationImpl(int code, int uid, @Nullable String packageName,
+ @Nullable String attributionTag, boolean shouldCollectAsyncNotedOp,
@Nullable String message, boolean shouldCollectMessage) {
- final int uid = attributionSource.getUid();
- final String packageName = attributionSource.getPackageName();
- final String attributionTag = attributionSource.getAttributionTag();
-
verifyIncomingUid(uid);
verifyIncomingOp(code);
if (!isIncomingPackageValid(packageName, UserHandle.getUserId(uid))) {
@@ -3216,42 +3163,22 @@ public class AppOpsService extends IAppOpsService.Stub {
}
}
- /** @deprecated Use {@link #startOperationWithState} instead. */
@Override
public SyncNotedAppOp startOperation(IBinder token, int code, int uid,
- @Nullable String packageName, @Nullable String attributionTag,
- boolean startIfModeDefault, boolean shouldCollectAsyncNotedOp,
- String message, boolean shouldCollectMessage, @AttributionFlags int attributionFlags,
- int attributionChainId) {
- final AttributionSource attributionSource = new AttributionSource.Builder(uid)
- .setPackageName(packageName)
- .setAttributionTag(attributionTag)
- .build();
- return mCheckOpsDelegateDispatcher.startOperation(token, code, attributionSource,
- startIfModeDefault, shouldCollectAsyncNotedOp, message, shouldCollectMessage,
- attributionFlags, attributionChainId);
- }
-
- @Override
- public SyncNotedAppOp startOperationWithState(IBinder token, int code,
- AttributionSourceState attributionSourceState,
+ @Nullable String packageName, @Nullable String attributionTag,
boolean startIfModeDefault, boolean shouldCollectAsyncNotedOp,
String message, boolean shouldCollectMessage, @AttributionFlags int attributionFlags,
int attributionChainId) {
- final AttributionSource attributionSource = new AttributionSource(attributionSourceState);
- return mCheckOpsDelegateDispatcher.startOperation(token, code, attributionSource,
- startIfModeDefault, shouldCollectAsyncNotedOp, message,
+ return mCheckOpsDelegateDispatcher.startOperation(token, code, uid, packageName,
+ attributionTag, startIfModeDefault, shouldCollectAsyncNotedOp, message,
shouldCollectMessage, attributionFlags, attributionChainId);
}
- private SyncNotedAppOp startOperationImpl(@NonNull IBinder clientId, int code,
- AttributionSource attributionSource, boolean startIfModeDefault,
- boolean shouldCollectAsyncNotedOp, @NonNull String message,
+ private SyncNotedAppOp startOperationImpl(@NonNull IBinder clientId, int code, int uid,
+ @Nullable String packageName, @Nullable String attributionTag,
+ boolean startIfModeDefault, boolean shouldCollectAsyncNotedOp, @NonNull String message,
boolean shouldCollectMessage, @AttributionFlags int attributionFlags,
int attributionChainId) {
- final String packageName = attributionSource.getPackageName();
- final int uid = attributionSource.getUid();
- final String attributionTag = attributionSource.getAttributionTag();
verifyIncomingUid(uid);
verifyIncomingOp(code);
if (!isIncomingPackageValid(packageName, UserHandle.getUserId(uid))) {
@@ -3273,7 +3200,7 @@ public class AppOpsService extends IAppOpsService.Stub {
int result = MODE_DEFAULT;
if (code == OP_RECORD_AUDIO_HOTWORD || code == OP_RECEIVE_AMBIENT_TRIGGER_AUDIO
|| code == OP_RECORD_AUDIO_SANDBOXED) {
- result = checkOperationWithState(OP_RECORD_AUDIO, attributionSource.asState());
+ result = checkOperation(OP_RECORD_AUDIO, uid, packageName);
// Check result
if (result != AppOpsManager.MODE_ALLOWED) {
return new SyncNotedAppOp(result, code, attributionTag, packageName);
@@ -3281,7 +3208,7 @@ public class AppOpsService extends IAppOpsService.Stub {
}
// As a special case for OP_CAMERA_SANDBOXED.
if (code == OP_CAMERA_SANDBOXED) {
- result = checkOperationWithState(OP_CAMERA, attributionSource.asState());
+ result = checkOperation(OP_CAMERA, uid, packageName);
// Check result
if (result != AppOpsManager.MODE_ALLOWED) {
return new SyncNotedAppOp(result, code, attributionTag, packageName);
@@ -3585,29 +3512,15 @@ public class AppOpsService extends IAppOpsService.Stub {
packageName);
}
- /** @deprecated Use {@link #finishOperationWithState} instead. */
@Override
public void finishOperation(IBinder clientId, int code, int uid, String packageName,
String attributionTag) {
- final AttributionSource attributionSource = new AttributionSource.Builder(uid)
- .setPackageName(packageName)
- .setAttributionTag(attributionTag)
- .build();
- mCheckOpsDelegateDispatcher.finishOperation(clientId, code, attributionSource);
- }
-
- @Override
- public void finishOperationWithState(IBinder clientId, int code,
- AttributionSourceState attributionSourceState) {
- final AttributionSource attributionSource = new AttributionSource(attributionSourceState);
- mCheckOpsDelegateDispatcher.finishOperation(clientId, code, attributionSource);
+ mCheckOpsDelegateDispatcher.finishOperation(clientId, code, uid, packageName,
+ attributionTag);
}
- private void finishOperationImpl(IBinder clientId, int code,
- AttributionSource attributionSource) {
- final String packageName = attributionSource.getPackageName();
- final int uid = attributionSource.getUid();
- final String attributionTag = attributionSource.getAttributionTag();
+ private void finishOperationImpl(IBinder clientId, int code, int uid, String packageName,
+ String attributionTag) {
verifyIncomingUid(uid);
verifyIncomingOp(code);
if (!isIncomingPackageValid(packageName, UserHandle.getUserId(uid))) {
@@ -5190,13 +5103,8 @@ public class AppOpsService extends IAppOpsService.Stub {
}
if (shell.packageName != null) {
- final AttributionSource shellAttributionSource =
- new AttributionSource.Builder(shell.packageUid)
- .setPackageName(shell.packageName)
- .setAttributionTag(shell.attributionTag)
- .build();
- shell.mInterface.startOperationWithState(shell.mToken, shell.op,
- shellAttributionSource.asState(), true, true,
+ shell.mInterface.startOperation(shell.mToken, shell.op, shell.packageUid,
+ shell.packageName, shell.attributionTag, true, true,
"appops start shell command", true,
AppOpsManager.ATTRIBUTION_FLAG_ACCESSOR, ATTRIBUTION_CHAIN_ID_NONE);
} else {
@@ -5211,13 +5119,8 @@ public class AppOpsService extends IAppOpsService.Stub {
}
if (shell.packageName != null) {
- final AttributionSource shellAttributionSource =
- new AttributionSource.Builder(shell.packageUid)
- .setPackageName(shell.packageName)
- .setAttributionTag(shell.attributionTag)
- .build();
- shell.mInterface.finishOperationWithState(shell.mToken, shell.op,
- shellAttributionSource.asState());
+ shell.mInterface.finishOperation(shell.mToken, shell.op, shell.packageUid,
+ shell.packageName, shell.attributionTag);
} else {
return -1;
}
@@ -6763,24 +6666,25 @@ public class AppOpsService extends IAppOpsService.Stub {
return mCheckOpsDelegate;
}
- public int checkOperation(int code, AttributionSource attributionSource, boolean raw) {
+ public int checkOperation(int code, int uid, String packageName,
+ @Nullable String attributionTag, boolean raw) {
if (mPolicy != null) {
if (mCheckOpsDelegate != null) {
- return mPolicy.checkOperation(code, attributionSource, raw,
+ return mPolicy.checkOperation(code, uid, packageName, attributionTag, raw,
this::checkDelegateOperationImpl);
} else {
- return mPolicy.checkOperation(code, attributionSource, raw,
+ return mPolicy.checkOperation(code, uid, packageName, attributionTag, raw,
AppOpsService.this::checkOperationImpl);
}
} else if (mCheckOpsDelegate != null) {
- return checkDelegateOperationImpl(code, attributionSource, raw);
+ return checkDelegateOperationImpl(code, uid, packageName, attributionTag, raw);
}
- return checkOperationImpl(code, attributionSource, raw);
+ return checkOperationImpl(code, uid, packageName, attributionTag, raw);
}
- private int checkDelegateOperationImpl(int code, AttributionSource attributionSource,
- boolean raw) {
- return mCheckOpsDelegate.checkOperation(code, attributionSource, raw,
+ private int checkDelegateOperationImpl(int code, int uid, String packageName,
+ @Nullable String attributionTag, boolean raw) {
+ return mCheckOpsDelegate.checkOperation(code, uid, packageName, attributionTag, raw,
AppOpsService.this::checkOperationImpl);
}
@@ -6805,32 +6709,32 @@ public class AppOpsService extends IAppOpsService.Stub {
AppOpsService.this::checkAudioOperationImpl);
}
- public SyncNotedAppOp noteOperation(int code, AttributionSource attributionSource,
- boolean shouldCollectAsyncNotedOp, String message,
+ public SyncNotedAppOp noteOperation(int code, int uid, String packageName,
+ String attributionTag, boolean shouldCollectAsyncNotedOp, String message,
boolean shouldCollectMessage) {
if (mPolicy != null) {
if (mCheckOpsDelegate != null) {
- return mPolicy.noteOperation(code, attributionSource,
+ return mPolicy.noteOperation(code, uid, packageName, attributionTag,
shouldCollectAsyncNotedOp, message, shouldCollectMessage,
this::noteDelegateOperationImpl);
} else {
- return mPolicy.noteOperation(code, attributionSource,
+ return mPolicy.noteOperation(code, uid, packageName, attributionTag,
shouldCollectAsyncNotedOp, message, shouldCollectMessage,
AppOpsService.this::noteOperationImpl);
}
} else if (mCheckOpsDelegate != null) {
- return noteDelegateOperationImpl(code, attributionSource, shouldCollectAsyncNotedOp,
- message, shouldCollectMessage);
+ return noteDelegateOperationImpl(code, uid, packageName,
+ attributionTag, shouldCollectAsyncNotedOp, message, shouldCollectMessage);
}
- return noteOperationImpl(code, attributionSource,
+ return noteOperationImpl(code, uid, packageName, attributionTag,
shouldCollectAsyncNotedOp, message, shouldCollectMessage);
}
- private SyncNotedAppOp noteDelegateOperationImpl(int code,
- AttributionSource attributionSource,
+ private SyncNotedAppOp noteDelegateOperationImpl(int code, int uid,
+ @Nullable String packageName, @Nullable String featureId,
boolean shouldCollectAsyncNotedOp, @Nullable String message,
boolean shouldCollectMessage) {
- return mCheckOpsDelegate.noteOperation(code, attributionSource,
+ return mCheckOpsDelegate.noteOperation(code, uid, packageName, featureId,
shouldCollectAsyncNotedOp, message, shouldCollectMessage,
AppOpsService.this::noteOperationImpl);
}
@@ -6866,38 +6770,39 @@ public class AppOpsService extends IAppOpsService.Stub {
AppOpsService.this::noteProxyOperationImpl);
}
- public SyncNotedAppOp startOperation(IBinder token, int code,
- AttributionSource attributionSource, boolean startIfModeDefault,
- boolean shouldCollectAsyncNotedOp, @Nullable String message,
- boolean shouldCollectMessage, @AttributionFlags int attributionFlags,
- int attributionChainId) {
+ public SyncNotedAppOp startOperation(IBinder token, int code, int uid,
+ @Nullable String packageName, @NonNull String attributionTag,
+ boolean startIfModeDefault, boolean shouldCollectAsyncNotedOp,
+ @Nullable String message, boolean shouldCollectMessage,
+ @AttributionFlags int attributionFlags, int attributionChainId) {
if (mPolicy != null) {
if (mCheckOpsDelegate != null) {
- return mPolicy.startOperation(token, code, attributionSource,
- startIfModeDefault, shouldCollectAsyncNotedOp, message,
+ return mPolicy.startOperation(token, code, uid, packageName,
+ attributionTag, startIfModeDefault, shouldCollectAsyncNotedOp, message,
shouldCollectMessage, attributionFlags, attributionChainId,
this::startDelegateOperationImpl);
} else {
- return mPolicy.startOperation(token, code, attributionSource,
+ return mPolicy.startOperation(token, code, uid, packageName, attributionTag,
startIfModeDefault, shouldCollectAsyncNotedOp, message,
shouldCollectMessage, attributionFlags, attributionChainId,
AppOpsService.this::startOperationImpl);
}
} else if (mCheckOpsDelegate != null) {
- return startDelegateOperationImpl(token, code, attributionSource,
+ return startDelegateOperationImpl(token, code, uid, packageName, attributionTag,
startIfModeDefault, shouldCollectAsyncNotedOp, message,
shouldCollectMessage, attributionFlags, attributionChainId);
}
- return startOperationImpl(token, code, attributionSource,
+ return startOperationImpl(token, code, uid, packageName, attributionTag,
startIfModeDefault, shouldCollectAsyncNotedOp, message, shouldCollectMessage,
attributionFlags, attributionChainId);
}
- private SyncNotedAppOp startDelegateOperationImpl(IBinder token, int code,
- AttributionSource attributionSource, boolean startIfModeDefault,
- boolean shouldCollectAsyncNotedOp, String message, boolean shouldCollectMessage,
- @AttributionFlags int attributionFlags, int attributionChainId) {
- return mCheckOpsDelegate.startOperation(token, code, attributionSource,
+ private SyncNotedAppOp startDelegateOperationImpl(IBinder token, int code, int uid,
+ @Nullable String packageName, @Nullable String attributionTag,
+ boolean startIfModeDefault, boolean shouldCollectAsyncNotedOp, String message,
+ boolean shouldCollectMessage, @AttributionFlags int attributionFlags,
+ int attributionChainId) {
+ return mCheckOpsDelegate.startOperation(token, code, uid, packageName, attributionTag,
startIfModeDefault, shouldCollectAsyncNotedOp, message, shouldCollectMessage,
attributionFlags, attributionChainId, AppOpsService.this::startOperationImpl);
}
@@ -6943,26 +6848,26 @@ public class AppOpsService extends IAppOpsService.Stub {
attributionChainId, AppOpsService.this::startProxyOperationImpl);
}
- public void finishOperation(IBinder clientId, int code,
- AttributionSource attributionSource) {
+ public void finishOperation(IBinder clientId, int code, int uid, String packageName,
+ String attributionTag) {
if (mPolicy != null) {
if (mCheckOpsDelegate != null) {
- mPolicy.finishOperation(clientId, code, attributionSource,
+ mPolicy.finishOperation(clientId, code, uid, packageName, attributionTag,
this::finishDelegateOperationImpl);
} else {
- mPolicy.finishOperation(clientId, code, attributionSource,
+ mPolicy.finishOperation(clientId, code, uid, packageName, attributionTag,
AppOpsService.this::finishOperationImpl);
}
} else if (mCheckOpsDelegate != null) {
- finishDelegateOperationImpl(clientId, code, attributionSource);
+ finishDelegateOperationImpl(clientId, code, uid, packageName, attributionTag);
} else {
- finishOperationImpl(clientId, code, attributionSource);
+ finishOperationImpl(clientId, code, uid, packageName, attributionTag);
}
}
- private void finishDelegateOperationImpl(IBinder clientId, int code,
- AttributionSource attributionSource) {
- mCheckOpsDelegate.finishOperation(clientId, code, attributionSource,
+ private void finishDelegateOperationImpl(IBinder clientId, int code, int uid,
+ String packageName, String attributionTag) {
+ mCheckOpsDelegate.finishOperation(clientId, code, uid, packageName, attributionTag,
AppOpsService.this::finishOperationImpl);
}
diff --git a/services/core/java/com/android/server/pdb/PersistentDataBlockService.java b/services/core/java/com/android/server/pdb/PersistentDataBlockService.java
index b006ac862533..a8cba532435d 100644
--- a/services/core/java/com/android/server/pdb/PersistentDataBlockService.java
+++ b/services/core/java/com/android/server/pdb/PersistentDataBlockService.java
@@ -35,11 +35,12 @@ import android.util.Slog;
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.DumpUtils;
-import com.android.server.pm.UserManagerInternal;
import com.android.server.LocalServices;
import com.android.server.SystemServerInitThreadPool;
import com.android.server.SystemService;
+import com.android.server.pm.UserManagerInternal;
import libcore.io.IoUtils;
@@ -53,6 +54,9 @@ import java.io.PrintWriter;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.nio.file.StandardOpenOption;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
@@ -114,21 +118,26 @@ public class PersistentDataBlockService extends SystemService {
private static final String GSI_RUNNING_PROP = "ro.gsid.image_running";
private static final String PERSISTENT_DATA_BLOCK_PROP = "ro.frp.pst";
- private static final int HEADER_SIZE = 8;
+ @VisibleForTesting
+ static final int HEADER_SIZE = 8;
// Magic number to mark block device as adhering to the format consumed by this service
private static final int PARTITION_TYPE_MARKER = 0x19901873;
/** Size of the block reserved for FRP credential, including 4 bytes for the size header. */
private static final int FRP_CREDENTIAL_RESERVED_SIZE = 1000;
/** Maximum size of the FRP credential handle that can be stored. */
- private static final int MAX_FRP_CREDENTIAL_HANDLE_SIZE = FRP_CREDENTIAL_RESERVED_SIZE - 4;
+ @VisibleForTesting
+ static final int MAX_FRP_CREDENTIAL_HANDLE_SIZE = FRP_CREDENTIAL_RESERVED_SIZE - 4;
/**
* Size of the block reserved for Test Harness Mode data, including 4 bytes for the size header.
*/
private static final int TEST_MODE_RESERVED_SIZE = 10000;
/** Maximum size of the Test Harness Mode data that can be stored. */
- private static final int MAX_TEST_MODE_DATA_SIZE = TEST_MODE_RESERVED_SIZE - 4;
+ @VisibleForTesting
+ static final int MAX_TEST_MODE_DATA_SIZE = TEST_MODE_RESERVED_SIZE - 4;
+
// Limit to 100k as blocks larger than this might cause strain on Binder.
- private static final int MAX_DATA_BLOCK_SIZE = 1024 * 100;
+ @VisibleForTesting
+ static final int MAX_DATA_BLOCK_SIZE = 1024 * 100;
public static final int DIGEST_SIZE_BYTES = 32;
private static final String OEM_UNLOCK_PROP = "sys.oem_unlock_allowed";
@@ -138,12 +147,12 @@ public class PersistentDataBlockService extends SystemService {
private final Context mContext;
private final String mDataBlockFile;
- private final boolean mIsRunningDSU;
+ private final boolean mIsFileBacked;
private final Object mLock = new Object();
private final CountDownLatch mInitDoneSignal = new CountDownLatch(1);
private int mAllowedUid = -1;
- private long mBlockDeviceSize;
+ private long mBlockDeviceSize = -1; // Load lazily
@GuardedBy("mLock")
private boolean mIsWritable = true;
@@ -151,13 +160,23 @@ public class PersistentDataBlockService extends SystemService {
public PersistentDataBlockService(Context context) {
super(context);
mContext = context;
- mIsRunningDSU = SystemProperties.getBoolean(GSI_RUNNING_PROP, false);
- if (mIsRunningDSU) {
+ if (SystemProperties.getBoolean(GSI_RUNNING_PROP, false)) {
+ mIsFileBacked = true;
mDataBlockFile = GSI_SANDBOX;
} else {
+ mIsFileBacked = false;
mDataBlockFile = SystemProperties.get(PERSISTENT_DATA_BLOCK_PROP);
}
- mBlockDeviceSize = -1; // Load lazily
+ }
+
+ @VisibleForTesting
+ PersistentDataBlockService(Context context, boolean isFileBacked, String dataBlockFile,
+ long blockDeviceSize) {
+ super(context);
+ mContext = context;
+ mIsFileBacked = isFileBacked;
+ mDataBlockFile = dataBlockFile;
+ mBlockDeviceSize = blockDeviceSize;
}
private int getAllowedUid() {
@@ -212,6 +231,11 @@ public class PersistentDataBlockService extends SystemService {
super.onBootPhase(phase);
}
+ @VisibleForTesting
+ void setAllowedUid(int uid) {
+ mAllowedUid = uid;
+ }
+
private void formatIfOemUnlockEnabled() {
boolean enabled = doGetOemUnlockEnabled();
if (enabled) {
@@ -220,7 +244,7 @@ public class PersistentDataBlockService extends SystemService {
}
}
- SystemProperties.set(OEM_UNLOCK_PROP, enabled ? "1" : "0");
+ setProperty(OEM_UNLOCK_PROP, enabled ? "1" : "0");
}
private void enforceOemUnlockReadPermission() {
@@ -278,7 +302,7 @@ public class PersistentDataBlockService extends SystemService {
private long getBlockDeviceSize() {
synchronized (mLock) {
if (mBlockDeviceSize == -1) {
- if (mIsRunningDSU) {
+ if (mIsFileBacked) {
mBlockDeviceSize = MAX_DATA_BLOCK_SIZE;
} else {
mBlockDeviceSize = nativeGetBlockDeviceSize(mDataBlockFile);
@@ -289,14 +313,26 @@ public class PersistentDataBlockService extends SystemService {
return mBlockDeviceSize;
}
- private long getFrpCredentialDataOffset() {
- return getBlockDeviceSize() - 1 - FRP_CREDENTIAL_RESERVED_SIZE;
+ @VisibleForTesting
+ int getMaximumFrpDataSize() {
+ return (int) (getTestHarnessModeDataOffset() - DIGEST_SIZE_BYTES - HEADER_SIZE);
+ }
+
+ @VisibleForTesting
+ long getFrpCredentialDataOffset() {
+ return getOemUnlockDataOffset() - FRP_CREDENTIAL_RESERVED_SIZE;
}
- private long getTestHarnessModeDataOffset() {
+ @VisibleForTesting
+ long getTestHarnessModeDataOffset() {
return getFrpCredentialDataOffset() - TEST_MODE_RESERVED_SIZE;
}
+ @VisibleForTesting
+ long getOemUnlockDataOffset() {
+ return getBlockDeviceSize() - 1;
+ }
+
private boolean enforceChecksumValidity() {
byte[] storedDigest = new byte[DIGEST_SIZE_BYTES];
@@ -385,7 +421,8 @@ public class PersistentDataBlockService extends SystemService {
return md.digest();
}
- private void formatPartitionLocked(boolean setOemUnlockEnabled) {
+ @VisibleForTesting
+ void formatPartitionLocked(boolean setOemUnlockEnabled) {
try {
FileChannel channel = getBlockOutputChannel();
@@ -448,10 +485,15 @@ public class PersistentDataBlockService extends SystemService {
Slog.e(TAG, "unable to access persistent partition", e);
return;
} finally {
- SystemProperties.set(OEM_UNLOCK_PROP, enabled ? "1" : "0");
+ setProperty(OEM_UNLOCK_PROP, enabled ? "1" : "0");
}
}
+ @VisibleForTesting
+ void setProperty(String name, String value) {
+ SystemProperties.set(name, value);
+ }
+
private boolean doGetOemUnlockEnabled() {
DataInputStream inputStream;
try {
@@ -483,6 +525,16 @@ public class PersistentDataBlockService extends SystemService {
private native long nativeGetBlockDeviceSize(String path);
private native int nativeWipe(String path);
+ @VisibleForTesting
+ IPersistentDataBlockService getInterfaceForTesting() {
+ return IPersistentDataBlockService.Stub.asInterface(mService);
+ }
+
+ @VisibleForTesting
+ PersistentDataBlockManagerInternal getInternalInterfaceForTesting() {
+ return mInternalService;
+ }
+
private final IBinder mService = new IPersistentDataBlockService.Stub() {
/**
@@ -588,7 +640,18 @@ public class PersistentDataBlockService extends SystemService {
enforceOemUnlockWritePermission();
synchronized (mLock) {
- int ret = nativeWipe(mDataBlockFile);
+ int ret;
+ if (mIsFileBacked) {
+ try {
+ Files.write(Paths.get(mDataBlockFile), new byte[MAX_DATA_BLOCK_SIZE],
+ StandardOpenOption.TRUNCATE_EXISTING);
+ ret = 0;
+ } catch (IOException e) {
+ ret = -1;
+ }
+ } else {
+ ret = nativeWipe(mDataBlockFile);
+ }
if (ret < 0) {
Slog.e(TAG, "failed to wipe persistent partition");
@@ -699,7 +762,7 @@ public class PersistentDataBlockService extends SystemService {
if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
pw.println("mDataBlockFile: " + mDataBlockFile);
- pw.println("mIsRunningDSU: " + mIsRunningDSU);
+ pw.println("mIsFileBacked: " + mIsFileBacked);
pw.println("mInitDoneSignal: " + mInitDoneSignal);
pw.println("mAllowedUid: " + mAllowedUid);
pw.println("mBlockDeviceSize: " + mBlockDeviceSize);
diff --git a/services/core/java/com/android/server/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java
index 26e70c0279e3..21284a05ddad 100644
--- a/services/core/java/com/android/server/pm/ApexManager.java
+++ b/services/core/java/com/android/server/pm/ApexManager.java
@@ -410,7 +410,7 @@ public abstract class ApexManager {
* Map of all apex system services to the jar files they are contained in.
*/
@GuardedBy("mLock")
- private List<ApexSystemServiceInfo> mApexSystemServices = new ArrayList<>();
+ private final List<ApexSystemServiceInfo> mApexSystemServices = new ArrayList<>();
/**
* Contains the list of {@code packageName}s of apks-in-apex for given
@@ -418,14 +418,14 @@ public abstract class ApexManager {
* difference between {@code packageName} and {@code apexModuleName}.
*/
@GuardedBy("mLock")
- private ArrayMap<String, List<String>> mApksInApex = new ArrayMap<>();
+ private final ArrayMap<String, List<String>> mApksInApex = new ArrayMap<>();
/**
* Contains the list of {@code Exception}s that were raised when installing apk-in-apex
* inside {@code apexModuleName}.
*/
@GuardedBy("mLock")
- private Map<String, String> mErrorWithApkInApex = new ArrayMap<>();
+ private final Map<String, String> mErrorWithApkInApex = new ArrayMap<>();
/**
* An APEX is a file format that delivers the apex-payload wrapped in an apk container. The
diff --git a/services/core/java/com/android/server/pm/AppsFilterBase.java b/services/core/java/com/android/server/pm/AppsFilterBase.java
index 5b32a94c4eac..a5bc2c36a5a8 100644
--- a/services/core/java/com/android/server/pm/AppsFilterBase.java
+++ b/services/core/java/com/android/server/pm/AppsFilterBase.java
@@ -201,7 +201,7 @@ public abstract class AppsFilterBase implements AppsFilterSnapshot {
protected static final boolean CACHE_VALID = true;
protected static final boolean CACHE_INVALID = false;
- protected AtomicBoolean mCacheValid = new AtomicBoolean(CACHE_INVALID);
+ protected final AtomicBoolean mCacheValid = new AtomicBoolean(CACHE_INVALID);
protected boolean isForceQueryable(int callingAppId) {
return mForceQueryable.contains(callingAppId);
diff --git a/services/core/java/com/android/server/pm/BackgroundDexOptService.java b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
index 9bca9f0192b2..36677df07ca3 100644
--- a/services/core/java/com/android/server/pm/BackgroundDexOptService.java
+++ b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
@@ -89,7 +89,7 @@ public final class BackgroundDexOptService {
private static final long CANCELLATION_WAIT_CHECK_INTERVAL_MS = 200;
- private static ComponentName sDexoptServiceName =
+ private static final ComponentName sDexoptServiceName =
new ComponentName("android", BackgroundDexOptJobService.class.getName());
// Possible return codes of individual optimization steps.
@@ -179,7 +179,7 @@ public final class BackgroundDexOptService {
private final long mDowngradeUnusedAppsThresholdInMillis;
- private List<PackagesUpdatedListener> mPackagesUpdatedListeners = new ArrayList<>();
+ private final List<PackagesUpdatedListener> mPackagesUpdatedListeners = new ArrayList<>();
private int mThermalStatusCutoff = THERMAL_CUTOFF_DEFAULT;
diff --git a/services/core/java/com/android/server/pm/CrossProfileAppsService.java b/services/core/java/com/android/server/pm/CrossProfileAppsService.java
index 486282aa2c04..0bd165ec91fa 100644
--- a/services/core/java/com/android/server/pm/CrossProfileAppsService.java
+++ b/services/core/java/com/android/server/pm/CrossProfileAppsService.java
@@ -21,7 +21,7 @@ import android.content.pm.CrossProfileAppsInternal;
import com.android.server.SystemService;
public class CrossProfileAppsService extends SystemService {
- private CrossProfileAppsServiceImpl mServiceImpl;
+ private final CrossProfileAppsServiceImpl mServiceImpl;
public CrossProfileAppsService(Context context) {
super(context);
diff --git a/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java b/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java
index 5f28e56e996c..f1dc2849a391 100644
--- a/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java
+++ b/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java
@@ -78,8 +78,8 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub {
private final LocalService mLocalService = new LocalService();
- private Context mContext;
- private Injector mInjector;
+ private final Context mContext;
+ private final Injector mInjector;
public CrossProfileAppsServiceImpl(Context context) {
this(context, new InjectorImpl(context));
@@ -783,7 +783,7 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub {
}
private static class InjectorImpl implements Injector {
- private Context mContext;
+ private final Context mContext;
public InjectorImpl(Context context) {
mContext = context;
diff --git a/services/core/java/com/android/server/pm/CrossProfileDomainInfo.java b/services/core/java/com/android/server/pm/CrossProfileDomainInfo.java
index 72f3afc35e99..3313e7234a19 100644
--- a/services/core/java/com/android/server/pm/CrossProfileDomainInfo.java
+++ b/services/core/java/com/android/server/pm/CrossProfileDomainInfo.java
@@ -22,10 +22,10 @@ import android.os.UserHandle;
public final class CrossProfileDomainInfo {
/* ResolveInfo for IntentForwarderActivity to send the intent to the other profile */
- ResolveInfo mResolveInfo;
+ final ResolveInfo mResolveInfo;
int mHighestApprovalLevel;
@UserIdInt
- int mTargetUserId = UserHandle.USER_CURRENT; // default as current user
+ final int mTargetUserId;
CrossProfileDomainInfo(ResolveInfo resolveInfo, int highestApprovalLevel, @UserIdInt
int targetUserId) {
@@ -37,6 +37,7 @@ public final class CrossProfileDomainInfo {
CrossProfileDomainInfo(ResolveInfo resolveInfo, int highestApprovalLevel) {
this.mResolveInfo = resolveInfo;
this.mHighestApprovalLevel = highestApprovalLevel;
+ this.mTargetUserId = UserHandle.USER_CURRENT; // default as current user
}
@Override
diff --git a/services/core/java/com/android/server/pm/CrossProfileIntentFilterHelper.java b/services/core/java/com/android/server/pm/CrossProfileIntentFilterHelper.java
index 51214faca730..56e9c0a3544b 100644
--- a/services/core/java/com/android/server/pm/CrossProfileIntentFilterHelper.java
+++ b/services/core/java/com/android/server/pm/CrossProfileIntentFilterHelper.java
@@ -25,11 +25,11 @@ import android.util.ArraySet;
* Helper class to manage {@link com.android.server.pm.CrossProfileIntentFilter}s.
*/
public class CrossProfileIntentFilterHelper {
- private Context mContext;
- private UserManagerInternal mUserManagerInternal;
- private Settings mSettings;
- private UserManagerService mUserManagerService;
- private PackageManagerTracedLock mLock;
+ private final Context mContext;
+ private final UserManagerInternal mUserManagerInternal;
+ private final Settings mSettings;
+ private final UserManagerService mUserManagerService;
+ private final PackageManagerTracedLock mLock;
public CrossProfileIntentFilterHelper(Settings settings, UserManagerService userManagerService,
PackageManagerTracedLock lock, UserManagerInternal userManagerInternal,
diff --git a/services/core/java/com/android/server/pm/CrossProfileResolver.java b/services/core/java/com/android/server/pm/CrossProfileResolver.java
index a8da818932fa..1d38bbb2a1bd 100644
--- a/services/core/java/com/android/server/pm/CrossProfileResolver.java
+++ b/services/core/java/com/android/server/pm/CrossProfileResolver.java
@@ -36,8 +36,8 @@ import java.util.function.Function;
*/
public abstract class CrossProfileResolver {
- protected ComponentResolverApi mComponentResolver;
- protected UserManagerService mUserManager;
+ protected final ComponentResolverApi mComponentResolver;
+ protected final UserManagerService mUserManager;
public CrossProfileResolver(ComponentResolverApi componentResolver,
UserManagerService userManager) {
diff --git a/services/core/java/com/android/server/pm/DataLoaderManagerService.java b/services/core/java/com/android/server/pm/DataLoaderManagerService.java
index 29322e2553e9..888e1c26206c 100644
--- a/services/core/java/com/android/server/pm/DataLoaderManagerService.java
+++ b/services/core/java/com/android/server/pm/DataLoaderManagerService.java
@@ -50,7 +50,8 @@ public class DataLoaderManagerService extends SystemService {
private final HandlerThread mThread;
private final Handler mHandler;
private final DataLoaderManagerBinderService mBinderService;
- private SparseArray<DataLoaderServiceConnection> mServiceConnections = new SparseArray<>();
+ private final SparseArray<DataLoaderServiceConnection> mServiceConnections =
+ new SparseArray<>();
public DataLoaderManagerService(Context context) {
super(context);
diff --git a/services/core/java/com/android/server/pm/DefaultCrossProfileIntentFilter.java b/services/core/java/com/android/server/pm/DefaultCrossProfileIntentFilter.java
index dc5915de5551..db05dd394915 100644
--- a/services/core/java/com/android/server/pm/DefaultCrossProfileIntentFilter.java
+++ b/services/core/java/com/android/server/pm/DefaultCrossProfileIntentFilter.java
@@ -75,10 +75,10 @@ public final class DefaultCrossProfileIntentFilter {
}
static final class Builder {
- private WatchedIntentFilter mFilter = new WatchedIntentFilter();
- private int mFlags;
- private @Direction int mDirection;
- private boolean mLetsPersonalDataIntoProfile;
+ private final WatchedIntentFilter mFilter = new WatchedIntentFilter();
+ private final int mFlags;
+ private final @Direction int mDirection;
+ private final boolean mLetsPersonalDataIntoProfile;
Builder(@Direction int direction, int flags, boolean letsPersonalDataIntoProfile) {
mDirection = direction;
diff --git a/services/core/java/com/android/server/pm/InstallArgs.java b/services/core/java/com/android/server/pm/InstallArgs.java
index dd96a2b84a97..cc6bb007411e 100644
--- a/services/core/java/com/android/server/pm/InstallArgs.java
+++ b/services/core/java/com/android/server/pm/InstallArgs.java
@@ -67,7 +67,8 @@ final class InstallArgs {
// The list of instruction sets supported by this app. This is currently
// only used during the rmdex() phase to clean up resources. We can get rid of this
// if we move dex files under the common app path.
- @Nullable String[] mInstructionSets;
+ @Nullable
+ final String[] mInstructionSets;
InstallArgs(OriginInfo originInfo, MoveInfo moveInfo, IPackageInstallObserver2 observer,
int installFlags, int developmentInstallFlags, InstallSource installSource,
diff --git a/services/core/java/com/android/server/pm/InstallRequest.java b/services/core/java/com/android/server/pm/InstallRequest.java
index be4fb5c539a9..fc831205f60e 100644
--- a/services/core/java/com/android/server/pm/InstallRequest.java
+++ b/services/core/java/com/android/server/pm/InstallRequest.java
@@ -153,7 +153,7 @@ final class InstallRequest {
private int[] mUpdateBroadcastInstantUserIds = EMPTY_INT_ARRAY;
@NonNull
- private ArrayList<String> mWarnings = new ArrayList<>();
+ private final ArrayList<String> mWarnings = new ArrayList<>();
// New install
InstallRequest(InstallingSession params) {
diff --git a/services/core/java/com/android/server/pm/InstallingSession.java b/services/core/java/com/android/server/pm/InstallingSession.java
index ca8dc2973404..187cadaf4d46 100644
--- a/services/core/java/com/android/server/pm/InstallingSession.java
+++ b/services/core/java/com/android/server/pm/InstallingSession.java
@@ -68,7 +68,7 @@ class InstallingSession {
final MoveInfo mMoveInfo;
final IPackageInstallObserver2 mObserver;
int mInstallFlags;
- int mDevelopmentInstallFlags;
+ final int mDevelopmentInstallFlags;
@NonNull
final InstallSource mInstallSource;
final String mVolumeUuid;
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index 8b82a1c6e7c9..3f4cc4a84ffd 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -233,7 +233,8 @@ public class LauncherAppsService extends SystemService {
final LauncherAppsServiceInternal mInternal;
@NonNull
- private final RemoteCallbackList<IDumpCallback> mDumpCallbacks = new RemoteCallbackList<>();
+ private final RemoteCallbackList<IDumpCallback> mDumpCallbacks =
+ new RemoteCallbackList<>();
public LauncherAppsImpl(Context context) {
mContext = context;
@@ -2374,8 +2375,8 @@ public class LauncherAppsService extends SystemService {
class PackageLoadingProgressCallback extends
PackageManagerInternal.InstalledLoadingProgressCallback {
- private String mPackageName;
- private UserHandle mUser;
+ private final String mPackageName;
+ private final UserHandle mUser;
PackageLoadingProgressCallback(String packageName, UserHandle user) {
super(mCallbackHandler);
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index a4d8632ac077..98eee4dc3b1d 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -1867,7 +1867,8 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
}
static class ParentChildSessionMap {
- private TreeMap<PackageInstallerSession, TreeSet<PackageInstallerSession>> mSessionMap;
+ private final TreeMap<PackageInstallerSession, TreeSet<PackageInstallerSession>>
+ mSessionMap;
private final Comparator<PackageInstallerSession> mSessionCreationComparator =
Comparator.comparingLong(
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 1be28ca9e915..4b466be8476b 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -491,7 +491,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
@GuardedBy("mLock")
private SigningDetails mSigningDetails;
@GuardedBy("mLock")
- private SparseArray<PackageInstallerSession> mChildSessions = new SparseArray<>();
+ private final SparseArray<PackageInstallerSession> mChildSessions = new SparseArray<>();
@GuardedBy("mLock")
private int mParentSessionId;
@@ -535,7 +535,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
@GuardedBy("mLock")
- private ArraySet<FileEntry> mFiles = new ArraySet<>();
+ private final ArraySet<FileEntry> mFiles = new ArraySet<>();
static class PerFileChecksum {
private final Checksum[] mChecksums;
@@ -556,7 +556,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
@GuardedBy("mLock")
- private ArrayMap<String, PerFileChecksum> mChecksums = new ArrayMap<>();
+ private final ArrayMap<String, PerFileChecksum> mChecksums = new ArrayMap<>();
@GuardedBy("mLock")
private boolean mSessionApplied;
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceTestParams.java b/services/core/java/com/android/server/pm/PackageManagerServiceTestParams.java
index 9428ef6c8ba9..655b9c93d9dd 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceTestParams.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceTestParams.java
@@ -60,7 +60,7 @@ public final class PackageManagerServiceTestParams {
public IncrementalManager incrementalManager;
public PackageInstallerService installerService;
public InstantAppRegistry instantAppRegistry;
- public ChangedPackagesTracker changedPackagesTracker = new ChangedPackagesTracker();
+ public final ChangedPackagesTracker changedPackagesTracker = new ChangedPackagesTracker();
public InstantAppResolverConnection instantAppResolverConnection;
public ComponentName instantAppResolverSettingsComponent;
public boolean isPreNmr1Upgrade;
@@ -118,7 +118,7 @@ public final class PackageManagerServiceTestParams {
public SuspendPackageHelper suspendPackageHelper;
public DistractingPackageHelper distractingPackageHelper;
public StorageEventHelper storageEventHelper;
- public Set<String> initialNonStoppedSystemPackages = new ArraySet<>();
+ public final Set<String> initialNonStoppedSystemPackages = new ArraySet<>();
public boolean shouldStopSystemPackagesByDefault;
public FreeStorageHelper freeStorageHelper;
public PackageMonitorCallbackHelper packageMonitorCallbackHelper;
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index d4abad8499f2..6f45d2befc6b 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -2364,7 +2364,7 @@ class PackageManagerShellCommand extends ShellCommand {
private boolean mSuccess = false;
private int mErrCode = -1;
private ParcelFileDescriptor mProfileReadFd = null;
- private CountDownLatch mDoneSignal = new CountDownLatch(1);
+ private final CountDownLatch mDoneSignal = new CountDownLatch(1);
@Override
public void onSuccess(ParcelFileDescriptor profileReadFd) {
@@ -5186,7 +5186,7 @@ class PackageManagerShellCommand extends ShellCommand {
private static class LocalIntentReceiver {
private final LinkedBlockingQueue<Intent> mResult = new LinkedBlockingQueue<>();
- private IIntentSender.Stub mLocalSender = new IIntentSender.Stub() {
+ private final IIntentSender.Stub mLocalSender = new IIntentSender.Stub() {
@Override
public void send(int code, Intent intent, String resolvedType, IBinder whitelistToken,
IIntentReceiver finishedReceiver, String requiredPermission, Bundle options) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommandDataLoader.java b/services/core/java/com/android/server/pm/PackageManagerShellCommandDataLoader.java
index a09e71311125..c829e1c79ba8 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommandDataLoader.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommandDataLoader.java
@@ -148,7 +148,8 @@ public class PackageManagerShellCommandDataLoader extends DataLoaderService {
private final byte[] mData;
private final String mSalt;
- private static AtomicLong sGlobalSalt = new AtomicLong((new SecureRandom()).nextLong());
+ private static final AtomicLong sGlobalSalt =
+ new AtomicLong((new SecureRandom()).nextLong());
private static Long nextGlobalSalt() {
return sGlobalSalt.incrementAndGet();
}
diff --git a/services/core/java/com/android/server/pm/PreferredComponent.java b/services/core/java/com/android/server/pm/PreferredComponent.java
index 5507e7c7754a..18caafdaa56a 100644
--- a/services/core/java/com/android/server/pm/PreferredComponent.java
+++ b/services/core/java/com/android/server/pm/PreferredComponent.java
@@ -48,7 +48,7 @@ public class PreferredComponent {
public final int mMatch;
public final ComponentName mComponent;
// Whether this is to be the one that's always chosen. If false, it's the most recently chosen.
- public boolean mAlways;
+ public final boolean mAlways;
final String[] mSetPackages;
final String[] mSetClasses;
diff --git a/services/core/java/com/android/server/pm/SELinuxMMAC.java b/services/core/java/com/android/server/pm/SELinuxMMAC.java
index cf5aa7b1eb02..e667bfe36d18 100644
--- a/services/core/java/com/android/server/pm/SELinuxMMAC.java
+++ b/services/core/java/com/android/server/pm/SELinuxMMAC.java
@@ -68,12 +68,12 @@ public final class SELinuxMMAC {
// All policy stanzas read from mac_permissions.xml. This is also the lock
// to synchronize access during policy load and access attempts.
- private static List<Policy> sPolicies = new ArrayList<>();
+ private static final List<Policy> sPolicies = new ArrayList<>();
/** Whether or not the policy files have been read */
private static boolean sPolicyRead;
/** Required MAC permissions files */
- private static List<File> sMacPermissions = new ArrayList<>();
+ private static final List<File> sMacPermissions = new ArrayList<>();
private static final String DEFAULT_SEINFO = "default";
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 440823c43607..6338965e4a80 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -3944,9 +3944,9 @@ public final class Settings implements Watchable, Snappable, ResilientAtomicFile
mDisabledSysPackages.put(name, ps);
}
- private static int PRE_M_APP_INFO_FLAG_HIDDEN = 1<<27;
- private static int PRE_M_APP_INFO_FLAG_CANT_SAVE_STATE = 1<<28;
- private static int PRE_M_APP_INFO_FLAG_PRIVILEGED = 1<<30;
+ private static final int PRE_M_APP_INFO_FLAG_HIDDEN = 1 << 27;
+ private static final int PRE_M_APP_INFO_FLAG_CANT_SAVE_STATE = 1 << 28;
+ private static final int PRE_M_APP_INFO_FLAG_PRIVILEGED = 1 << 30;
private void readPackageLPw(TypedXmlPullParser parser, List<UserInfo> users,
ArrayMap<String, Long> originalFirstInstallTimes)
@@ -5846,7 +5846,7 @@ public final class Settings implements Watchable, Snappable, ResilientAtomicFile
@GuardedBy("mLock")
// Tracking the mutations that haven't yet been written to legacy state.
// This avoids unnecessary work when writing settings for multiple users.
- private AtomicBoolean mIsLegacyPermissionStateStale = new AtomicBoolean(false);
+ private final AtomicBoolean mIsLegacyPermissionStateStale = new AtomicBoolean(false);
@GuardedBy("mLock")
// The mapping keys are user ids.
diff --git a/services/core/java/com/android/server/pm/ShortcutPackageItem.java b/services/core/java/com/android/server/pm/ShortcutPackageItem.java
index 8667888fbb51..12115afcbeec 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackageItem.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackageItem.java
@@ -53,7 +53,7 @@ abstract class ShortcutPackageItem {
protected ShortcutUser mShortcutUser;
@GuardedBy("mLock")
- protected ShortcutBitmapSaver mShortcutBitmapSaver;
+ protected final ShortcutBitmapSaver mShortcutBitmapSaver;
protected final Object mLock = new Object();
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index c6aba2ab9cbe..3adeb4b5925f 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -296,24 +296,26 @@ public class ShortcutService extends IShortcutService.Stub {
private final Object mNonPersistentUsersLock = new Object();
private final Object mWtfLock = new Object();
- private static List<ResolveInfo> EMPTY_RESOLVE_INFO = new ArrayList<>(0);
+ private static final List<ResolveInfo> EMPTY_RESOLVE_INFO = new ArrayList<>(0);
// Temporarily reverted to anonymous inner class form due to: b/32554459
- private static Predicate<ResolveInfo> ACTIVITY_NOT_EXPORTED = new Predicate<ResolveInfo>() {
- public boolean test(ResolveInfo ri) {
- return !ri.activityInfo.exported;
- }
- };
+ private static final Predicate<ResolveInfo> ACTIVITY_NOT_EXPORTED =
+ new Predicate<ResolveInfo>() {
+ public boolean test(ResolveInfo ri) {
+ return !ri.activityInfo.exported;
+ }
+ };
- private static Predicate<ResolveInfo> ACTIVITY_NOT_INSTALLED = (ri) ->
+ private static final Predicate<ResolveInfo> ACTIVITY_NOT_INSTALLED = (ri) ->
!isInstalled(ri.activityInfo);
// Temporarily reverted to anonymous inner class form due to: b/32554459
- private static Predicate<PackageInfo> PACKAGE_NOT_INSTALLED = new Predicate<PackageInfo>() {
- public boolean test(PackageInfo pi) {
- return !isInstalled(pi);
- }
- };
+ private static final Predicate<PackageInfo> PACKAGE_NOT_INSTALLED =
+ new Predicate<PackageInfo>() {
+ public boolean test(PackageInfo pi) {
+ return !isInstalled(pi);
+ }
+ };
private final Handler mHandler;
@@ -4656,8 +4658,8 @@ public class ShortcutService extends IShortcutService.Stub {
private boolean mDumpFiles = false;
private boolean mDumpDetails = true;
- private List<Pattern> mPackagePatterns = new ArrayList<>();
- private List<Integer> mUsers = new ArrayList<>();
+ private final List<Pattern> mPackagePatterns = new ArrayList<>();
+ private final List<Integer> mUsers = new ArrayList<>();
void addPackageRegex(String regex) {
mPackagePatterns.add(Pattern.compile(regex));
diff --git a/services/core/java/com/android/server/pm/SnapshotStatistics.java b/services/core/java/com/android/server/pm/SnapshotStatistics.java
index e04a1e5b3569..31541d083fbc 100644
--- a/services/core/java/com/android/server/pm/SnapshotStatistics.java
+++ b/services/core/java/com/android/server/pm/SnapshotStatistics.java
@@ -157,12 +157,12 @@ public class SnapshotStatistics {
private static class BinMap {
// The number of bins
- private int mCount;
+ private final int mCount;
// The maximum mapped value. Values at or above this are mapped to the
// top bin.
- private int mMaxBin;
+ private final int mMaxBin;
// A copy of the original key
- private int[] mUserKey;
+ private final int[] mUserKey;
/**
* Create a bin map. The input is an array of integers, which must be
@@ -232,13 +232,13 @@ public class SnapshotStatistics {
* The build-time histogram. The total number of rebuilds is the sum over the
* histogram entries.
*/
- public int[] mTimes;
+ public final int[] mTimes;
/**
* The reuse histogram. The total number of snapshot uses is the sum over the
* histogram entries.
*/
- public int[] mUsed;
+ public final int[] mUsed;
/**
* The total number of rebuilds. This could be computed by summing over the use
@@ -477,12 +477,12 @@ public class SnapshotStatistics {
/**
* Long statistics. These roll over approximately one day.
*/
- private Stats[] mLong;
+ private final Stats[] mLong;
/**
* Short statistics. These roll over approximately every minute;
*/
- private Stats[] mShort;
+ private final Stats[] mShort;
/**
* The time of last logging to the FrameworkStatsLog.
diff --git a/services/core/java/com/android/server/pm/UserJourneyLogger.java b/services/core/java/com/android/server/pm/UserJourneyLogger.java
index 895edce093b5..651578dc5deb 100644
--- a/services/core/java/com/android/server/pm/UserJourneyLogger.java
+++ b/services/core/java/com/android/server/pm/UserJourneyLogger.java
@@ -586,7 +586,7 @@ public class UserJourneyLogger {
public final long mSessionId;
@UserJourney
public final int mJourney;
- public long mStartTimeInMills;
+ public final long mStartTimeInMills;
@VisibleForTesting
public UserJourneySession(long sessionId, @UserJourney int journey) {
diff --git a/services/core/java/com/android/server/pm/dex/DexManager.java b/services/core/java/com/android/server/pm/dex/DexManager.java
index 6e738daf9315..78c13f854fe4 100644
--- a/services/core/java/com/android/server/pm/dex/DexManager.java
+++ b/services/core/java/com/android/server/pm/dex/DexManager.java
@@ -119,10 +119,10 @@ public class DexManager {
private final int mCriticalBatteryLevel;
// Possible outcomes of a dex search.
- private static int DEX_SEARCH_NOT_FOUND = 0; // dex file not found
- private static int DEX_SEARCH_FOUND_PRIMARY = 1; // dex file is the primary/base apk
- private static int DEX_SEARCH_FOUND_SPLIT = 2; // dex file is a split apk
- private static int DEX_SEARCH_FOUND_SECONDARY = 3; // dex file is a secondary dex
+ private static final int DEX_SEARCH_NOT_FOUND = 0; // dex file not found
+ private static final int DEX_SEARCH_FOUND_PRIMARY = 1; // dex file is the primary/base apk
+ private static final int DEX_SEARCH_FOUND_SPLIT = 2; // dex file is a split apk
+ private static final int DEX_SEARCH_FOUND_SECONDARY = 3; // dex file is a secondary dex
public DexManager(Context context, PackageDexOptimizer pdo, Installer installer,
Object installLock, DynamicCodeLogger dynamicCodeLogger) {
@@ -959,8 +959,8 @@ public class DexManager {
* Convenience class to store ownership search results.
*/
private class DexSearchResult {
- private String mOwningPackageName;
- private int mOutcome;
+ private final String mOwningPackageName;
+ private final int mOutcome;
public DexSearchResult(String owningPackageName, int outcome) {
this.mOwningPackageName = owningPackageName;
diff --git a/services/core/java/com/android/server/pm/parsing/PackageCacher.java b/services/core/java/com/android/server/pm/parsing/PackageCacher.java
index d3a64bb0b9ac..2ab7db47f8e5 100644
--- a/services/core/java/com/android/server/pm/parsing/PackageCacher.java
+++ b/services/core/java/com/android/server/pm/parsing/PackageCacher.java
@@ -49,7 +49,7 @@ public class PackageCacher {
public static final AtomicInteger sCachedPackageReadCount = new AtomicInteger();
@NonNull
- private File mCacheDir;
+ private final File mCacheDir;
public PackageCacher(@NonNull File cacheDir) {
this.mCacheDir = cacheDir;
diff --git a/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
index 9e20805c2874..c26cf1c9a113 100644
--- a/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
+++ b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
@@ -1132,7 +1132,7 @@ public class PackageInfoUtils {
*/
public static class CachedApplicationInfoGenerator {
// Map from a package name to the corresponding app info.
- private ArrayMap<String, ApplicationInfo> mCache = new ArrayMap<>();
+ private final ArrayMap<String, ApplicationInfo> mCache = new ArrayMap<>();
/**
* {@link PackageInfoUtils#generateApplicationInfo} with a cache.
diff --git a/services/core/java/com/android/server/pm/parsing/PackageParser2.java b/services/core/java/com/android/server/pm/parsing/PackageParser2.java
index d82a5000844f..3b10c7f2c2a6 100644
--- a/services/core/java/com/android/server/pm/parsing/PackageParser2.java
+++ b/services/core/java/com/android/server/pm/parsing/PackageParser2.java
@@ -96,19 +96,19 @@ public class PackageParser2 implements AutoCloseable {
private static final boolean LOG_PARSE_TIMINGS = Build.IS_DEBUGGABLE;
private static final int LOG_PARSE_TIMINGS_THRESHOLD_MS = 100;
- private ThreadLocal<ApplicationInfo> mSharedAppInfo =
+ private final ThreadLocal<ApplicationInfo> mSharedAppInfo =
ThreadLocal.withInitial(() -> {
ApplicationInfo appInfo = new ApplicationInfo();
appInfo.uid = -1; // Not a valid UID since the app will not be installed yet
return appInfo;
});
- private ThreadLocal<ParseTypeImpl> mSharedResult;
+ private final ThreadLocal<ParseTypeImpl> mSharedResult;
@Nullable
protected PackageCacher mCacher;
- private ParsingPackageUtils parsingUtils;
+ private final ParsingPackageUtils parsingUtils;
public PackageParser2(String[] separateProcesses, DisplayMetrics displayMetrics,
@Nullable File cacheDir, @NonNull Callback callback) {
diff --git a/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java b/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java
index 056aae49ae82..75dd67d97620 100644
--- a/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java
+++ b/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java
@@ -113,21 +113,21 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal,
private static final SparseArray<int[]> EMPTY_INT_ARRAY_SPARSE_ARRAY = new SparseArray<>();
private static final Comparator<ParsedMainComponent> ORDER_COMPARATOR =
(first, second) -> Integer.compare(second.getOrder(), first.getOrder());
- public static Parcelling.BuiltIn.ForBoolean sForBoolean = Parcelling.Cache.getOrCreate(
+ public static final Parcelling.BuiltIn.ForBoolean sForBoolean = Parcelling.Cache.getOrCreate(
Parcelling.BuiltIn.ForBoolean.class);
- public static ForInternedString sForInternedString = Parcelling.Cache.getOrCreate(
+ public static final ForInternedString sForInternedString = Parcelling.Cache.getOrCreate(
ForInternedString.class);
- public static Parcelling.BuiltIn.ForInternedStringArray sForInternedStringArray = Parcelling.Cache.getOrCreate(
- Parcelling.BuiltIn.ForInternedStringArray.class);
- public static Parcelling.BuiltIn.ForInternedStringList sForInternedStringList = Parcelling.Cache.getOrCreate(
- Parcelling.BuiltIn.ForInternedStringList.class);
- public static Parcelling.BuiltIn.ForInternedStringValueMap sForInternedStringValueMap =
+ public static final Parcelling.BuiltIn.ForInternedStringArray sForInternedStringArray =
+ Parcelling.Cache.getOrCreate(Parcelling.BuiltIn.ForInternedStringArray.class);
+ public static final Parcelling.BuiltIn.ForInternedStringList sForInternedStringList =
+ Parcelling.Cache.getOrCreate(Parcelling.BuiltIn.ForInternedStringList.class);
+ public static final Parcelling.BuiltIn.ForInternedStringValueMap sForInternedStringValueMap =
Parcelling.Cache.getOrCreate(Parcelling.BuiltIn.ForInternedStringValueMap.class);
- public static Parcelling.BuiltIn.ForStringSet sForStringSet = Parcelling.Cache.getOrCreate(
- Parcelling.BuiltIn.ForStringSet.class);
- public static Parcelling.BuiltIn.ForInternedStringSet sForInternedStringSet =
+ public static final Parcelling.BuiltIn.ForStringSet sForStringSet =
+ Parcelling.Cache.getOrCreate(Parcelling.BuiltIn.ForStringSet.class);
+ public static final Parcelling.BuiltIn.ForInternedStringSet sForInternedStringSet =
Parcelling.Cache.getOrCreate(Parcelling.BuiltIn.ForInternedStringSet.class);
- protected static ParsingUtils.StringPairListParceler sForIntentInfoPairs =
+ protected static final ParsingUtils.StringPairListParceler sForIntentInfoPairs =
new ParsingUtils.StringPairListParceler();
protected int versionCode;
protected int versionCodeMajor;
diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
index d6a7dc6681b9..6f6bb45bad50 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -1748,14 +1748,14 @@ final class DefaultPermissionGrantPolicy {
*/
private class DelayingPackageManagerCache extends PackageManagerWrapper {
/** uid -> permission -> isGranted, flags */
- private SparseArray<ArrayMap<String, PermissionState>> mDelayedPermissionState =
+ private final SparseArray<ArrayMap<String, PermissionState>> mDelayedPermissionState =
new SparseArray<>();
/** userId -> context */
- private SparseArray<Context> mUserContexts = new SparseArray<>();
+ private final SparseArray<Context> mUserContexts = new SparseArray<>();
/** Permission name -> info */
- private ArrayMap<String, PermissionInfo> mPermissionInfos = new ArrayMap<>();
+ private final ArrayMap<String, PermissionInfo> mPermissionInfos = new ArrayMap<>();
/** Package name -> info */
- private ArrayMap<String, PackageInfo> mPackageInfos = new ArrayMap<>();
+ private final ArrayMap<String, PackageInfo> mPackageInfos = new ArrayMap<>();
/**
* Apply the cached state
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedPermissionImpl.java b/services/core/java/com/android/server/pm/pkg/component/ParsedPermissionImpl.java
index 70986c3cfbac..4c831d36c9e3 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedPermissionImpl.java
+++ b/services/core/java/com/android/server/pm/pkg/component/ParsedPermissionImpl.java
@@ -41,7 +41,8 @@ import java.util.Set;
public class ParsedPermissionImpl extends ParsedComponentImpl implements ParsedPermission,
Parcelable {
- private static ForStringSet sForStringSet = Parcelling.Cache.getOrCreate(ForStringSet.class);
+ private static final ForStringSet sForStringSet =
+ Parcelling.Cache.getOrCreate(ForStringSet.class);
@Nullable
private String backgroundPermission;
diff --git a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
index 8240c47a607b..061698a929d6 100644
--- a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
+++ b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
@@ -328,11 +328,11 @@ public class ParsingPackageUtils {
return input.success(pkg);
}
- private String[] mSeparateProcesses;
- private DisplayMetrics mDisplayMetrics;
+ private final String[] mSeparateProcesses;
+ private final DisplayMetrics mDisplayMetrics;
@NonNull
- private List<PermissionManager.SplitPermissionInfo> mSplitPermissionInfos;
- private Callback mCallback;
+ private final List<PermissionManager.SplitPermissionInfo> mSplitPermissionInfos;
+ private final Callback mCallback;
public ParsingPackageUtils(String[] separateProcesses, DisplayMetrics displayMetrics,
@NonNull List<PermissionManager.SplitPermissionInfo> splitPermissions,
diff --git a/services/core/java/com/android/server/pm/resolution/ComponentResolver.java b/services/core/java/com/android/server/pm/resolution/ComponentResolver.java
index fac681aaf1c4..0ceda421913d 100644
--- a/services/core/java/com/android/server/pm/resolution/ComponentResolver.java
+++ b/services/core/java/com/android/server/pm/resolution/ComponentResolver.java
@@ -951,7 +951,7 @@ public class ComponentResolver extends ComponentResolverLocked implements
extends MimeGroupsAwareIntentResolver<Pair<ParsedActivity, ParsedIntentInfo>, ResolveInfo> {
@NonNull
- private UserNeedsBadgingCache mUserNeedsBadging;
+ private final UserNeedsBadgingCache mUserNeedsBadging;
// Default constructor
ActivityIntentResolver(@NonNull UserManagerService userManager,
diff --git a/services/core/java/com/android/server/pm/resolution/ComponentResolverBase.java b/services/core/java/com/android/server/pm/resolution/ComponentResolverBase.java
index 9115775acd05..80cde73ecf1f 100644
--- a/services/core/java/com/android/server/pm/resolution/ComponentResolverBase.java
+++ b/services/core/java/com/android/server/pm/resolution/ComponentResolverBase.java
@@ -68,7 +68,7 @@ public abstract class ComponentResolverBase extends WatchableImpl implements Com
protected ArrayMap<String, ParsedProvider> mProvidersByAuthority;
@NonNull
- protected UserManagerService mUserManager;
+ protected final UserManagerService mUserManager;
protected ComponentResolverBase(@NonNull UserManagerService userManager) {
mUserManager = userManager;
diff --git a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java
index 11f62e953525..3d4d4eca7f48 100644
--- a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java
+++ b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java
@@ -2005,9 +2005,9 @@ public class DomainVerificationService extends SystemService
private static class GetAttachedResult {
@Nullable
- private DomainVerificationPkgState mPkgState;
+ private final DomainVerificationPkgState mPkgState;
- private int mErrorCode;
+ private final int mErrorCode;
GetAttachedResult(@Nullable DomainVerificationPkgState pkgState, int errorCode) {
mPkgState = pkgState;
diff --git a/services/core/java/com/android/server/pm/verify/domain/models/DomainVerificationPkgState.java b/services/core/java/com/android/server/pm/verify/domain/models/DomainVerificationPkgState.java
index 6c56360177d8..d71dbbb5d53b 100644
--- a/services/core/java/com/android/server/pm/verify/domain/models/DomainVerificationPkgState.java
+++ b/services/core/java/com/android/server/pm/verify/domain/models/DomainVerificationPkgState.java
@@ -40,7 +40,7 @@ public class DomainVerificationPkgState {
private final String mPackageName;
@NonNull
- private UUID mId;
+ private final UUID mId;
/**
* Whether or not the package declares any autoVerify domains. This is separate from an empty
diff --git a/services/core/java/com/android/server/policy/AppOpsPolicy.java b/services/core/java/com/android/server/policy/AppOpsPolicy.java
index c2821aef2142..b83421fe78d7 100644
--- a/services/core/java/com/android/server/policy/AppOpsPolicy.java
+++ b/services/core/java/com/android/server/policy/AppOpsPolicy.java
@@ -50,12 +50,11 @@ import android.util.Log;
import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.function.HeptFunction;
import com.android.internal.util.function.HexFunction;
-import com.android.internal.util.function.NonaFunction;
import com.android.internal.util.function.QuadFunction;
+import com.android.internal.util.function.QuintConsumer;
import com.android.internal.util.function.QuintFunction;
-import com.android.internal.util.function.TriConsumer;
-import com.android.internal.util.function.TriFunction;
import com.android.internal.util.function.UndecFunction;
import com.android.server.LocalServices;
@@ -230,12 +229,10 @@ public final class AppOpsPolicy implements AppOpsManagerInternal.CheckOpsDelegat
}
@Override
- public int checkOperation(int code, AttributionSource attributionSource, boolean raw,
- TriFunction<Integer, AttributionSource, Boolean, Integer> superImpl) {
- final int uid = attributionSource.getUid();
- final AttributionSource resolvedAttributionSource =
- attributionSource.withUid(resolveUid(code, uid));
- return superImpl.apply(code, resolvedAttributionSource, raw);
+ public int checkOperation(int code, int uid, String packageName,
+ @Nullable String attributionTag, boolean raw,
+ QuintFunction<Integer, Integer, String, String, Boolean, Integer> superImpl) {
+ return superImpl.apply(code, resolveUid(code, uid), packageName, attributionTag, raw);
}
@Override
@@ -245,25 +242,21 @@ public final class AppOpsPolicy implements AppOpsManagerInternal.CheckOpsDelegat
}
@Override
- public SyncNotedAppOp noteOperation(int code, AttributionSource attributionSource,
- boolean shouldCollectAsyncNotedOp, @Nullable
- String message, boolean shouldCollectMessage,
- @NonNull QuintFunction<Integer, AttributionSource, Boolean, String, Boolean,
- SyncNotedAppOp> superImpl) {
- final int uid = attributionSource.getUid();
- final AttributionSource resolvedAttributionSource =
- attributionSource.withUid(resolveUid(code, uid));
- return superImpl.apply(resolveDatasourceOp(code, uid, attributionSource.getPackageName(),
- attributionSource.getAttributionTag()), resolvedAttributionSource,
- shouldCollectAsyncNotedOp, message, shouldCollectMessage);
+ public SyncNotedAppOp noteOperation(int code, int uid, @Nullable String packageName,
+ @Nullable String attributionTag, boolean shouldCollectAsyncNotedOp, @Nullable
+ String message, boolean shouldCollectMessage, @NonNull HeptFunction<Integer, Integer,
+ String, String, Boolean, String, Boolean, SyncNotedAppOp> superImpl) {
+ return superImpl.apply(resolveDatasourceOp(code, uid, packageName, attributionTag),
+ resolveUid(code, uid), packageName, attributionTag, shouldCollectAsyncNotedOp,
+ message, shouldCollectMessage);
}
@Override
public SyncNotedAppOp noteProxyOperation(int code, @NonNull AttributionSource attributionSource,
boolean shouldCollectAsyncNotedOp, @Nullable String message,
boolean shouldCollectMessage, boolean skipProxyOperation, @NonNull HexFunction<Integer,
- AttributionSource, Boolean, String, Boolean, Boolean,
- SyncNotedAppOp> superImpl) {
+ AttributionSource, Boolean, String, Boolean, Boolean,
+ SyncNotedAppOp> superImpl) {
return superImpl.apply(resolveDatasourceOp(code, attributionSource.getUid(),
attributionSource.getPackageName(), attributionSource.getAttributionTag()),
attributionSource, shouldCollectAsyncNotedOp, message, shouldCollectMessage,
@@ -271,21 +264,17 @@ public final class AppOpsPolicy implements AppOpsManagerInternal.CheckOpsDelegat
}
@Override
- public SyncNotedAppOp startOperation(IBinder token, int code,
- AttributionSource attributionSource,
+ public SyncNotedAppOp startOperation(IBinder token, int code, int uid,
+ @Nullable String packageName, @Nullable String attributionTag,
boolean startIfModeDefault, boolean shouldCollectAsyncNotedOp, String message,
boolean shouldCollectMessage, @AttributionFlags int attributionFlags,
- int attributionChainId,
- @NonNull NonaFunction<IBinder, Integer, AttributionSource, Boolean, Boolean, String,
- Boolean, Integer, Integer,
- SyncNotedAppOp> superImpl) {
- final int uid = attributionSource.getUid();
- final AttributionSource resolvedAttributionSource =
- attributionSource.withUid(resolveUid(code, uid));
- return superImpl.apply(token, resolveDatasourceOp(code, uid,
- attributionSource.getPackageName(), attributionSource.getAttributionTag()),
- resolvedAttributionSource, startIfModeDefault, shouldCollectAsyncNotedOp, message,
- shouldCollectMessage, attributionFlags, attributionChainId);
+ int attributionChainId, @NonNull UndecFunction<IBinder, Integer, Integer, String,
+ String, Boolean, Boolean, String, Boolean, Integer, Integer,
+ SyncNotedAppOp> superImpl) {
+ return superImpl.apply(token, resolveDatasourceOp(code, uid, packageName, attributionTag),
+ resolveUid(code, uid), packageName, attributionTag, startIfModeDefault,
+ shouldCollectAsyncNotedOp, message, shouldCollectMessage, attributionFlags,
+ attributionChainId);
}
@Override
@@ -304,14 +293,11 @@ public final class AppOpsPolicy implements AppOpsManagerInternal.CheckOpsDelegat
}
@Override
- public void finishOperation(IBinder clientId, int code, AttributionSource attributionSource,
- @NonNull TriConsumer<IBinder, Integer, AttributionSource> superImpl) {
- final int uid = attributionSource.getUid();
- final AttributionSource resolvedAttributionSource =
- attributionSource.withUid(resolveUid(code, uid));
- superImpl.accept(clientId, resolveDatasourceOp(code, uid,
- attributionSource.getPackageName(), attributionSource.getAttributionTag()),
- resolvedAttributionSource);
+ public void finishOperation(IBinder clientId, int code, int uid, String packageName,
+ String attributionTag,
+ @NonNull QuintConsumer<IBinder, Integer, Integer, String, String> superImpl) {
+ superImpl.accept(clientId, resolveDatasourceOp(code, uid, packageName, attributionTag),
+ resolveUid(code, uid), packageName, attributionTag);
}
@Override
diff --git a/services/core/java/com/android/server/power/stats/CpuPowerStatsCollector.java b/services/core/java/com/android/server/power/stats/CpuPowerStatsCollector.java
index a388932cb708..b8e581f32a58 100644
--- a/services/core/java/com/android/server/power/stats/CpuPowerStatsCollector.java
+++ b/services/core/java/com/android/server/power/stats/CpuPowerStatsCollector.java
@@ -592,6 +592,10 @@ public class CpuPowerStatsCollector extends PowerStatsCollector {
public void dumpCpuPowerBracketsLocked(PrintWriter pw) {
ensureInitialized();
+ if (mLayout == null) {
+ return;
+ }
+
pw.println("CPU power brackets; cluster/freq in MHz(avg current in mA):");
for (int bracket = 0; bracket < mLayout.getCpuPowerBracketCount(); bracket++) {
pw.print(" ");
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index 08af75c10d38..c0bf2ce41435 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -59,6 +59,7 @@ import static android.window.TransitionInfo.FLAG_TRANSLUCENT;
import static android.window.TransitionInfo.FLAG_WILL_IME_SHOWN;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_PENDING_INTENT;
+import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
import static com.android.server.wm.ActivityRecord.State.RESUMED;
import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_RECENTS_ANIM;
import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_SPLASH_SCREEN;
@@ -1272,18 +1273,23 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
}
}
// Commit wallpaper visibility after activity, because usually the wallpaper target token is
- // an activity, and wallpaper's visibility is depends on activity's visibility.
+ // an activity, and wallpaper's visibility depends on activity's visibility.
for (int i = mParticipants.size() - 1; i >= 0; --i) {
final WallpaperWindowToken wt = mParticipants.valueAt(i).asWallpaperToken();
if (wt == null) continue;
final WindowState target = wt.mDisplayContent.mWallpaperController.getWallpaperTarget();
final boolean isTargetInvisible = target == null || !target.mToken.isVisible();
- if (isTargetInvisible || (!wt.isVisibleRequested()
- && !mVisibleAtTransitionEndTokens.contains(wt))) {
+ final boolean isWallpaperVisibleAtEnd =
+ wt.isVisibleRequested() || mVisibleAtTransitionEndTokens.contains(wt);
+ if (isTargetInvisible || !isWallpaperVisibleAtEnd) {
ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS,
" Commit wallpaper becoming invisible: %s", wt);
wt.commitVisibility(false /* visible */);
}
+ if (isTargetInvisible) {
+ // Our original target went invisible, so we should look for a new target.
+ wt.mDisplayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
+ }
}
if (committedSomeInvisible) {
mController.onCommittedInvisibles();
diff --git a/services/core/jni/tvinput/JTvInputHal.cpp b/services/core/jni/tvinput/JTvInputHal.cpp
index dc05462c1a1c..80427b346f1a 100644
--- a/services/core/jni/tvinput/JTvInputHal.cpp
+++ b/services/core/jni/tvinput/JTvInputHal.cpp
@@ -25,7 +25,7 @@ JTvInputHal::JTvInputHal(JNIEnv* env, jobject thiz, std::shared_ptr<ITvInputWrap
mThiz = env->NewWeakGlobalRef(thiz);
mTvInput = tvInput;
mLooper = looper;
- mTvInputCallback = ::ndk::SharedRefBase::make<TvInputCallback>(this);
+ mTvInputCallback = std::shared_ptr<TvInputCallbackWrapper>(new TvInputCallbackWrapper(this));
mTvInput->setCallback(mTvInputCallback);
}
@@ -443,18 +443,23 @@ void JTvInputHal::NotifyTvMessageHandler::handleMessage(const Message& message)
}
}
-JTvInputHal::TvInputCallback::TvInputCallback(JTvInputHal* hal) {
+JTvInputHal::TvInputCallbackWrapper::TvInputCallbackWrapper(JTvInputHal* hal) {
+ aidlTvInputCallback = ::ndk::SharedRefBase::make<AidlTvInputCallback>(hal);
+ hidlTvInputCallback = sp<HidlTvInputCallback>::make(hal);
+}
+
+JTvInputHal::AidlTvInputCallback::AidlTvInputCallback(JTvInputHal* hal) {
mHal = hal;
}
-::ndk::ScopedAStatus JTvInputHal::TvInputCallback::notify(const AidlTvInputEvent& event) {
+::ndk::ScopedAStatus JTvInputHal::AidlTvInputCallback::notify(const AidlTvInputEvent& event) {
mHal->mLooper->sendMessage(new NotifyHandler(mHal,
TvInputEventWrapper::createEventWrapper(event)),
static_cast<int>(event.type));
return ::ndk::ScopedAStatus::ok();
}
-::ndk::ScopedAStatus JTvInputHal::TvInputCallback::notifyTvMessageEvent(
+::ndk::ScopedAStatus JTvInputHal::AidlTvInputCallback::notifyTvMessageEvent(
const AidlTvMessageEvent& event) {
const std::string DEVICE_ID_SUBTYPE = "device_id";
::ndk::ScopedAStatus status = ::ndk::ScopedAStatus::ok();
@@ -487,11 +492,14 @@ JTvInputHal::ITvInputWrapper::ITvInputWrapper(std::shared_ptr<AidlITvInput>& aid
: mIsHidl(false), mAidlTvInput(aidlTvInput) {}
::ndk::ScopedAStatus JTvInputHal::ITvInputWrapper::setCallback(
- const std::shared_ptr<TvInputCallback>& in_callback) {
+ const std::shared_ptr<TvInputCallbackWrapper>& in_callback) {
if (mIsHidl) {
- return hidlSetCallback(in_callback);
+ in_callback->aidlTvInputCallback = nullptr;
+ return hidlSetCallback(in_callback == nullptr ? nullptr : in_callback->hidlTvInputCallback);
} else {
- return mAidlTvInput->setCallback(in_callback);
+ in_callback->hidlTvInputCallback = nullptr;
+ return mAidlTvInput->setCallback(in_callback == nullptr ? nullptr
+ : in_callback->aidlTvInputCallback);
}
}
diff --git a/services/core/jni/tvinput/JTvInputHal.h b/services/core/jni/tvinput/JTvInputHal.h
index 6026a107c67f..2ef94ac4a3b0 100644
--- a/services/core/jni/tvinput/JTvInputHal.h
+++ b/services/core/jni/tvinput/JTvInputHal.h
@@ -168,23 +168,39 @@ private:
JTvInputHal* mHal;
};
- class TvInputCallback : public HidlITvInputCallback, public BnTvInputCallback {
+ class AidlTvInputCallback : public BnTvInputCallback {
public:
- explicit TvInputCallback(JTvInputHal* hal);
+ explicit AidlTvInputCallback(JTvInputHal* hal);
::ndk::ScopedAStatus notify(const AidlTvInputEvent& event) override;
::ndk::ScopedAStatus notifyTvMessageEvent(const AidlTvMessageEvent& event) override;
+
+ private:
+ JTvInputHal* mHal;
+ };
+
+ class HidlTvInputCallback : public HidlITvInputCallback {
+ public:
+ explicit HidlTvInputCallback(JTvInputHal* hal);
Return<void> notify(const HidlTvInputEvent& event) override;
private:
JTvInputHal* mHal;
};
+ class TvInputCallbackWrapper {
+ public:
+ explicit TvInputCallbackWrapper(JTvInputHal* hal);
+ std::shared_ptr<AidlTvInputCallback> aidlTvInputCallback;
+ sp<HidlTvInputCallback> hidlTvInputCallback;
+ };
+
class ITvInputWrapper {
public:
ITvInputWrapper(std::shared_ptr<AidlITvInput>& aidlTvInput);
ITvInputWrapper(sp<HidlITvInput>& hidlTvInput);
- ::ndk::ScopedAStatus setCallback(const std::shared_ptr<TvInputCallback>& in_callback);
+ ::ndk::ScopedAStatus setCallback(
+ const std::shared_ptr<TvInputCallbackWrapper>& in_callback);
::ndk::ScopedAStatus getStreamConfigurations(int32_t in_deviceId,
std::vector<AidlTvStreamConfig>* _aidl_return);
::ndk::ScopedAStatus openStream(int32_t in_deviceId, int32_t in_streamId,
@@ -198,7 +214,7 @@ private:
::ndk::ScopedAStatus getAidlInterfaceVersion(int32_t* _aidl_return);
private:
- ::ndk::ScopedAStatus hidlSetCallback(const std::shared_ptr<TvInputCallback>& in_callback);
+ ::ndk::ScopedAStatus hidlSetCallback(const sp<HidlTvInputCallback>& in_callback);
::ndk::ScopedAStatus hidlGetStreamConfigurations(
int32_t in_deviceId, std::vector<AidlTvStreamConfig>* _aidl_return);
::ndk::ScopedAStatus hidlOpenStream(int32_t in_deviceId, int32_t in_streamId,
@@ -229,7 +245,7 @@ private:
KeyedVector<int, KeyedVector<int, Connection> > mConnections;
std::shared_ptr<ITvInputWrapper> mTvInput;
- std::shared_ptr<TvInputCallback> mTvInputCallback;
+ std::shared_ptr<TvInputCallbackWrapper> mTvInputCallback;
};
} // namespace android
diff --git a/services/core/jni/tvinput/TvInputHal_hidl.cpp b/services/core/jni/tvinput/TvInputHal_hidl.cpp
index 37cf8445920f..cdd926622dcc 100644
--- a/services/core/jni/tvinput/TvInputHal_hidl.cpp
+++ b/services/core/jni/tvinput/TvInputHal_hidl.cpp
@@ -59,7 +59,11 @@ JTvInputHal::TvInputEventWrapper JTvInputHal::TvInputEventWrapper::createEventWr
return event;
}
-Return<void> JTvInputHal::TvInputCallback::notify(const HidlTvInputEvent& event) {
+JTvInputHal::HidlTvInputCallback::HidlTvInputCallback(JTvInputHal* hal) {
+ mHal = hal;
+}
+
+Return<void> JTvInputHal::HidlTvInputCallback::notify(const HidlTvInputEvent& event) {
mHal->mLooper->sendMessage(new NotifyHandler(mHal,
TvInputEventWrapper::createEventWrapper(event)),
static_cast<int>(event.type));
@@ -70,9 +74,8 @@ JTvInputHal::ITvInputWrapper::ITvInputWrapper(sp<HidlITvInput>& hidlTvInput)
: mIsHidl(true), mHidlTvInput(hidlTvInput) {}
::ndk::ScopedAStatus JTvInputHal::ITvInputWrapper::hidlSetCallback(
- const std::shared_ptr<TvInputCallback>& in_callback) {
- mHidlTvInput->setCallback(in_callback == nullptr ? nullptr
- : sp<TvInputCallback>(in_callback.get()));
+ const sp<HidlTvInputCallback>& in_callback) {
+ mHidlTvInput->setCallback(in_callback);
return ::ndk::ScopedAStatus::ok();
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/AppStateTrackerTest.java b/services/tests/mockingservicestests/src/com/android/server/AppStateTrackerTest.java
index 7ceccc57c0f1..47ae97fc5d27 100644
--- a/services/tests/mockingservicestests/src/com/android/server/AppStateTrackerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/AppStateTrackerTest.java
@@ -44,7 +44,6 @@ import android.app.AppOpsManager.PackageOps;
import android.app.IActivityManager;
import android.app.IUidObserver;
import android.app.usage.UsageStatsManager;
-import android.content.AttributionSourceState;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -230,20 +229,12 @@ public class AppStateTrackerTest {
private AppStateTrackerTestable newInstance() throws Exception {
MockitoAnnotations.initMocks(this);
- when(mMockIAppOpsService.checkOperationWithState(eq(TARGET_OP), any()))
- .thenAnswer(
- (Answer<Integer>)
- invocation -> {
- AttributionSourceState attribution =
- (AttributionSourceState) invocation.getArguments()[1];
- return mRestrictedPackages.indexOf(
- Pair.create(
- attribution.uid,
- attribution.packageName))
- >= 0
- ? AppOpsManager.MODE_IGNORED
- : AppOpsManager.MODE_ALLOWED;
- });
+ when(mMockIAppOpsService.checkOperation(eq(TARGET_OP), anyInt(), anyString()))
+ .thenAnswer(inv -> {
+ return mRestrictedPackages.indexOf(
+ Pair.create(inv.getArgument(1), inv.getArgument(2))) >= 0 ?
+ AppOpsManager.MODE_IGNORED : AppOpsManager.MODE_ALLOWED;
+ });
final AppStateTrackerTestable instance = new AppStateTrackerTestable();
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/ActivityManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/am/ActivityManagerServiceTest.java
index 032d026648df..2f909f818bfe 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/ActivityManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/ActivityManagerServiceTest.java
@@ -69,7 +69,6 @@ import android.app.BroadcastOptions;
import android.app.IApplicationThread;
import android.app.IUidObserver;
import android.app.SyncNotedAppOp;
-import android.content.AttributionSourceState;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -234,16 +233,12 @@ public class ActivityManagerServiceTest {
assertThat(sProcessListSettingsListener).isNotNull();
}
- private void mockNoteOp() {
+ private void mockNoteOperation() {
SyncNotedAppOp allowed = new SyncNotedAppOp(AppOpsManager.MODE_ALLOWED,
AppOpsManager.OP_GET_USAGE_STATS, null, mContext.getPackageName());
- when(mAppOpsService.noteOperationWithState(
- eq(AppOpsManager.OP_GET_USAGE_STATS),
- any(AttributionSourceState.class),
- any(Boolean.class),
- nullable(String.class),
- any(Boolean.class)))
- .thenReturn(allowed);
+ when(mAppOpsService.noteOperation(eq(AppOpsManager.OP_GET_USAGE_STATS), eq(Process.myUid()),
+ nullable(String.class), nullable(String.class), any(Boolean.class),
+ nullable(String.class), any(Boolean.class))).thenReturn(allowed);
}
@After
@@ -696,7 +691,7 @@ public class ActivityManagerServiceTest {
*/
@Test
public void testDispatchUids_dispatchNeededChanges() throws RemoteException {
- mockNoteOp();
+ mockNoteOperation();
final int[] changesToObserve = {
ActivityManager.UID_OBSERVER_PROCSTATE,
@@ -905,7 +900,7 @@ public class ActivityManagerServiceTest {
*/
@Test
public void testDispatchUidChanges_procStateCutpoint() throws RemoteException {
- mockNoteOp();
+ mockNoteOperation();
final IUidObserver observer = mock(IUidObserver.Stub.class);
@@ -975,7 +970,7 @@ public class ActivityManagerServiceTest {
*/
@Test
public void testDispatchUidChanges_validateUidsUpdated() {
- mockNoteOp();
+ mockNoteOperation();
final int[] changesForPendingItems = UID_RECORD_CHANGES;
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/BackgroundRestrictionTest.java b/services/tests/mockingservicestests/src/com/android/server/am/BackgroundRestrictionTest.java
index dcbee83b839b..bb91939c430e 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/BackgroundRestrictionTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/BackgroundRestrictionTest.java
@@ -113,8 +113,6 @@ import android.app.Notification;
import android.app.NotificationManager;
import android.app.role.RoleManager;
import android.app.usage.AppStandbyInfo;
-import android.content.AttributionSource;
-import android.content.AttributionSourceState;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
@@ -2456,12 +2454,9 @@ public final class BackgroundRestrictionTest {
doReturn(granted ? MODE_ALLOWED : MODE_IGNORED)
.when(mAppOpsManager)
.checkOpNoThrow(op, uid, packageName);
- AttributionSource attributionSource =
- new AttributionSource.Builder(uid).setPackageName(packageName).build();
- AttributionSourceState attributionSourceState = attributionSource.asState();
doReturn(granted ? MODE_ALLOWED : MODE_IGNORED)
.when(mIAppOpsService)
- .checkOperationWithState(eq(op), eq(attributionSourceState));
+ .checkOperation(op, uid, packageName);
} catch (RemoteException e) {
// Ignore.
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java
index daed5df4edd7..646f4862d75d 100644
--- a/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java
@@ -49,7 +49,6 @@ import static org.mockito.ArgumentMatchers.nullable;
import android.app.AppOpsManager;
import android.app.AppOpsManager.OpEntry;
import android.app.AppOpsManager.PackageOps;
-import android.content.AttributionSource;
import android.content.ContentResolver;
import android.content.Context;
import android.content.pm.PackageManagerInternal;
@@ -217,21 +216,18 @@ public class AppOpsServiceTest {
}
@Test
- public void testNoteOpAndGetOpsForPackage() {
+ public void testNoteOperationAndGetOpsForPackage() {
mAppOpsService.setMode(OP_READ_SMS, mMyUid, sMyPackageName, MODE_ALLOWED);
mAppOpsService.setMode(OP_WRITE_SMS, mMyUid, sMyPackageName, MODE_ERRORED);
- AttributionSource attributionSource =
- new AttributionSource.Builder(mMyUid).setPackageName(sMyPackageName).build();
// Note an op that's allowed.
- mAppOpsService.noteOperationWithState(OP_READ_SMS, attributionSource.asState(), false,
- null, false);
+ mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, sMyPackageName, null, false, null, false);
List<PackageOps> loggedOps = getLoggedOps();
assertContainsOp(loggedOps, OP_READ_SMS, mTestStartMillis, -1, MODE_ALLOWED);
// Note another op that's not allowed.
- mAppOpsService.noteOperationWithState(OP_WRITE_SMS, attributionSource.asState(), false,
- null, false);
+ mAppOpsService.noteOperation(OP_WRITE_SMS, mMyUid, sMyPackageName, null, false, null,
+ false);
loggedOps = getLoggedOps();
assertContainsOp(loggedOps, OP_READ_SMS, mTestStartMillis, -1, MODE_ALLOWED);
assertContainsOp(loggedOps, OP_WRITE_SMS, -1, mTestStartMillis, MODE_ERRORED);
@@ -243,24 +239,20 @@ public class AppOpsServiceTest {
* ACCESS_COARSE_LOCATION op is used to check whether WIFI_SCAN is allowed.
*/
@Test
- public void testNoteOpAndGetOpsForPackage_controlledByDifferentOp() {
+ public void testNoteOperationAndGetOpsForPackage_controlledByDifferentOp() {
// This op controls WIFI_SCAN
mAppOpsService.setMode(OP_COARSE_LOCATION, mMyUid, sMyPackageName, MODE_ALLOWED);
- assertThat(mAppOpsService.noteOperationWithState(OP_WIFI_SCAN,
- new AttributionSource.Builder(mMyUid).setPackageName(sMyPackageName)
- .build().asState(), false, null, false).getOpMode())
- .isEqualTo(MODE_ALLOWED);
+ assertThat(mAppOpsService.noteOperation(OP_WIFI_SCAN, mMyUid, sMyPackageName, null, false,
+ null, false).getOpMode()).isEqualTo(MODE_ALLOWED);
assertContainsOp(getLoggedOps(), OP_WIFI_SCAN, mTestStartMillis, -1,
MODE_ALLOWED /* default for WIFI_SCAN; this is not changed or used in this test */);
// Now set COARSE_LOCATION to ERRORED -> this will make WIFI_SCAN disabled as well.
mAppOpsService.setMode(OP_COARSE_LOCATION, mMyUid, sMyPackageName, MODE_ERRORED);
- assertThat(mAppOpsService.noteOperationWithState(OP_WIFI_SCAN,
- new AttributionSource.Builder(mMyUid).setPackageName(sMyPackageName)
- .build().asState(), false, null, false)
- .getOpMode()).isEqualTo(MODE_ERRORED);
+ assertThat(mAppOpsService.noteOperation(OP_WIFI_SCAN, mMyUid, sMyPackageName, null, false,
+ null, false).getOpMode()).isEqualTo(MODE_ERRORED);
assertContainsOp(getLoggedOps(), OP_WIFI_SCAN, mTestStartMillis, mTestStartMillis,
MODE_ALLOWED /* default for WIFI_SCAN; this is not changed or used in this test */);
@@ -271,12 +263,9 @@ public class AppOpsServiceTest {
public void testStatePersistence() {
mAppOpsService.setMode(OP_READ_SMS, mMyUid, sMyPackageName, MODE_ALLOWED);
mAppOpsService.setMode(OP_WRITE_SMS, mMyUid, sMyPackageName, MODE_ERRORED);
- AttributionSource attributionSource =
- new AttributionSource.Builder(mMyUid).setPackageName(sMyPackageName).build();
- mAppOpsService.noteOperationWithState(OP_READ_SMS, attributionSource.asState(), false,
- null, false);
- mAppOpsService.noteOperationWithState(OP_WRITE_SMS, attributionSource.asState(), false,
- null, false);
+ mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, sMyPackageName, null, false, null, false);
+ mAppOpsService.noteOperation(OP_WRITE_SMS, mMyUid, sMyPackageName, null, false, null,
+ false);
mAppOpsService.shutdown();
@@ -294,10 +283,7 @@ public class AppOpsServiceTest {
@Test
public void testShutdown() {
mAppOpsService.setMode(OP_READ_SMS, mMyUid, sMyPackageName, MODE_ALLOWED);
- AttributionSource attributionSource =
- new AttributionSource.Builder(mMyUid).setPackageName(sMyPackageName).build();
- mAppOpsService.noteOperationWithState(OP_READ_SMS, attributionSource.asState(), false,
- null, false);
+ mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, sMyPackageName, null, false, null, false);
mAppOpsService.shutdown();
// Create a new app ops service which will initialize its state from XML.
@@ -311,10 +297,7 @@ public class AppOpsServiceTest {
@Test
public void testGetOpsForPackage() {
mAppOpsService.setMode(OP_READ_SMS, mMyUid, sMyPackageName, MODE_ALLOWED);
- AttributionSource attributionSource =
- new AttributionSource.Builder(mMyUid).setPackageName(sMyPackageName).build();
- mAppOpsService.noteOperationWithState(OP_READ_SMS, attributionSource.asState(), false,
- null, false);
+ mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, sMyPackageName, null, false, null, false);
// Query all ops
List<PackageOps> loggedOps = mAppOpsService.getOpsForPackage(
@@ -343,10 +326,7 @@ public class AppOpsServiceTest {
@Test
public void testPackageRemoved() {
mAppOpsService.setMode(OP_READ_SMS, mMyUid, sMyPackageName, MODE_ALLOWED);
- AttributionSource attributionSource =
- new AttributionSource.Builder(mMyUid).setPackageName(sMyPackageName).build();
- mAppOpsService.noteOperationWithState(OP_READ_SMS, attributionSource.asState(), false,
- null, false);
+ mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, sMyPackageName, null, false, null, false);
List<PackageOps> loggedOps = getLoggedOps();
assertContainsOp(loggedOps, OP_READ_SMS, mTestStartMillis, -1, MODE_ALLOWED);
@@ -361,8 +341,7 @@ public class AppOpsServiceTest {
@Test
public void testPackageRemovedHistoricalOps() throws InterruptedException {
mAppOpsService.setMode(OP_READ_SMS, mMyUid, sMyPackageName, MODE_ALLOWED);
- mAppOpsService.noteOperationWithState(OP_READ_SMS, mMyUid, sMyPackageName, null, false,
- null, false);
+ mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, sMyPackageName, null, false, null, false);
AppOpsManager.HistoricalOps historicalOps = new AppOpsManager.HistoricalOps(0, 15000);
historicalOps.increaseAccessCount(OP_READ_SMS, mMyUid, sMyPackageName, null,
@@ -402,10 +381,7 @@ public class AppOpsServiceTest {
@Test
public void testUidRemoved() {
mAppOpsService.setMode(OP_READ_SMS, mMyUid, sMyPackageName, MODE_ALLOWED);
- AttributionSource attributionSource =
- new AttributionSource.Builder(mMyUid).setPackageName(sMyPackageName).build();
- mAppOpsService.noteOperationWithState(OP_READ_SMS, attributionSource.asState(),
- false, null, false);
+ mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, sMyPackageName, null, false, null, false);
List<PackageOps> loggedOps = getLoggedOps();
assertContainsOp(loggedOps, OP_READ_SMS, mTestStartMillis, -1, MODE_ALLOWED);
@@ -417,10 +393,7 @@ public class AppOpsServiceTest {
@Test
public void testUidStateInitializationDoesntClearState() throws InterruptedException {
mAppOpsService.setMode(OP_READ_SMS, mMyUid, sMyPackageName, MODE_ALLOWED);
- AttributionSource attributionSource =
- new AttributionSource.Builder(mMyUid).setPackageName(sMyPackageName).build();
- mAppOpsService.noteOperationWithState(OP_READ_SMS, attributionSource.asState(), false,
- null, false);
+ mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, sMyPackageName, null, false, null, false);
mAppOpsService.initializeUidStates();
List<PackageOps> ops = mAppOpsService.getOpsForPackage(mMyUid, sMyPackageName,
new int[]{OP_READ_SMS});
diff --git a/services/tests/servicestests/src/com/android/server/pdb/PersistentDataBlockServiceTest.java b/services/tests/servicestests/src/com/android/server/pdb/PersistentDataBlockServiceTest.java
new file mode 100644
index 000000000000..f537efd9736d
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/pdb/PersistentDataBlockServiceTest.java
@@ -0,0 +1,552 @@
+/*
+ * Copyright (C) 2023 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.pdb;
+
+import static com.android.server.pdb.PersistentDataBlockService.DIGEST_SIZE_BYTES;
+import static com.android.server.pdb.PersistentDataBlockService.MAX_DATA_BLOCK_SIZE;
+import static com.android.server.pdb.PersistentDataBlockService.MAX_FRP_CREDENTIAL_HANDLE_SIZE;
+import static com.android.server.pdb.PersistentDataBlockService.MAX_TEST_MODE_DATA_SIZE;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+import static org.junit.Assert.assertThrows;
+
+import android.Manifest;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.os.Binder;
+import android.os.RemoteException;
+import android.os.UserManager;
+import android.service.persistentdata.IPersistentDataBlockService;
+
+import androidx.test.core.app.ApplicationProvider;
+
+import junitparams.JUnitParamsRunner;
+import junitparams.Parameters;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.io.File;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+import java.nio.file.StandardOpenOption;
+
+@RunWith(JUnitParamsRunner.class)
+public class PersistentDataBlockServiceTest {
+ private static final String TAG = "PersistentDataBlockServiceTest";
+
+ private static final byte[] SMALL_DATA = "data to write".getBytes();
+ private static final byte[] ANOTHER_SMALL_DATA = "something else".getBytes();
+
+ private Context mContext;
+ private PersistentDataBlockService mPdbService;
+ private IPersistentDataBlockService mInterface;
+ private PersistentDataBlockManagerInternal mInternalInterface;
+ private File mDataBlockFile;
+ private String mOemUnlockPropertyValue;
+
+ @Mock private UserManager mUserManager;
+
+ private class FakePersistentDataBlockService extends PersistentDataBlockService {
+ FakePersistentDataBlockService(Context context, String dataBlockFile,
+ long blockDeviceSize) {
+ super(context, /* isFileBacked */ true, dataBlockFile, blockDeviceSize);
+ }
+
+ @Override
+ void setProperty(String key, String value) {
+ // Override to capture the value instead of actually setting the property.
+ assertThat(key).isEqualTo("sys.oem_unlock_allowed");
+ mOemUnlockPropertyValue = value;
+ }
+ }
+
+ @Rule public TemporaryFolder mTemporaryFolder = new TemporaryFolder();
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+
+ mDataBlockFile = mTemporaryFolder.newFile();
+ mContext = spy(ApplicationProvider.getApplicationContext());
+ mPdbService = new FakePersistentDataBlockService(mContext, mDataBlockFile.getPath(),
+ /* blockDeviceSize */ -1);
+ mPdbService.setAllowedUid(Binder.getCallingUid());
+ mPdbService.formatPartitionLocked(/* setOemUnlockEnabled */ false);
+ mInterface = mPdbService.getInterfaceForTesting();
+ mInternalInterface = mPdbService.getInternalInterfaceForTesting();
+
+ when(mContext.getSystemService(eq(Context.USER_SERVICE))).thenReturn(mUserManager);
+ when(mContext.getSystemService(UserManager.class)).thenReturn(mUserManager);
+ }
+
+ abstract static class Block {
+ public PersistentDataBlockService service;
+
+ abstract int write(byte[] data) throws RemoteException;
+ abstract byte[] read() throws RemoteException;
+ }
+
+ /**
+ * Configuration for parameterizing tests, including the block name, maximum block size, and
+ * a block implementation for the read/write operations.
+ */
+ public Object[][] getTestParametersForBlocks() {
+ return new Object[][] {
+ {
+ new Block() {
+ @Override public int write(byte[] data) throws RemoteException {
+ return service.getInterfaceForTesting().write(data);
+ }
+
+ @Override public byte[] read() throws RemoteException {
+ return service.getInterfaceForTesting().read();
+ }
+ },
+ },
+ {
+ new Block() {
+ @Override public int write(byte[] data) {
+ service.getInternalInterfaceForTesting().setFrpCredentialHandle(data);
+ // The written size isn't returned. Pretend it's fully written in the
+ // test for now.
+ return data.length;
+ }
+
+ @Override public byte[] read() {
+ return service.getInternalInterfaceForTesting().getFrpCredentialHandle();
+ }
+ },
+ },
+ {
+ new Block() {
+ @Override public int write(byte[] data) {
+ service.getInternalInterfaceForTesting().setTestHarnessModeData(data);
+ // The written size isn't returned. Pretend it's fully written in the
+ // test for now.
+ return data.length;
+ }
+
+ @Override public byte[] read() {
+ return service.getInternalInterfaceForTesting().getTestHarnessModeData();
+ }
+ },
+ },
+ };
+ }
+
+ @Test
+ @Parameters(method = "getTestParametersForBlocks")
+ public void writeThenRead(Block block) throws Exception {
+ block.service = mPdbService;
+ assertThat(block.write(SMALL_DATA)).isEqualTo(SMALL_DATA.length);
+ assertThat(block.read()).isEqualTo(SMALL_DATA);
+ }
+
+ @Test
+ @Parameters(method = "getTestParametersForBlocks")
+ public void writeWhileAlreadyCorrupted(Block block) throws Exception {
+ block.service = mPdbService;
+ assertThat(block.write(SMALL_DATA)).isEqualTo(SMALL_DATA.length);
+ assertThat(block.read()).isEqualTo(SMALL_DATA);
+
+ tamperWithDigest();
+
+ // In the currently implementation, expect the write to not trigger formatting.
+ assertThat(block.write(ANOTHER_SMALL_DATA)).isEqualTo(ANOTHER_SMALL_DATA.length);
+ }
+
+ @Test
+ public void frpWriteOutOfBound() throws Exception {
+ byte[] maxData = new byte[mPdbService.getMaximumFrpDataSize()];
+ assertThat(mInterface.write(maxData)).isEqualTo(maxData.length);
+
+ byte[] overflowData = new byte[mPdbService.getMaximumFrpDataSize() + 1];
+ assertThat(mInterface.write(overflowData)).isLessThan(0);
+ }
+
+ @Test
+ public void frpCredentialWriteOutOfBound() throws Exception {
+ byte[] maxData = new byte[MAX_FRP_CREDENTIAL_HANDLE_SIZE];
+ mInternalInterface.setFrpCredentialHandle(maxData);
+
+ byte[] overflowData = new byte[MAX_FRP_CREDENTIAL_HANDLE_SIZE + 1];
+ assertThrows(IllegalArgumentException.class, () ->
+ mInternalInterface.setFrpCredentialHandle(overflowData));
+ }
+
+ @Test
+ public void testHardnessWriteOutOfBound() throws Exception {
+ byte[] maxData = new byte[MAX_TEST_MODE_DATA_SIZE];
+ mInternalInterface.setTestHarnessModeData(maxData);
+
+ byte[] overflowData = new byte[MAX_TEST_MODE_DATA_SIZE + 1];
+ assertThrows(IllegalArgumentException.class, () ->
+ mInternalInterface.setTestHarnessModeData(overflowData));
+ }
+
+ @Test
+ public void readCorruptedFrpData() throws Exception {
+ assertThat(mInterface.write(SMALL_DATA)).isEqualTo(SMALL_DATA.length);
+ assertThat(mInterface.read()).isEqualTo(SMALL_DATA);
+
+ tamperWithDigest();
+
+ // Expect the read to trigger formatting, resulting in reading empty data.
+ assertThat(mInterface.read()).hasLength(0);
+ }
+
+ @Test
+ public void readCorruptedFrpCredentialData() throws Exception {
+ mInternalInterface.setFrpCredentialHandle(SMALL_DATA);
+ assertThat(mInternalInterface.getFrpCredentialHandle()).isEqualTo(SMALL_DATA);
+
+ tamperWithDigest();
+
+ assertThrows(IllegalStateException.class, () ->
+ mInternalInterface.getFrpCredentialHandle());
+ }
+
+ @Test
+ public void readCorruptedTestHarnessData() throws Exception {
+ mInternalInterface.setTestHarnessModeData(SMALL_DATA);
+ assertThat(mInternalInterface.getTestHarnessModeData()).isEqualTo(SMALL_DATA);
+
+ tamperWithDigest();
+
+ assertThrows(IllegalStateException.class, () ->
+ mInternalInterface.getTestHarnessModeData());
+ }
+
+ @Test
+ public void nullWrite() throws Exception {
+ assertThrows(NullPointerException.class, () -> mInterface.write(null));
+ mInternalInterface.setFrpCredentialHandle(null); // no exception
+ mInternalInterface.setTestHarnessModeData(null); // no exception
+ }
+
+ @Test
+ public void emptyDataWrite() throws Exception {
+ var empty = new byte[0];
+ assertThat(mInterface.write(empty)).isEqualTo(0);
+
+ assertThrows(IllegalArgumentException.class, () ->
+ mInternalInterface.setFrpCredentialHandle(empty));
+ assertThrows(IllegalArgumentException.class, () ->
+ mInternalInterface.setTestHarnessModeData(empty));
+ }
+
+ @Test
+ public void frpWriteMoreThan100K() throws Exception {
+ File dataBlockFile = mTemporaryFolder.newFile();
+ PersistentDataBlockService pdbService = new FakePersistentDataBlockService(mContext,
+ dataBlockFile.getPath(), /* blockDeviceSize */ 128 * 1000);
+ pdbService.setAllowedUid(Binder.getCallingUid());
+ pdbService.formatPartitionLocked(/* setOemUnlockEnabled */ false);
+
+ IPersistentDataBlockService service = pdbService.getInterfaceForTesting();
+ int maxDataSize = (int) service.getMaximumDataBlockSize();
+ assertThat(service.write(new byte[maxDataSize])).isEqualTo(maxDataSize);
+ assertThat(service.write(new byte[maxDataSize + 1])).isEqualTo(-MAX_DATA_BLOCK_SIZE);
+ }
+
+ @Test
+ public void frpBlockReadWriteWithoutPermission() throws Exception {
+ mPdbService.setAllowedUid(Binder.getCallingUid() + 1); // unexpected uid
+ assertThrows(SecurityException.class, () -> mInterface.write(SMALL_DATA));
+ assertThrows(SecurityException.class, () -> mInterface.read());
+ }
+
+ @Test
+ public void getMaximumDataBlockSizeDenied() throws Exception {
+ mPdbService.setAllowedUid(Binder.getCallingUid() + 1); // unexpected uid
+ assertThrows(SecurityException.class, () -> mInterface.getMaximumDataBlockSize());
+ }
+
+ @Test
+ public void getMaximumDataBlockSize() throws Exception {
+ mPdbService.setAllowedUid(Binder.getCallingUid());
+ assertThat(mInterface.getMaximumDataBlockSize())
+ .isEqualTo(mPdbService.getMaximumFrpDataSize());
+ }
+
+ @Test
+ public void getMaximumDataBlockSizeOfLargerPartition() throws Exception {
+ File dataBlockFile = mTemporaryFolder.newFile();
+ PersistentDataBlockService pdbService = new FakePersistentDataBlockService(mContext,
+ dataBlockFile.getPath(), /* blockDeviceSize */ 128 * 1000);
+ pdbService.setAllowedUid(Binder.getCallingUid());
+ pdbService.formatPartitionLocked(/* setOemUnlockEnabled */ false);
+
+ IPersistentDataBlockService service = pdbService.getInterfaceForTesting();
+ assertThat(service.getMaximumDataBlockSize()).isEqualTo(MAX_DATA_BLOCK_SIZE);
+ }
+
+ @Test
+ public void getFrpDataBlockSizeGrantedByUid() throws Exception {
+ assertThat(mInterface.write(SMALL_DATA)).isEqualTo(SMALL_DATA.length);
+
+ mPdbService.setAllowedUid(Binder.getCallingUid());
+ assertThat(mInterface.getDataBlockSize()).isEqualTo(SMALL_DATA.length);
+
+ // Modify the magic / type marker. In the current implementation, getting the FRP data block
+ // size does not check digest.
+ tamperWithMagic();
+ assertThat(mInterface.getDataBlockSize()).isEqualTo(0);
+ }
+
+ @Test
+ public void getFrpDataBlockSizeGrantedByPermission() throws Exception {
+ assertThat(mInterface.write(SMALL_DATA)).isEqualTo(SMALL_DATA.length);
+
+ mPdbService.setAllowedUid(Binder.getCallingUid() + 1); // unexpected uid
+ grantAccessPdbStatePermission();
+
+ assertThat(mInterface.getDataBlockSize()).isEqualTo(SMALL_DATA.length);
+
+ // Modify the magic / type marker. In the current implementation, getting the FRP data block
+ // size does not check digest.
+ tamperWithMagic();
+ assertThat(mInterface.getDataBlockSize()).isEqualTo(0);
+ }
+
+ @Test
+ public void wipePermissionCheck() throws Exception {
+ denyOemUnlockPermission();
+ assertThrows(SecurityException.class, () -> mInterface.wipe());
+ }
+
+ @Test
+ public void wipeMakesItNotWritable() throws Exception {
+ grantOemUnlockPermission();
+ mInterface.wipe();
+
+ // Verify that nothing is written.
+ final int headerAndDataBytes = 4 + SMALL_DATA.length;
+ assertThat(mInterface.write(SMALL_DATA)).isLessThan(0);
+ assertThat(readBackingFile(DIGEST_SIZE_BYTES + 4, headerAndDataBytes).array())
+ .isEqualTo(new byte[headerAndDataBytes]);
+
+ mInternalInterface.setFrpCredentialHandle(SMALL_DATA);
+ assertThat(readBackingFile(mPdbService.getFrpCredentialDataOffset() + 4,
+ headerAndDataBytes)
+ .array())
+ .isEqualTo(new byte[headerAndDataBytes]);
+
+ mInternalInterface.setTestHarnessModeData(SMALL_DATA);
+ assertThat(readBackingFile(mPdbService.getTestHarnessModeDataOffset() + 4,
+ headerAndDataBytes)
+ .array())
+ .isEqualTo(new byte[headerAndDataBytes]);
+ }
+
+ @Test
+ public void hasFrpCredentialHandleGrantedByUid() throws Exception {
+ mPdbService.setAllowedUid(Binder.getCallingUid());
+
+ assertThat(mInterface.hasFrpCredentialHandle()).isFalse();
+ mInternalInterface.setFrpCredentialHandle(SMALL_DATA);
+ assertThat(mInterface.hasFrpCredentialHandle()).isTrue();
+ }
+
+ @Test
+ public void hasFrpCredentialHandleGrantedByPermission() throws Exception {
+ mPdbService.setAllowedUid(Binder.getCallingUid() + 1); // unexpected uid
+ grantAccessPdbStatePermission();
+
+ assertThat(mInterface.hasFrpCredentialHandle()).isFalse();
+ mInternalInterface.setFrpCredentialHandle(SMALL_DATA);
+ assertThat(mInterface.hasFrpCredentialHandle()).isTrue();
+ }
+
+ @Test
+ public void clearTestHarnessModeData() throws Exception {
+ mInternalInterface.setTestHarnessModeData(SMALL_DATA);
+ mInternalInterface.clearTestHarnessModeData();
+
+ assertThat(readBackingFile(mPdbService.getTestHarnessModeDataOffset(),
+ MAX_TEST_MODE_DATA_SIZE).array())
+ .isEqualTo(new byte[MAX_TEST_MODE_DATA_SIZE]);
+ }
+
+ @Test
+ public void getAllowedUid() throws Exception {
+ assertThat(mInternalInterface.getAllowedUid()).isEqualTo(Binder.getCallingUid());
+ }
+
+ @Test
+ public void oemUnlockWithoutPermission() throws Exception {
+ denyOemUnlockPermission();
+
+ assertThrows(SecurityException.class, () -> mInterface.setOemUnlockEnabled(true));
+ }
+
+ @Test
+ public void oemUnlockNotAdmin() throws Exception {
+ grantOemUnlockPermission();
+ makeUserAdmin(false);
+
+ assertThrows(SecurityException.class, () -> mInterface.setOemUnlockEnabled(true));
+ }
+
+ @Test
+ public void oemUnlock() throws Exception {
+ grantOemUnlockPermission();
+ makeUserAdmin(true);
+
+ mInterface.setOemUnlockEnabled(true);
+ assertThat(mInterface.getOemUnlockEnabled()).isTrue();
+ assertThat(mOemUnlockPropertyValue).isEqualTo("1");
+ }
+
+ @Test
+ public void oemUnlockUserRestriction_OemUnlock() throws Exception {
+ grantOemUnlockPermission();
+ makeUserAdmin(true);
+ when(mUserManager.hasUserRestriction(eq(UserManager.DISALLOW_OEM_UNLOCK)))
+ .thenReturn(true);
+
+ assertThrows(SecurityException.class, () -> mInterface.setOemUnlockEnabled(true));
+ }
+
+ @Test
+ public void oemUnlockUserRestriction_FactoryReset() throws Exception {
+ grantOemUnlockPermission();
+ makeUserAdmin(true);
+ when(mUserManager.hasUserRestriction(eq(UserManager.DISALLOW_FACTORY_RESET)))
+ .thenReturn(true);
+
+ assertThrows(SecurityException.class, () -> mInterface.setOemUnlockEnabled(true));
+ }
+
+ @Test
+ public void oemUnlockIgnoreTampering() throws Exception {
+ grantOemUnlockPermission();
+ makeUserAdmin(true);
+
+ // The current implementation does not check digest before set or get the oem unlock bit.
+ tamperWithDigest();
+ mInterface.setOemUnlockEnabled(true);
+ assertThat(mOemUnlockPropertyValue).isEqualTo("1");
+ tamperWithDigest();
+ assertThat(mInterface.getOemUnlockEnabled()).isTrue();
+ }
+
+ @Test
+ public void getOemUnlockEnabledPermissionCheck_NoPermission() throws Exception {
+ assertThrows(SecurityException.class, () -> mInterface.getOemUnlockEnabled());
+ }
+
+ @Test
+ public void getOemUnlockEnabledPermissionCheck_OemUnlcokState() throws Exception {
+ doReturn(PackageManager.PERMISSION_GRANTED).when(mContext)
+ .checkCallingOrSelfPermission(eq(Manifest.permission.OEM_UNLOCK_STATE));
+ assertThat(mInterface.getOemUnlockEnabled()).isFalse();
+ }
+
+ @Test
+ public void getOemUnlockEnabledPermissionCheck_ReadOemUnlcokState() throws Exception {
+ doReturn(PackageManager.PERMISSION_GRANTED).when(mContext)
+ .checkCallingOrSelfPermission(eq(Manifest.permission.READ_OEM_UNLOCK_STATE));
+ assertThat(mInterface.getOemUnlockEnabled()).isFalse();
+ }
+
+ @Test
+ public void forceOemUnlock_RequiresNoPermission() throws Exception {
+ denyOemUnlockPermission();
+
+ mInternalInterface.forceOemUnlockEnabled(true);
+
+ assertThat(mOemUnlockPropertyValue).isEqualTo("1");
+ assertThat(readBackingFile(mPdbService.getOemUnlockDataOffset(), 1).array())
+ .isEqualTo(new byte[] { 1 });
+ }
+
+ @Test
+ public void getFlashLockStatePermissionCheck_NoPermission() throws Exception {
+ assertThrows(SecurityException.class, () -> mInterface.getFlashLockState());
+ }
+
+ @Test
+ public void getFlashLockStatePermissionCheck_OemUnlcokState() throws Exception {
+ doReturn(PackageManager.PERMISSION_GRANTED).when(mContext)
+ .checkCallingOrSelfPermission(eq(Manifest.permission.OEM_UNLOCK_STATE));
+ mInterface.getFlashLockState(); // Do not throw
+ }
+
+ @Test
+ public void getFlashLockStatePermissionCheck_ReadOemUnlcokState() throws Exception {
+ doReturn(PackageManager.PERMISSION_GRANTED).when(mContext)
+ .checkCallingOrSelfPermission(eq(Manifest.permission.READ_OEM_UNLOCK_STATE));
+ mInterface.getFlashLockState(); // Do not throw
+ }
+
+ private void tamperWithDigest() throws Exception {
+ try (var ch = FileChannel.open(mDataBlockFile.toPath(), StandardOpenOption.WRITE)) {
+ ch.write(ByteBuffer.wrap("tampered-digest".getBytes()));
+ }
+ }
+
+ private void tamperWithMagic() throws Exception {
+ try (var ch = FileChannel.open(mDataBlockFile.toPath(), StandardOpenOption.WRITE)) {
+ ch.write(ByteBuffer.wrap("mark".getBytes()), DIGEST_SIZE_BYTES);
+ }
+ }
+
+ private void makeUserAdmin(boolean isAdmin) {
+ when(mUserManager.isUserAdmin(anyInt())).thenReturn(isAdmin);
+ }
+
+ private void grantOemUnlockPermission() {
+ doReturn(PackageManager.PERMISSION_GRANTED).when(mContext)
+ .checkCallingOrSelfPermission(eq(Manifest.permission.OEM_UNLOCK_STATE));
+ doNothing().when(mContext)
+ .enforceCallingOrSelfPermission(eq(Manifest.permission.OEM_UNLOCK_STATE),
+ anyString());
+ }
+
+ private void denyOemUnlockPermission() {
+ doReturn(PackageManager.PERMISSION_DENIED).when(mContext)
+ .checkCallingOrSelfPermission(eq(Manifest.permission.OEM_UNLOCK_STATE));
+ }
+
+ private void grantAccessPdbStatePermission() {
+ doReturn(PackageManager.PERMISSION_GRANTED).when(mContext)
+ .checkCallingPermission(eq(Manifest.permission.ACCESS_PDB_STATE));
+ }
+
+ private ByteBuffer readBackingFile(long position, int size) throws Exception {
+ try (var ch = FileChannel.open(mDataBlockFile.toPath(), StandardOpenOption.READ)) {
+ var buffer = ByteBuffer.allocate(size);
+ assertThat(ch.read(buffer, position)).isGreaterThan(0);
+ return buffer;
+ }
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/pm/SuspendPackagesTest.java b/services/tests/servicestests/src/com/android/server/pm/SuspendPackagesTest.java
index 01a91c1db1e6..398148ff4d3b 100644
--- a/services/tests/servicestests/src/com/android/server/pm/SuspendPackagesTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/SuspendPackagesTest.java
@@ -30,7 +30,6 @@ import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import android.app.AppGlobals;
-import android.content.AttributionSource;
import android.content.Context;
import android.content.pm.IPackageManager;
import android.content.pm.LauncherApps;
@@ -282,16 +281,12 @@ public class SuspendPackagesTest {
};
iAppOps.startWatchingMode(code, TEST_APP_PACKAGE_NAME, watcher);
final int testPackageUid = mPackageManager.getPackageUid(TEST_APP_PACKAGE_NAME, 0);
- AttributionSource attributionSource =
- new AttributionSource.Builder(testPackageUid)
- .setPackageName(TEST_APP_PACKAGE_NAME)
- .build();
- int opMode = iAppOps.checkOperationWithState(code, attributionSource.asState());
+ int opMode = iAppOps.checkOperation(code, testPackageUid, TEST_APP_PACKAGE_NAME);
assertEquals("Op " + opToName(code) + " disallowed for unsuspended package", MODE_ALLOWED,
opMode);
suspendTestPackage(null, null, null);
assertTrue("AppOpsWatcher did not callback", latch.await(5, TimeUnit.SECONDS));
- opMode = iAppOps.checkOperationWithState(code, attributionSource.asState());
+ opMode = iAppOps.checkOperation(code, testPackageUid, TEST_APP_PACKAGE_NAME);
assertEquals("Op " + opToName(code) + " allowed for suspended package", MODE_IGNORED,
opMode);
iAppOps.stopWatchingMode(watcher);
diff --git a/services/tests/wmtests/src/com/android/server/wm/RefreshRatePolicyTest.java b/services/tests/wmtests/src/com/android/server/wm/RefreshRatePolicyTest.java
index c4d03bebc751..49a888689e60 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RefreshRatePolicyTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RefreshRatePolicyTest.java
@@ -20,6 +20,7 @@ import static android.view.SurfaceControl.RefreshRateRange.FLOAT_TOLERANCE;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION;
+import static com.android.window.flags.Flags.explicitRefreshRateHints;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -282,6 +283,9 @@ public class RefreshRatePolicyTest extends WindowTestsBase {
assertEquals(0, mPolicy.getPreferredMinRefreshRate(overrideWindow), FLOAT_TOLERANCE);
assertEquals(0, mPolicy.getPreferredMaxRefreshRate(overrideWindow), FLOAT_TOLERANCE);
+ if (explicitRefreshRateHints()) {
+ return;
+ }
overrideWindow.mActivityRecord.mSurfaceAnimator.startAnimation(
overrideWindow.getPendingTransaction(), mock(AnimationAdapter.class),
false /* hidden */, ANIMATION_TYPE_APP_TRANSITION);
@@ -320,6 +324,9 @@ public class RefreshRatePolicyTest extends WindowTestsBase {
assertEquals(0, mPolicy.getPreferredMinRefreshRate(overrideWindow), FLOAT_TOLERANCE);
assertEquals(0, mPolicy.getPreferredMaxRefreshRate(overrideWindow), FLOAT_TOLERANCE);
+ if (explicitRefreshRateHints()) {
+ return;
+ }
overrideWindow.mActivityRecord.mSurfaceAnimator.startAnimation(
overrideWindow.getPendingTransaction(), mock(AnimationAdapter.class),
false /* hidden */, ANIMATION_TYPE_APP_TRANSITION);
@@ -342,6 +349,9 @@ public class RefreshRatePolicyTest extends WindowTestsBase {
assertEquals(0, mPolicy.getPreferredMinRefreshRate(window), FLOAT_TOLERANCE);
assertEquals(0, mPolicy.getPreferredMaxRefreshRate(window), FLOAT_TOLERANCE);
+ if (explicitRefreshRateHints()) {
+ return;
+ }
window.mActivityRecord.mSurfaceAnimator.startAnimation(
window.getPendingTransaction(), mock(AnimationAdapter.class),
false /* hidden */, ANIMATION_TYPE_APP_TRANSITION);
diff --git a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
index 2689e9d14c00..a83caa4a4e95 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
@@ -2454,6 +2454,7 @@ public class TransitionTests extends WindowTestsBase {
spyOn(perfHinter);
doAnswer(invocation -> {
session[0] = (SystemPerformanceHinter.HighPerfSession) invocation.callRealMethod();
+ spyOn(session[0]);
return session[0];
}).when(perfHinter).createSession(anyInt(), anyInt(), anyString());
}
diff --git a/test-mock/api/current.txt b/test-mock/api/current.txt
index f61cce666cca..daaab3314679 100644
--- a/test-mock/api/current.txt
+++ b/test-mock/api/current.txt
@@ -156,6 +156,7 @@ package android.test.mock {
method @Deprecated public int getInt(int);
method @Deprecated public long getLong(int);
method @Deprecated public android.net.Uri getNotificationUri();
+ method @Deprecated public java.util.List<android.net.Uri> getNotificationUris();
method @Deprecated public int getPosition();
method @Deprecated public short getShort(int);
method @Deprecated public String getString(int);
@@ -179,6 +180,7 @@ package android.test.mock {
method @Deprecated public android.os.Bundle respond(android.os.Bundle);
method @Deprecated public void setExtras(android.os.Bundle);
method @Deprecated public void setNotificationUri(android.content.ContentResolver, android.net.Uri);
+ method @Deprecated public void setNotificationUris(android.content.ContentResolver, java.util.List<android.net.Uri>);
method @Deprecated public void unregisterContentObserver(android.database.ContentObserver);
method @Deprecated public void unregisterDataSetObserver(android.database.DataSetObserver);
}
diff --git a/tools/hoststubgen/TEST_MAPPING b/tools/hoststubgen/TEST_MAPPING
index 970362611f53..e02492d68bb4 100644
--- a/tools/hoststubgen/TEST_MAPPING
+++ b/tools/hoststubgen/TEST_MAPPING
@@ -1,6 +1,8 @@
{
// TODO: Change to presubmit.
"postsubmit": [
- { "name": "tiny-framework-dump-test" }
+ { "name": "tiny-framework-dump-test" },
+ { "name": "hoststubgentest" },
+ { "name": "hoststubgen-invoke-test" }
]
}
diff --git a/tools/hoststubgen/hoststubgen/Android.bp b/tools/hoststubgen/hoststubgen/Android.bp
index 182940e6f7c5..fd4ec8bd5931 100644
--- a/tools/hoststubgen/hoststubgen/Android.bp
+++ b/tools/hoststubgen/hoststubgen/Android.bp
@@ -99,6 +99,18 @@ java_binary_host {
visibility: ["//visibility:public"],
}
+java_test_host {
+ name: "hoststubgentest",
+ // main_class: "com.android.hoststubgen.Main",
+ srcs: ["test/**/*.kt"],
+ static_libs: [
+ "hoststubgen",
+ "truth",
+ ],
+ test_suites: ["general-tests"],
+ visibility: ["//visibility:private"],
+}
+
// File that contains the standard command line argumetns to hoststubgen.
// This is only for the prototype. The productionized version is "ravenwood-standard-options".
filegroup {
diff --git a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/Parcel_host.java b/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/Parcel_host.java
index d749f076f3b5..12c7841556fc 100644
--- a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/Parcel_host.java
+++ b/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/Parcel_host.java
@@ -20,6 +20,7 @@ import android.os.IBinder;
import java.io.FileDescriptor;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
@@ -197,9 +198,9 @@ public class Parcel_host {
if (b == null) {
nativeWriteInt(nativePtr, -1);
} else {
- final var alignedSize = align4(b.length);
+ final var alignedSize = align4(len);
- nativeWriteInt(nativePtr, b.length);
+ nativeWriteInt(nativePtr, len);
p.ensureMoreCapacity(alignedSize);
@@ -280,6 +281,7 @@ public class Parcel_host {
+ data.length + " given=" + destLen);
return false;
}
+ System.arraycopy(data, 0, dest, 0, data.length);
return true;
}
@@ -289,7 +291,12 @@ public class Parcel_host {
return null;
}
var p = getInstance(nativePtr);
- p.ensureDataAvailable(size);
+ try {
+ p.ensureDataAvailable(align4(size));
+ } catch (Exception e) {
+ System.err.println(e.toString());
+ return null;
+ }
var bytes = new byte[size];
System.arraycopy(p.mBuffer, p.mPos, bytes, 0, size);
@@ -301,7 +308,10 @@ public class Parcel_host {
public static int nativeReadInt(long nativePtr) {
var p = getInstance(nativePtr);
- p.ensureDataAvailable(Integer.BYTES);
+ if (p.mSize - p.mPos < 4) {
+ // Match native impl that returns "0" when not enough data
+ return 0;
+ }
var ret = (((p.mBuffer[p.mPos++] & 0xff) << 24)
| ((p.mBuffer[p.mPos++] & 0xff) << 16)
@@ -341,11 +351,16 @@ public class Parcel_host {
}
public static byte[] nativeMarshall(long nativePtr) {
- throw new RuntimeException("Not implemented yet");
+ var p = getInstance(nativePtr);
+ return Arrays.copyOf(p.mBuffer, p.mSize);
}
public static void nativeUnmarshall(
long nativePtr, byte[] data, int offset, int length) {
- throw new RuntimeException("Not implemented yet");
+ var p = getInstance(nativePtr);
+ p.ensureMoreCapacity(length);
+ System.arraycopy(data, offset, p.mBuffer, p.mPos, length);
+ p.mPos += length;
+ p.updateSize();
}
public static int nativeCompareData(long thisNativePtr, long otherNativePtr) {
throw new RuntimeException("Not implemented yet");
diff --git a/tools/hoststubgen/hoststubgen/invoketest/Android.bp b/tools/hoststubgen/hoststubgen/invoketest/Android.bp
new file mode 100644
index 000000000000..7e90e421a1f9
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/invoketest/Android.bp
@@ -0,0 +1,20 @@
+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"],
+}
+
+sh_test_host {
+ name: "hoststubgen-invoke-test",
+ src: "hoststubgen-invoke-test.sh",
+ test_suites: ["general-tests"],
+
+ // Note: java_data: ["hoststubgen"] will only install the jar file, but not the command wrapper.
+ java_data: [
+ "hoststubgen",
+ "hoststubgen-test-tiny-framework",
+ ],
+}
diff --git a/tools/hoststubgen/hoststubgen/invoketest/hoststubgen-invoke-test.sh b/tools/hoststubgen/hoststubgen/invoketest/hoststubgen-invoke-test.sh
new file mode 100755
index 000000000000..34b2145b8d22
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/invoketest/hoststubgen-invoke-test.sh
@@ -0,0 +1,163 @@
+#!/bin/bash
+# Copyright (C) 2023 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.
+
+set -e # Exit when any command files
+
+# This script runs HostStubGen directly with various arguments and make sure
+# the tool behaves in the expected way.
+
+
+echo "# Listing files in the test environment"
+ls -lR
+
+echo "# Dumping the environment variables"
+env
+
+# Set up the constants and variables
+
+export TEMP=$TEST_TMPDIR
+
+JAR=hoststubgen-test-tiny-framework.jar
+STUB=$TEMP/stub.jar
+IMPL=$TEMP/impl.jar
+
+ANNOTATION_FILTER=$TEMP/annotation-filter.txt
+
+HOSTSTUBGEN_OUT=$TEMP/output.txt
+
+# Because of `set -e`, we can't return non-zero from functions, so we store
+# HostStubGen result in it.
+HOSTSTUBGEN_RC=0
+
+# Define the functions to
+
+
+# Note, because the build rule will only install hoststubgen.jar, but not the wrapper script,
+# we need to execute it manually with the java command.
+hoststubgen() {
+ java -jar ./hoststubgen.jar "$@"
+}
+
+run_hoststubgen() {
+ local test_name="$1"
+ local annotation_filter="$2"
+
+ echo "# Test: $test_name"
+
+ rm -f $HOSTSTUBGEN_OUT
+
+ local filter_arg=""
+
+ if [[ "$annotation_filter" != "" ]] ; then
+ echo "$annotation_filter" > $ANNOTATION_FILTER
+ filter_arg="--annotation-allowed-classes-file $ANNOTATION_FILTER"
+ echo "=== filter ==="
+ cat $ANNOTATION_FILTER
+ fi
+
+ hoststubgen \
+ --debug \
+ --in-jar $JAR \
+ --out-stub-jar $STUB \
+ --out-impl-jar $IMPL \
+ $filter_arg \
+ |& tee $HOSTSTUBGEN_OUT
+ HOSTSTUBGEN_RC=${PIPESTATUS[0]}
+ echo "HostStubGen exited with $HOSTSTUBGEN_RC"
+ return 0
+}
+
+run_hoststubgen_for_success() {
+ run_hoststubgen "$@"
+
+ if (( $HOSTSTUBGEN_RC != 0 )) ; then
+ echo "HostStubGen expected to finish successfully, but failed with $rc"
+ return 1
+ fi
+}
+
+run_hoststubgen_for_failure() {
+ local test_name="$1"
+ local expected_error_message="$2"
+ shift 2
+
+ run_hoststubgen "$test_name" "$@"
+
+ if (( $HOSTSTUBGEN_RC == 0 )) ; then
+ echo "HostStubGen expected to fail, but it didn't fail"
+ return 1
+ fi
+
+ # The output should contain the expected message. (note we se fgrep here.)
+ grep -Fq "$expected_error_message" $HOSTSTUBGEN_OUT
+}
+
+# Start the tests...
+
+# Pass "" as a filter to _not_ add `--annotation-allowed-classes-file`.
+run_hoststubgen_for_success "No annotation filter" ""
+
+# Now, we use " ", so we do add `--annotation-allowed-classes-file`.
+run_hoststubgen_for_failure "No classes are allowed to have annotations" \
+ "not allowed to have Ravenwood annotations" \
+ " "
+
+run_hoststubgen_for_success "All classes allowed (wildcard)" \
+ "
+* # Allow all classes
+"
+
+run_hoststubgen_for_failure "All classes disallowed (wildcard)" \
+ "not allowed to have Ravenwood annotations" \
+ "
+!* # Disallow all classes
+"
+
+run_hoststubgen_for_failure "Some classes not allowed (1)" \
+ "not allowed to have Ravenwood annotations" \
+ "
+android.hosttest.*
+com.android.hoststubgen.*
+com.supported.*
+"
+
+run_hoststubgen_for_failure "Some classes not allowed (2)" \
+ "not allowed to have Ravenwood annotations" \
+ "
+android.hosttest.*
+com.android.hoststubgen.*
+com.unsupported.*
+"
+
+run_hoststubgen_for_success "All classes allowed (package wildcard)" \
+ "
+android.hosttest.*
+com.android.hoststubgen.*
+com.supported.*
+com.unsupported.*
+"
+
+
+run_hoststubgen_for_failure "One specific class disallowed" \
+ "TinyFrameworkClassAnnotations is not allowed to have Ravenwood annotations" \
+ "
+!com.android.hoststubgen.test.tinyframework.TinyFrameworkClassAnnotations
+* # All other classes allowed
+"
+
+
+
+echo "All tests passed"
+exit 0 \ No newline at end of file
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt
index 872d56856c33..f32dc721873e 100644
--- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt
@@ -27,6 +27,7 @@ import com.android.hoststubgen.filters.OutputFilter
import com.android.hoststubgen.filters.StubIntersectingFilter
import com.android.hoststubgen.filters.createFilterFromTextPolicyFile
import com.android.hoststubgen.filters.printAsTextPolicy
+import com.android.hoststubgen.utils.ClassFilter
import com.android.hoststubgen.visitors.BaseAdapter
import com.android.hoststubgen.visitors.PackageRedirectRemapper
import org.objectweb.asm.ClassReader
@@ -167,6 +168,14 @@ class HostStubGen(val options: HostStubGenOptions) {
filter
)
+ val annotationAllowedClassesFilter = options.annotationAllowedClassesFile.let { filename ->
+ if (filename == null) {
+ ClassFilter.newNullFilter(true) // Allow all classes
+ } else {
+ ClassFilter.loadFromFile(filename, false)
+ }
+ }
+
// Next, Java annotation based filter.
filter = AnnotationBasedFilter(
errors,
@@ -181,7 +190,8 @@ class HostStubGen(val options: HostStubGenOptions) {
options.nativeSubstituteAnnotations,
options.classLoadHookAnnotations,
options.stubStaticInitializerAnnotations,
- filter
+ annotationAllowedClassesFilter,
+ filter,
)
// Next, "text based" filter, which allows to override polices without touching
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenOptions.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenOptions.kt
index d74612d48de2..aab02b8de254 100644
--- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenOptions.kt
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenOptions.kt
@@ -51,6 +51,8 @@ class HostStubGenOptions(
var packageRedirects: MutableList<Pair<String, String>> = mutableListOf(),
+ var annotationAllowedClassesFile: String? = null,
+
var defaultClassLoadHook: String? = null,
var defaultMethodCallHook: String? = null,
@@ -171,6 +173,9 @@ class HostStubGenOptions(
"--package-redirect" ->
ret.packageRedirects += parsePackageRedirect(ai.nextArgRequired(arg))
+ "--annotation-allowed-classes-file" ->
+ ret.annotationAllowedClassesFile = ai.nextArgRequired(arg)
+
"--default-class-load-hook" ->
ret.defaultClassLoadHook = ai.nextArgRequired(arg)
@@ -314,6 +319,7 @@ class HostStubGenOptions(
nativeSubstituteAnnotations=$nativeSubstituteAnnotations,
classLoadHookAnnotations=$classLoadHookAnnotations,
packageRedirects=$packageRedirects,
+ $annotationAllowedClassesFile=$annotationAllowedClassesFile,
defaultClassLoadHook=$defaultClassLoadHook,
defaultMethodCallHook=$defaultMethodCallHook,
intersectStubJars=$intersectStubJars,
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/Utils.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/Utils.kt
index f75062b3a878..937e56c2cbb5 100644
--- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/Utils.kt
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/Utils.kt
@@ -58,4 +58,29 @@ fun <T> addNonNullElement(a: List<T>, b: T?): List<T> {
return listOf(b)
}
return a + b
-} \ No newline at end of file
+}
+
+
+/**
+ * Exception for a parse error in a file
+ */
+class ParseException : Exception, UserErrorException {
+ val hasSourceInfo: Boolean
+
+ constructor(message: String) : super(message) {
+ hasSourceInfo = false
+ }
+
+ constructor(message: String, file: String, line: Int) :
+ super("$message in file $file line $line") {
+ hasSourceInfo = true
+ }
+
+ fun withSourceInfo(filename: String, lineNo: Int): ParseException {
+ if (hasSourceInfo) {
+ return this // Already has source information.
+ } else {
+ return ParseException(this.message ?: "", filename, lineNo)
+ }
+ }
+}
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/asm/AsmUtils.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/asm/AsmUtils.kt
index a51bdcf0c793..1bcf3642082f 100644
--- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/asm/AsmUtils.kt
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/asm/AsmUtils.kt
@@ -22,6 +22,8 @@ import org.objectweb.asm.Opcodes
import org.objectweb.asm.Type
import org.objectweb.asm.tree.AnnotationNode
import org.objectweb.asm.tree.ClassNode
+import org.objectweb.asm.tree.FieldNode
+import org.objectweb.asm.tree.MethodNode
/** Name of the class initializer method. */
@@ -175,3 +177,93 @@ fun isVisibilityPrivateOrPackagePrivate(access: Int): Boolean {
else -> false
}
}
+
+fun ClassNode.isEnum(): Boolean {
+ return (this.access and Opcodes.ACC_ENUM) != 0
+}
+
+fun ClassNode.isAnnotation(): Boolean {
+ return (this.access and Opcodes.ACC_ANNOTATION) != 0
+}
+
+fun ClassNode.isSynthetic(): Boolean {
+ return (this.access and Opcodes.ACC_SYNTHETIC) != 0
+}
+
+fun MethodNode.isSynthetic(): Boolean {
+ return (this.access and Opcodes.ACC_SYNTHETIC) != 0
+}
+
+fun FieldNode.isEnum(): Boolean {
+ return (this.access and Opcodes.ACC_ENUM) != 0
+}
+
+fun FieldNode.isSynthetic(): Boolean {
+ return (this.access and Opcodes.ACC_SYNTHETIC) != 0
+}
+
+/*
+
+Dump of the members of TinyFrameworkEnumSimple:
+
+class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple keep
+ field Cat keep (ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM)
+ field Dog keep
+ field $VALUES keep (ACC_PRIVATE, ACC_STATIC, ACC_FINAL, ACC_SYNTHETIC)
+
+ method values ()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple; keep
+ ^- NOT synthetic (ACC_PUBLIC, ACC_STATIC)
+ method valueOf (Ljava/lang/String;)Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple; keep
+ ^- NOT synthetic (ACC_PUBLIC, ACC_STATIC)
+ method <init> (Ljava/lang/String;I)V keep
+ ^- NOT synthetic (ACC_PRIVATE)
+
+ method $values ()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple; keep
+ (ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC)
+ method <clinit> ()V keep
+
+Dump of the members of TinyFrameworkEnumSimple:
+
+class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex keep
+ field RED keep
+ field BLUE keep
+ field GREEN keep
+ field mLongName keep
+ field mShortName keep
+ field $VALUES keep
+ method values ()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex; keep
+ method valueOf (Ljava/lang/String;)Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex; keep
+ method <init> (Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)V keep
+ method getLongName ()Ljava/lang/String; keep
+ method getShortName ()Ljava/lang/String; keep
+ method $values ()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex; keep
+ method <clinit> ()V keep
+
+ */
+
+fun isAutoGeneratedEnumMember(mn: MethodNode): Boolean {
+ if (mn.isSynthetic()) {
+ return true
+ }
+ if (mn.name == "<init>" && mn.desc == "(Ljava/lang/String;I)V") {
+ return true
+ }
+ if (mn.name == "<clinit>" && mn.desc == "()V") {
+ return true
+ }
+ if (mn.name == "values" && mn.desc.startsWith("()")) {
+ return true
+ }
+ if (mn.name == "valueOf" && mn.desc.startsWith("(Ljava/lang/String;)")) {
+ return true
+ }
+
+ return false
+}
+
+fun isAutoGeneratedEnumMember(fn: FieldNode): Boolean {
+ if (fn.isSynthetic() || fn.isEnum()) {
+ return true
+ }
+ return false
+}
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/AnnotationBasedFilter.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/AnnotationBasedFilter.kt
index 9f3ec4d2b450..9bb5381eef06 100644
--- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/AnnotationBasedFilter.kt
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/AnnotationBasedFilter.kt
@@ -25,9 +25,11 @@ import com.android.hoststubgen.asm.CLASS_INITIALIZER_NAME
import com.android.hoststubgen.asm.ClassNodes
import com.android.hoststubgen.asm.findAnnotationValueAsString
import com.android.hoststubgen.asm.findAnyAnnotation
+import com.android.hoststubgen.asm.toHumanReadableClassName
import com.android.hoststubgen.asm.toHumanReadableMethodName
import com.android.hoststubgen.asm.toJvmClassName
import com.android.hoststubgen.log
+import com.android.hoststubgen.utils.ClassFilter
import org.objectweb.asm.tree.AnnotationNode
import org.objectweb.asm.tree.ClassNode
@@ -51,6 +53,7 @@ class AnnotationBasedFilter(
nativeSubstituteAnnotations_: Set<String>,
classLoadHookAnnotations_: Set<String>,
stubStaticInitializerAnnotations_: Set<String>,
+ private val annotationAllowedClassesFilter: ClassFilter,
fallback: OutputFilter,
) : DelegatingFilter(fallback) {
private var stubAnnotations = convertToInternalNames(stubAnnotations_)
@@ -62,7 +65,8 @@ class AnnotationBasedFilter(
private var substituteAnnotations = convertToInternalNames(substituteAnnotations_)
private var nativeSubstituteAnnotations = convertToInternalNames(nativeSubstituteAnnotations_)
private var classLoadHookAnnotations = convertToInternalNames(classLoadHookAnnotations_)
- private var stubStaticInitializerAnnotations = convertToInternalNames(stubStaticInitializerAnnotations_)
+ private var stubStaticInitializerAnnotations =
+ convertToInternalNames(stubStaticInitializerAnnotations_)
/** Annotations that control API visibility. */
private var visibilityAnnotations: Set<String> = convertToInternalNames(
@@ -135,15 +139,22 @@ class AnnotationBasedFilter(
* name1 - 4 are only used in exception messages.
*/
private fun findAnnotation(
- visibles: List<AnnotationNode>?,
- invisibles: List<AnnotationNode>?,
- type: String,
- name1: String,
- name2: String = "",
- name3: String = "",
+ className: String,
+ visibles: List<AnnotationNode>?,
+ invisibles: List<AnnotationNode>?,
+ type: String,
+ name1: String,
+ name2: String = "",
+ name3: String = "",
): FilterPolicyWithReason? {
detectInvalidAnnotations(visibles, invisibles, type, name1, name2, name3)
+ if (!annotationAllowedClassesFilter.matches(className)) {
+ throw InvalidAnnotationException(
+ "Class ${className.toHumanReadableClassName()} is not allowed to have " +
+ "Ravenwood annotations. Contact g/ravenwood for more details.")
+ }
+
findAnyAnnotation(stubAnnotations, visibles, invisibles)?.let {
return FilterPolicy.Stub.withReason(reasonAnnotation)
}
@@ -170,6 +181,7 @@ class AnnotationBasedFilter(
val cn = classes.getClass(className)
findAnnotation(
+ cn.name,
cn.visibleAnnotations,
cn.invisibleAnnotations,
"class",
@@ -193,6 +205,7 @@ class AnnotationBasedFilter(
cn.fields?.firstOrNull { it.name == fieldName }?.let {fn ->
findAnnotation(
+ cn.name,
fn.visibleAnnotations,
fn.invisibleAnnotations,
"field",
@@ -229,6 +242,7 @@ class AnnotationBasedFilter(
// If there's no substitution, then we check the annotation.
findAnnotation(
+ cn.name,
mn.visibleAnnotations,
mn.invisibleAnnotations,
"method",
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/ImplicitOutputFilter.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/ImplicitOutputFilter.kt
index 07a023c66926..9c0fa69f8a14 100644
--- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/ImplicitOutputFilter.kt
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/ImplicitOutputFilter.kt
@@ -22,6 +22,9 @@ import com.android.hoststubgen.asm.CLASS_INITIALIZER_NAME
import com.android.hoststubgen.asm.isAnonymousInnerClass
import com.android.hoststubgen.log
import com.android.hoststubgen.asm.ClassNodes
+import com.android.hoststubgen.asm.isAnnotation
+import com.android.hoststubgen.asm.isAutoGeneratedEnumMember
+import com.android.hoststubgen.asm.isEnum
import com.android.hoststubgen.asm.isVisibilityPrivateOrPackagePrivate
import org.objectweb.asm.tree.ClassNode
@@ -57,18 +60,8 @@ class ImplicitOutputFilter(
override fun getPolicyForClass(className: String): FilterPolicyWithReason {
val fallback = super.getPolicyForClass(className)
- // TODO: This check should be cached.
val cn = classes.getClass(className)
- if (cn.superName == "java/lang/Enum" &&
- fallback.policy == FilterPolicy.Keep) {
- return FilterPolicy.KeepClass.withReason("enum")
- }
- if (cn.interfaces.contains("java/lang/annotation/Annotation") &&
- fallback.policy == FilterPolicy.Keep) {
- return FilterPolicy.KeepClass.withReason("annotation")
- }
-
// Use the implicit policy, if any.
getClassImplicitPolicy(className, cn)?.let { return it }
@@ -95,16 +88,78 @@ class ImplicitOutputFilter(
}
}
+ val cn = classes.getClass(className)
+
// If we throw from the static initializer, the class would be useless, so we convert it
// "keep" instead.
- if (methodName == CLASS_INITIALIZER_NAME && descriptor == CLASS_INITIALIZER_DESC &&
- fallback.policy == FilterPolicy.Throw) {
+ // Unless it's an enum -- in that case, the below code would handle it.
+ if (!cn.isEnum() &&
+ fallback.policy == FilterPolicy.Throw &&
+ methodName == CLASS_INITIALIZER_NAME && descriptor == CLASS_INITIALIZER_DESC) {
// TODO Maybe show a warning?? But that'd be too noisy with --default-throw.
return FilterPolicy.Ignore.withReason(
"'throw' on static initializer is handled as 'ignore'" +
" [original throw reason: ${fallback.reason}]")
}
+ val classPolicy = super.getPolicyForClass(className)
+
+ log.d("Class ${cn.name} Class policy: $classPolicy")
+ if (classPolicy.policy.needsInImpl) {
+ // Do it only when the class needs to be kept...
+
+ // Member policy should be "keep" or "stub".
+ val memberPolicy = classPolicy.policy.resolveClassWidePolicy()
+
+ // Keep (or stub) the generated enum members.
+ if (cn.isEnum()) {
+ classes.findMethod(className, methodName, descriptor)?.let { mn ->
+ if (isAutoGeneratedEnumMember(mn)) {
+ return memberPolicy.withReason(classPolicy.reason).wrapReason("enum")
+ }
+ }
+ }
+
+ // Keep (or stub) all members of annotations.
+ if (cn.isAnnotation()) {
+ return memberPolicy.withReason(classPolicy.reason).wrapReason("annotation")
+ }
+ }
+
+ return fallback
+ }
+
+ override fun getPolicyForField(
+ className: String,
+ fieldName: String
+ ): FilterPolicyWithReason {
+ val fallback = super.getPolicyForField(className, fieldName)
+
+ val cn = classes.getClass(className)
+ val classPolicy = super.getPolicyForClass(className)
+
+ log.d("Class ${cn.name} Class policy: $classPolicy")
+ if (classPolicy.policy.needsInImpl) {
+ // Do it only when the class needs to be kept...
+
+ // Member policy should be "keep" or "stub".
+ val memberPolicy = classPolicy.policy.resolveClassWidePolicy()
+
+ // Keep (or stub) the generated enum members.
+ if (cn.isEnum()) {
+ classes.findField(className, fieldName)?.let { fn ->
+ if (isAutoGeneratedEnumMember(fn)) {
+ return memberPolicy.withReason(classPolicy.reason).wrapReason("enum")
+ }
+ }
+ }
+
+ // Keep (or stub) all members of annotations.
+ if (cn.isAnnotation()) {
+ return memberPolicy.withReason(classPolicy.reason).wrapReason("annotation")
+ }
+ }
+
return fallback
}
} \ No newline at end of file
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/TextFileFilterPolicyParser.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/TextFileFilterPolicyParser.kt
index 46546e8b9491..416f08505867 100644
--- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/TextFileFilterPolicyParser.kt
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/TextFileFilterPolicyParser.kt
@@ -15,7 +15,7 @@
*/
package com.android.hoststubgen.filters
-import com.android.hoststubgen.UserErrorException
+import com.android.hoststubgen.ParseException
import com.android.hoststubgen.asm.ClassNodes
import com.android.hoststubgen.log
import com.android.hoststubgen.normalizeTextLine
@@ -46,30 +46,6 @@ private fun isVisible(access: Int): Boolean {
return (access and (Opcodes.ACC_PUBLIC or Opcodes.ACC_PROTECTED)) != 0
}
-/**
- * Exception for a parse error.
- */
-private class ParseException : Exception, UserErrorException {
- val hasSourceInfo: Boolean
-
- constructor(message: String) : super(message) {
- hasSourceInfo = false
- }
-
- constructor(message: String, file: String, line: Int) :
- super("$message in file $file line $line") {
- hasSourceInfo = true
- }
-
- fun withSourceInfo(filename: String, lineNo: Int): ParseException {
- if (hasSourceInfo) {
- return this // Already has source information.
- } else {
- return ParseException(this.message ?: "", filename, lineNo)
- }
- }
-}
-
private const val FILTER_REASON = "file-override"
/**
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/utils/ClassFilter.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/utils/ClassFilter.kt
new file mode 100644
index 000000000000..01a7ab3eacfa
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/utils/ClassFilter.kt
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2023 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.hoststubgen.utils
+
+import com.android.hoststubgen.ParseException
+import com.android.hoststubgen.asm.toHumanReadableClassName
+import com.android.hoststubgen.asm.toJvmClassName
+import com.android.hoststubgen.normalizeTextLine
+import java.io.File
+
+/**
+ * General purpose filter for class names.
+ */
+class ClassFilter private constructor (
+ val defaultResult: Boolean,
+) {
+ private data class FilterElement(
+ val allowed: Boolean,
+ val internalName: String,
+ val isPrefix: Boolean,
+ ) {
+ fun matches(classInternalName: String): Boolean {
+ if (isPrefix) {
+ return classInternalName.startsWith(internalName)
+ } else {
+ return classInternalName == internalName
+ }
+ }
+ }
+
+ private val elements: MutableList<FilterElement> = mutableListOf()
+
+ private val cache: MutableMap<String, Boolean> = mutableMapOf()
+
+ /**
+ * Takes an internal class name (e.g. "com/android/hoststubgen/ClassName") and returns if
+ * matches the filter or not.
+ */
+ fun matches(classInternalName: String): Boolean {
+ cache[classInternalName]?.let {
+ return it
+ }
+
+ var result = defaultResult
+ run outer@{
+ elements.forEach { e ->
+ if (e.matches(classInternalName)) {
+ result = e.allowed
+ return@outer // break equivalent.
+ }
+ }
+ }
+ cache[classInternalName] = result
+
+ return result
+ }
+
+ fun getCacheSizeForTest(): Int {
+ return cache.size
+ }
+
+ companion object {
+ /**
+ * Return a filter that alawys returns true or false.
+ */
+ fun newNullFilter(defaultResult: Boolean): ClassFilter {
+ return ClassFilter(defaultResult)
+ }
+
+ /** Build a filter from a file. */
+ fun loadFromFile(filename: String, defaultResult: Boolean): ClassFilter {
+ return buildFromString(File(filename).readText(), defaultResult, filename)
+ }
+
+ /** Build a filter from a string (for unit tests). */
+ fun buildFromString(
+ filterString: String,
+ defaultResult: Boolean,
+ filenameForErrorMessage: String
+ ): ClassFilter {
+ val ret = ClassFilter(defaultResult)
+
+ var lineNo = 0
+ filterString.split('\n').forEach { s ->
+ lineNo++
+
+ var line = normalizeTextLine(s)
+
+ if (line.isEmpty()) {
+ return@forEach // skip empty lines.
+ }
+
+ line = line.toHumanReadableClassName() // Convert all the slashes to periods.
+
+ var allow = true
+ if (line.startsWith("!")) {
+ allow = false
+ line = line.substring(1).trimStart()
+ }
+
+ // Special case -- matches any class names.
+ if (line == "*") {
+ ret.elements.add(FilterElement(allow, "", true))
+ return@forEach
+ }
+
+ // Handle wildcard -- e.g. "package.name.*"
+ if (line.endsWith(".*")) {
+ ret.elements.add(FilterElement(
+ allow, line.substring(0, line.length - 2).toJvmClassName(), true))
+ return@forEach
+ }
+
+ // Any other uses of "*" would be an error.
+ if (line.contains('*')) {
+ throw ParseException(
+ "Wildcard (*) can only show up as the last element",
+ filenameForErrorMessage,
+ lineNo
+ )
+ }
+ ret.elements.add(FilterElement(allow, line.toJvmClassName(), false))
+ }
+
+ return ret
+ }
+ }
+} \ No newline at end of file
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/Android.bp b/tools/hoststubgen/hoststubgen/test-tiny-framework/Android.bp
index 3dc6da348937..e7873d6eecc3 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/Android.bp
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/Android.bp
@@ -16,6 +16,7 @@ java_library {
static_libs: [
"hoststubgen-annotations",
],
+ visibility: ["//frameworks/base/tools/hoststubgen:__subpackages__"],
}
// Create stub/impl jars from "hoststubgen-test-tiny-framework", using the following 3 rules.
@@ -30,6 +31,7 @@ java_genrule_host {
":hoststubgen-test-tiny-framework",
"policy-override-tiny-framework.txt",
],
+ visibility: ["//visibility:private"],
}
java_genrule_host {
@@ -41,6 +43,7 @@ java_genrule_host {
out: [
"host_stub.jar",
],
+ visibility: ["//visibility:private"],
}
java_genrule_host {
@@ -52,6 +55,7 @@ java_genrule_host {
out: [
"host_impl.jar",
],
+ visibility: ["//visibility:private"],
}
// Same as "hoststubgen-test-tiny-framework-host", but with more options, to test more hoststubgen
@@ -71,6 +75,7 @@ java_genrule_host {
":hoststubgen-test-tiny-framework",
"policy-override-tiny-framework.txt",
],
+ visibility: ["//visibility:private"],
}
java_genrule_host {
@@ -82,6 +87,7 @@ java_genrule_host {
out: [
"host_stub.jar",
],
+ visibility: ["//visibility:private"],
}
java_genrule_host {
@@ -93,6 +99,7 @@ java_genrule_host {
out: [
"host_impl.jar",
],
+ visibility: ["//visibility:private"],
}
// Compile the test jar, using 2 rules.
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/annotation-allowed-classes-tiny-framework.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/annotation-allowed-classes-tiny-framework.txt
new file mode 100644
index 000000000000..bd9e85e17890
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/annotation-allowed-classes-tiny-framework.txt
@@ -0,0 +1,29 @@
+# Only classes listed here can use the hoststubgen annotations.
+
+# For each class, we check each item in this file, and when a match is found, we
+# either allow it if the line doesn't have a !, or disallow if the line has a !.
+# All the lines after the matching line will be ignored.
+
+
+# To allow a specific class to use annotations:
+# com.android.hoststubgen.test.tinyframework.TinyFrameworkClassAnnotations
+
+# To disallow a specific class to use annotations:
+# !com.android.hoststubgen.test.tinyframework.TinyFrameworkClassAnnotations
+
+# To allow a specific package to use annotations:
+# com.android.hoststubgen.test.*
+
+# To disallow a specific package to use annotations:
+# !com.android.hoststubgen.test.*
+
+
+com.android.hoststubgen.test.tinyframework.*
+com.supported.*
+com.unsupported.*
+
+# Use this to allow all packages
+# *
+
+# Use this to allow all packages
+# !* \ No newline at end of file
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/01-hoststubgen-test-tiny-framework-orig-dump.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/01-hoststubgen-test-tiny-framework-orig-dump.txt
index f627c6e7d7b5..78a4fa692c21 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/01-hoststubgen-test-tiny-framework-orig-dump.txt
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/01-hoststubgen-test-tiny-framework-orig-dump.txt
@@ -879,6 +879,314 @@ RuntimeInvisibleAnnotations:
android.hosttest.annotation.HostSideTestStub
x: #x()
android.hosttest.annotation.HostSideTestStaticInitializerStub
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex.class
+ Compiled from "TinyFrameworkEnumComplex.java"
+public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex extends java.lang.Enum<com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex>
+ minor version: 0
+ major version: 61
+ flags: (0x4031) ACC_PUBLIC, ACC_FINAL, ACC_SUPER, ACC_ENUM
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex
+ super_class: #x // java/lang/Enum
+ interfaces: 0, fields: 6, methods: 7, attributes: 3
+ public static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex RED;
+ descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ flags: (0x4019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
+
+ public static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex GREEN;
+ descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ flags: (0x4019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
+
+ public static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex BLUE;
+ descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ flags: (0x4019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
+
+ private final java.lang.String mLongName;
+ descriptor: Ljava/lang/String;
+ flags: (0x0012) ACC_PRIVATE, ACC_FINAL
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+
+ private final java.lang.String mShortName;
+ descriptor: Ljava/lang/String;
+ flags: (0x0012) ACC_PRIVATE, ACC_FINAL
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+
+ private static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex[] $VALUES;
+ descriptor: [Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ flags: (0x101a) ACC_PRIVATE, ACC_STATIC, ACC_FINAL, ACC_SYNTHETIC
+
+ public static com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex[] values();
+ descriptor: ()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=1, locals=0, args_size=0
+ x: getstatic #x // Field $VALUES:[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ x: invokevirtual #x // Method "[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;".clone:()Ljava/lang/Object;
+ x: checkcast #x // class "[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;"
+ x: areturn
+ LineNumberTable:
+
+ public static com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex valueOf(java.lang.String);
+ descriptor: (Ljava/lang/String;)Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=2, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex
+ x: aload_0
+ x: invokestatic #x // Method java/lang/Enum.valueOf:(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;
+ x: checkcast #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex
+ x: areturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 10 0 name Ljava/lang/String;
+
+ private com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex(java.lang.String, java.lang.String);
+ descriptor: (Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)V
+ flags: (0x0002) ACC_PRIVATE
+ Code:
+ stack=3, locals=5, args_size=5
+ x: aload_0
+ x: aload_1
+ x: iload_2
+ x: invokespecial #x // Method java/lang/Enum."<init>":(Ljava/lang/String;I)V
+ x: aload_0
+ x: aload_3
+ x: putfield #x // Field mLongName:Ljava/lang/String;
+ x: aload_0
+ x: aload 4
+ x: putfield #x // Field mShortName:Ljava/lang/String;
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 18 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ 0 18 3 longName Ljava/lang/String;
+ 0 18 4 shortName Ljava/lang/String;
+ Signature: #x // (Ljava/lang/String;Ljava/lang/String;)V
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
+
+ public java.lang.String getLongName();
+ descriptor: ()Ljava/lang/String;
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: getfield #x // Field mLongName:Ljava/lang/String;
+ x: areturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
+
+ public java.lang.String getShortName();
+ descriptor: ()Ljava/lang/String;
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: getfield #x // Field mShortName:Ljava/lang/String;
+ x: areturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
+
+ private static com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex[] $values();
+ descriptor: ()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ flags: (0x100a) ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
+ Code:
+ stack=4, locals=0, args_size=0
+ x: iconst_3
+ x: anewarray #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex
+ x: dup
+ x: iconst_0
+ x: getstatic #x // Field RED:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ x: aastore
+ x: dup
+ x: iconst_1
+ x: getstatic #x // Field GREEN:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ x: aastore
+ x: dup
+ x: iconst_2
+ x: getstatic #x // Field BLUE:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ x: aastore
+ x: areturn
+ LineNumberTable:
+
+ static {};
+ descriptor: ()V
+ flags: (0x0008) ACC_STATIC
+ Code:
+ stack=6, locals=0, args_size=0
+ x: new #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex
+ x: dup
+ x: ldc #x // String RED
+ x: iconst_0
+ x: ldc #x // String Red
+ x: ldc #x // String R
+ x: invokespecial #x // Method "<init>":(Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)V
+ x: putstatic #x // Field RED:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ x: new #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex
+ x: dup
+ x: ldc #x // String GREEN
+ x: iconst_1
+ x: ldc #x // String Green
+ x: ldc #x // String G
+ x: invokespecial #x // Method "<init>":(Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)V
+ x: putstatic #x // Field GREEN:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ x: new #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex
+ x: dup
+ x: ldc #x // String BLUE
+ x: iconst_2
+ x: ldc #x // String Blue
+ x: ldc #x // String B
+ x: invokespecial #x // Method "<init>":(Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)V
+ x: putstatic #x // Field BLUE:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ x: invokestatic #x // Method $values:()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ x: putstatic #x // Field $VALUES:[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ x: return
+ LineNumberTable:
+}
+Signature: #x // Ljava/lang/Enum<Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;>;
+SourceFile: "TinyFrameworkEnumComplex.java"
+RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple.class
+ Compiled from "TinyFrameworkEnumSimple.java"
+public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple extends java.lang.Enum<com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple>
+ minor version: 0
+ major version: 61
+ flags: (0x4031) ACC_PUBLIC, ACC_FINAL, ACC_SUPER, ACC_ENUM
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple
+ super_class: #x // java/lang/Enum
+ interfaces: 0, fields: 3, methods: 5, attributes: 3
+ public static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple CAT;
+ descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ flags: (0x4019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
+
+ public static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple DOG;
+ descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ flags: (0x4019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
+
+ private static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple[] $VALUES;
+ descriptor: [Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ flags: (0x101a) ACC_PRIVATE, ACC_STATIC, ACC_FINAL, ACC_SYNTHETIC
+
+ public static com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple[] values();
+ descriptor: ()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=1, locals=0, args_size=0
+ x: getstatic #x // Field $VALUES:[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ x: invokevirtual #x // Method "[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;".clone:()Ljava/lang/Object;
+ x: checkcast #x // class "[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;"
+ x: areturn
+ LineNumberTable:
+
+ public static com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple valueOf(java.lang.String);
+ descriptor: (Ljava/lang/String;)Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=2, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple
+ x: aload_0
+ x: invokestatic #x // Method java/lang/Enum.valueOf:(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;
+ x: checkcast #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple
+ x: areturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 10 0 name Ljava/lang/String;
+
+ private com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple();
+ descriptor: (Ljava/lang/String;I)V
+ flags: (0x0002) ACC_PRIVATE
+ Code:
+ stack=3, locals=3, args_size=3
+ x: aload_0
+ x: aload_1
+ x: iload_2
+ x: invokespecial #x // Method java/lang/Enum."<init>":(Ljava/lang/String;I)V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 7 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ Signature: #x // ()V
+
+ private static com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple[] $values();
+ descriptor: ()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ flags: (0x100a) ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
+ Code:
+ stack=4, locals=0, args_size=0
+ x: iconst_2
+ x: anewarray #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple
+ x: dup
+ x: iconst_0
+ x: getstatic #x // Field CAT:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ x: aastore
+ x: dup
+ x: iconst_1
+ x: getstatic #x // Field DOG:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ x: aastore
+ x: areturn
+ LineNumberTable:
+
+ static {};
+ descriptor: ()V
+ flags: (0x0008) ACC_STATIC
+ Code:
+ stack=4, locals=0, args_size=0
+ x: new #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple
+ x: dup
+ x: ldc #x // String CAT
+ x: iconst_0
+ x: invokespecial #x // Method "<init>":(Ljava/lang/String;I)V
+ x: putstatic #x // Field CAT:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ x: new #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple
+ x: dup
+ x: ldc #x // String DOG
+ x: iconst_1
+ x: invokespecial #x // Method "<init>":(Ljava/lang/String;I)V
+ x: putstatic #x // Field DOG:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ x: invokestatic #x // Method $values:()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ x: putstatic #x // Field $VALUES:[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ x: return
+ LineNumberTable:
+}
+Signature: #x // Ljava/lang/Enum<Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;>;
+SourceFile: "TinyFrameworkEnumSimple.java"
+RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkExceptionTester.class
Compiled from "TinyFrameworkExceptionTester.java"
public class com.android.hoststubgen.test.tinyframework.TinyFrameworkExceptionTester
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/02-hoststubgen-test-tiny-framework-host-stub-dump.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/02-hoststubgen-test-tiny-framework-host-stub-dump.txt
index d7f0149494c0..df63815ea0ae 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/02-hoststubgen-test-tiny-framework-host-stub-dump.txt
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/02-hoststubgen-test-tiny-framework-host-stub-dump.txt
@@ -446,6 +446,230 @@ RuntimeInvisibleAnnotations:
android.hosttest.annotation.HostSideTestStub
x: #x()
android.hosttest.annotation.HostSideTestStaticInitializerStub
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex.class
+ Compiled from "TinyFrameworkEnumComplex.java"
+public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex extends java.lang.Enum<com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex>
+ minor version: 0
+ major version: 61
+ flags: (0x4031) ACC_PUBLIC, ACC_FINAL, ACC_SUPER, ACC_ENUM
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex
+ super_class: #x // java/lang/Enum
+ interfaces: 0, fields: 4, methods: 7, attributes: 4
+ public static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex RED;
+ descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ flags: (0x4019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
+
+ public static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex GREEN;
+ descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ flags: (0x4019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
+
+ public static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex BLUE;
+ descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ flags: (0x4019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
+
+ private static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex[] $VALUES;
+ descriptor: [Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ flags: (0x101a) ACC_PRIVATE, ACC_STATIC, ACC_FINAL, ACC_SYNTHETIC
+
+ public static com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex[] values();
+ descriptor: ()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=3, locals=0, args_size=0
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+
+ public static com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex valueOf(java.lang.String);
+ descriptor: (Ljava/lang/String;)Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=3, locals=1, args_size=1
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+
+ private com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex(java.lang.String, java.lang.String);
+ descriptor: (Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)V
+ flags: (0x0002) ACC_PRIVATE
+ Code:
+ stack=3, locals=5, args_size=5
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ Signature: #x // (Ljava/lang/String;Ljava/lang/String;)V
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
+
+ public java.lang.String getLongName();
+ descriptor: ()Ljava/lang/String;
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=3, locals=1, args_size=1
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
+
+ public java.lang.String getShortName();
+ descriptor: ()Ljava/lang/String;
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=3, locals=1, args_size=1
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
+
+ private static com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex[] $values();
+ descriptor: ()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ flags: (0x100a) ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
+ Code:
+ stack=3, locals=0, args_size=0
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+
+ static {};
+ descriptor: ()V
+ flags: (0x0008) ACC_STATIC
+ Code:
+ stack=3, locals=0, args_size=0
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+}
+Signature: #x // Ljava/lang/Enum<Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;>;
+SourceFile: "TinyFrameworkEnumComplex.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple.class
+ Compiled from "TinyFrameworkEnumSimple.java"
+public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple extends java.lang.Enum<com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple>
+ minor version: 0
+ major version: 61
+ flags: (0x4031) ACC_PUBLIC, ACC_FINAL, ACC_SUPER, ACC_ENUM
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple
+ super_class: #x // java/lang/Enum
+ interfaces: 0, fields: 3, methods: 5, attributes: 4
+ public static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple CAT;
+ descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ flags: (0x4019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
+
+ public static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple DOG;
+ descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ flags: (0x4019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
+
+ private static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple[] $VALUES;
+ descriptor: [Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ flags: (0x101a) ACC_PRIVATE, ACC_STATIC, ACC_FINAL, ACC_SYNTHETIC
+
+ public static com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple[] values();
+ descriptor: ()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=3, locals=0, args_size=0
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+
+ public static com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple valueOf(java.lang.String);
+ descriptor: (Ljava/lang/String;)Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=3, locals=1, args_size=1
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+
+ private com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple();
+ descriptor: (Ljava/lang/String;I)V
+ flags: (0x0002) ACC_PRIVATE
+ Code:
+ stack=3, locals=3, args_size=3
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ Signature: #x // ()V
+
+ private static com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple[] $values();
+ descriptor: ()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ flags: (0x100a) ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
+ Code:
+ stack=3, locals=0, args_size=0
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+
+ static {};
+ descriptor: ()V
+ flags: (0x0008) ACC_STATIC
+ Code:
+ stack=3, locals=0, args_size=0
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+}
+Signature: #x // Ljava/lang/Enum<Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;>;
+SourceFile: "TinyFrameworkEnumSimple.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkExceptionTester.class
Compiled from "TinyFrameworkExceptionTester.java"
public class com.android.hoststubgen.test.tinyframework.TinyFrameworkExceptionTester
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/03-hoststubgen-test-tiny-framework-host-impl-dump.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/03-hoststubgen-test-tiny-framework-host-impl-dump.txt
index 131e0b1f8b48..2218d8d0b2e1 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/03-hoststubgen-test-tiny-framework-host-impl-dump.txt
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/03-hoststubgen-test-tiny-framework-host-impl-dump.txt
@@ -798,6 +798,324 @@ RuntimeInvisibleAnnotations:
android.hosttest.annotation.HostSideTestStub
x: #x()
android.hosttest.annotation.HostSideTestStaticInitializerStub
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex.class
+ Compiled from "TinyFrameworkEnumComplex.java"
+public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex extends java.lang.Enum<com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex>
+ minor version: 0
+ major version: 61
+ flags: (0x4031) ACC_PUBLIC, ACC_FINAL, ACC_SUPER, ACC_ENUM
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex
+ super_class: #x // java/lang/Enum
+ interfaces: 0, fields: 6, methods: 7, attributes: 4
+ public static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex RED;
+ descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ flags: (0x4019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
+
+ public static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex GREEN;
+ descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ flags: (0x4019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
+
+ public static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex BLUE;
+ descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ flags: (0x4019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
+
+ private final java.lang.String mLongName;
+ descriptor: Ljava/lang/String;
+ flags: (0x0012) ACC_PRIVATE, ACC_FINAL
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+
+ private final java.lang.String mShortName;
+ descriptor: Ljava/lang/String;
+ flags: (0x0012) ACC_PRIVATE, ACC_FINAL
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+
+ private static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex[] $VALUES;
+ descriptor: [Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ flags: (0x101a) ACC_PRIVATE, ACC_STATIC, ACC_FINAL, ACC_SYNTHETIC
+
+ public static com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex[] values();
+ descriptor: ()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=1, locals=0, args_size=0
+ x: getstatic #x // Field $VALUES:[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ x: invokevirtual #x // Method "[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;".clone:()Ljava/lang/Object;
+ x: checkcast #x // class "[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;"
+ x: areturn
+ LineNumberTable:
+
+ public static com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex valueOf(java.lang.String);
+ descriptor: (Ljava/lang/String;)Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=2, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex
+ x: aload_0
+ x: invokestatic #x // Method java/lang/Enum.valueOf:(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;
+ x: checkcast #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex
+ x: areturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 10 0 name Ljava/lang/String;
+
+ private com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex(java.lang.String, java.lang.String);
+ descriptor: (Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)V
+ flags: (0x0002) ACC_PRIVATE
+ Code:
+ stack=3, locals=5, args_size=5
+ x: aload_0
+ x: aload_1
+ x: iload_2
+ x: invokespecial #x // Method java/lang/Enum."<init>":(Ljava/lang/String;I)V
+ x: aload_0
+ x: aload_3
+ x: putfield #x // Field mLongName:Ljava/lang/String;
+ x: aload_0
+ x: aload 4
+ x: putfield #x // Field mShortName:Ljava/lang/String;
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 18 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ 0 18 3 longName Ljava/lang/String;
+ 0 18 4 shortName Ljava/lang/String;
+ Signature: #x // (Ljava/lang/String;Ljava/lang/String;)V
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
+
+ public java.lang.String getLongName();
+ descriptor: ()Ljava/lang/String;
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: getfield #x // Field mLongName:Ljava/lang/String;
+ x: areturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
+
+ public java.lang.String getShortName();
+ descriptor: ()Ljava/lang/String;
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: getfield #x // Field mShortName:Ljava/lang/String;
+ x: areturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
+
+ private static com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex[] $values();
+ descriptor: ()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ flags: (0x100a) ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
+ Code:
+ stack=4, locals=0, args_size=0
+ x: iconst_3
+ x: anewarray #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex
+ x: dup
+ x: iconst_0
+ x: getstatic #x // Field RED:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ x: aastore
+ x: dup
+ x: iconst_1
+ x: getstatic #x // Field GREEN:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ x: aastore
+ x: dup
+ x: iconst_2
+ x: getstatic #x // Field BLUE:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ x: aastore
+ x: areturn
+ LineNumberTable:
+
+ static {};
+ descriptor: ()V
+ flags: (0x0008) ACC_STATIC
+ Code:
+ stack=6, locals=0, args_size=0
+ x: new #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex
+ x: dup
+ x: ldc #x // String RED
+ x: iconst_0
+ x: ldc #x // String Red
+ x: ldc #x // String R
+ x: invokespecial #x // Method "<init>":(Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)V
+ x: putstatic #x // Field RED:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ x: new #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex
+ x: dup
+ x: ldc #x // String GREEN
+ x: iconst_1
+ x: ldc #x // String Green
+ x: ldc #x // String G
+ x: invokespecial #x // Method "<init>":(Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)V
+ x: putstatic #x // Field GREEN:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ x: new #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex
+ x: dup
+ x: ldc #x // String BLUE
+ x: iconst_2
+ x: ldc #x // String Blue
+ x: ldc #x // String B
+ x: invokespecial #x // Method "<init>":(Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)V
+ x: putstatic #x // Field BLUE:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ x: invokestatic #x // Method $values:()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ x: putstatic #x // Field $VALUES:[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ x: return
+ LineNumberTable:
+}
+Signature: #x // Ljava/lang/Enum<Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;>;
+SourceFile: "TinyFrameworkEnumComplex.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple.class
+ Compiled from "TinyFrameworkEnumSimple.java"
+public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple extends java.lang.Enum<com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple>
+ minor version: 0
+ major version: 61
+ flags: (0x4031) ACC_PUBLIC, ACC_FINAL, ACC_SUPER, ACC_ENUM
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple
+ super_class: #x // java/lang/Enum
+ interfaces: 0, fields: 3, methods: 5, attributes: 4
+ public static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple CAT;
+ descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ flags: (0x4019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
+
+ public static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple DOG;
+ descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ flags: (0x4019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
+
+ private static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple[] $VALUES;
+ descriptor: [Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ flags: (0x101a) ACC_PRIVATE, ACC_STATIC, ACC_FINAL, ACC_SYNTHETIC
+
+ public static com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple[] values();
+ descriptor: ()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=1, locals=0, args_size=0
+ x: getstatic #x // Field $VALUES:[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ x: invokevirtual #x // Method "[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;".clone:()Ljava/lang/Object;
+ x: checkcast #x // class "[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;"
+ x: areturn
+ LineNumberTable:
+
+ public static com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple valueOf(java.lang.String);
+ descriptor: (Ljava/lang/String;)Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=2, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple
+ x: aload_0
+ x: invokestatic #x // Method java/lang/Enum.valueOf:(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;
+ x: checkcast #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple
+ x: areturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 10 0 name Ljava/lang/String;
+
+ private com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple();
+ descriptor: (Ljava/lang/String;I)V
+ flags: (0x0002) ACC_PRIVATE
+ Code:
+ stack=3, locals=3, args_size=3
+ x: aload_0
+ x: aload_1
+ x: iload_2
+ x: invokespecial #x // Method java/lang/Enum."<init>":(Ljava/lang/String;I)V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 7 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ Signature: #x // ()V
+
+ private static com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple[] $values();
+ descriptor: ()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ flags: (0x100a) ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
+ Code:
+ stack=4, locals=0, args_size=0
+ x: iconst_2
+ x: anewarray #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple
+ x: dup
+ x: iconst_0
+ x: getstatic #x // Field CAT:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ x: aastore
+ x: dup
+ x: iconst_1
+ x: getstatic #x // Field DOG:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ x: aastore
+ x: areturn
+ LineNumberTable:
+
+ static {};
+ descriptor: ()V
+ flags: (0x0008) ACC_STATIC
+ Code:
+ stack=4, locals=0, args_size=0
+ x: new #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple
+ x: dup
+ x: ldc #x // String CAT
+ x: iconst_0
+ x: invokespecial #x // Method "<init>":(Ljava/lang/String;I)V
+ x: putstatic #x // Field CAT:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ x: new #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple
+ x: dup
+ x: ldc #x // String DOG
+ x: iconst_1
+ x: invokespecial #x // Method "<init>":(Ljava/lang/String;I)V
+ x: putstatic #x // Field DOG:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ x: invokestatic #x // Method $values:()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ x: putstatic #x // Field $VALUES:[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ x: return
+ LineNumberTable:
+}
+Signature: #x // Ljava/lang/Enum<Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;>;
+SourceFile: "TinyFrameworkEnumSimple.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkExceptionTester.class
Compiled from "TinyFrameworkExceptionTester.java"
public class com.android.hoststubgen.test.tinyframework.TinyFrameworkExceptionTester
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/12-hoststubgen-test-tiny-framework-host-ext-stub-dump.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/12-hoststubgen-test-tiny-framework-host-ext-stub-dump.txt
index d7f0149494c0..df63815ea0ae 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/12-hoststubgen-test-tiny-framework-host-ext-stub-dump.txt
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/12-hoststubgen-test-tiny-framework-host-ext-stub-dump.txt
@@ -446,6 +446,230 @@ RuntimeInvisibleAnnotations:
android.hosttest.annotation.HostSideTestStub
x: #x()
android.hosttest.annotation.HostSideTestStaticInitializerStub
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex.class
+ Compiled from "TinyFrameworkEnumComplex.java"
+public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex extends java.lang.Enum<com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex>
+ minor version: 0
+ major version: 61
+ flags: (0x4031) ACC_PUBLIC, ACC_FINAL, ACC_SUPER, ACC_ENUM
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex
+ super_class: #x // java/lang/Enum
+ interfaces: 0, fields: 4, methods: 7, attributes: 4
+ public static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex RED;
+ descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ flags: (0x4019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
+
+ public static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex GREEN;
+ descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ flags: (0x4019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
+
+ public static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex BLUE;
+ descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ flags: (0x4019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
+
+ private static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex[] $VALUES;
+ descriptor: [Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ flags: (0x101a) ACC_PRIVATE, ACC_STATIC, ACC_FINAL, ACC_SYNTHETIC
+
+ public static com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex[] values();
+ descriptor: ()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=3, locals=0, args_size=0
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+
+ public static com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex valueOf(java.lang.String);
+ descriptor: (Ljava/lang/String;)Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=3, locals=1, args_size=1
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+
+ private com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex(java.lang.String, java.lang.String);
+ descriptor: (Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)V
+ flags: (0x0002) ACC_PRIVATE
+ Code:
+ stack=3, locals=5, args_size=5
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ Signature: #x // (Ljava/lang/String;Ljava/lang/String;)V
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
+
+ public java.lang.String getLongName();
+ descriptor: ()Ljava/lang/String;
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=3, locals=1, args_size=1
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
+
+ public java.lang.String getShortName();
+ descriptor: ()Ljava/lang/String;
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=3, locals=1, args_size=1
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
+
+ private static com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex[] $values();
+ descriptor: ()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ flags: (0x100a) ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
+ Code:
+ stack=3, locals=0, args_size=0
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+
+ static {};
+ descriptor: ()V
+ flags: (0x0008) ACC_STATIC
+ Code:
+ stack=3, locals=0, args_size=0
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+}
+Signature: #x // Ljava/lang/Enum<Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;>;
+SourceFile: "TinyFrameworkEnumComplex.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple.class
+ Compiled from "TinyFrameworkEnumSimple.java"
+public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple extends java.lang.Enum<com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple>
+ minor version: 0
+ major version: 61
+ flags: (0x4031) ACC_PUBLIC, ACC_FINAL, ACC_SUPER, ACC_ENUM
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple
+ super_class: #x // java/lang/Enum
+ interfaces: 0, fields: 3, methods: 5, attributes: 4
+ public static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple CAT;
+ descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ flags: (0x4019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
+
+ public static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple DOG;
+ descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ flags: (0x4019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
+
+ private static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple[] $VALUES;
+ descriptor: [Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ flags: (0x101a) ACC_PRIVATE, ACC_STATIC, ACC_FINAL, ACC_SYNTHETIC
+
+ public static com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple[] values();
+ descriptor: ()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=3, locals=0, args_size=0
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+
+ public static com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple valueOf(java.lang.String);
+ descriptor: (Ljava/lang/String;)Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=3, locals=1, args_size=1
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+
+ private com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple();
+ descriptor: (Ljava/lang/String;I)V
+ flags: (0x0002) ACC_PRIVATE
+ Code:
+ stack=3, locals=3, args_size=3
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ Signature: #x // ()V
+
+ private static com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple[] $values();
+ descriptor: ()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ flags: (0x100a) ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
+ Code:
+ stack=3, locals=0, args_size=0
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+
+ static {};
+ descriptor: ()V
+ flags: (0x0008) ACC_STATIC
+ Code:
+ stack=3, locals=0, args_size=0
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+}
+Signature: #x // Ljava/lang/Enum<Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;>;
+SourceFile: "TinyFrameworkEnumSimple.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkExceptionTester.class
Compiled from "TinyFrameworkExceptionTester.java"
public class com.android.hoststubgen.test.tinyframework.TinyFrameworkExceptionTester
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/13-hoststubgen-test-tiny-framework-host-ext-impl-dump.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/13-hoststubgen-test-tiny-framework-host-ext-impl-dump.txt
index 3318c7de13f9..3ac9c6a816f1 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/13-hoststubgen-test-tiny-framework-host-ext-impl-dump.txt
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/13-hoststubgen-test-tiny-framework-host-ext-impl-dump.txt
@@ -1046,6 +1046,390 @@ RuntimeInvisibleAnnotations:
android.hosttest.annotation.HostSideTestStub
x: #x()
android.hosttest.annotation.HostSideTestStaticInitializerStub
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex.class
+ Compiled from "TinyFrameworkEnumComplex.java"
+public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex extends java.lang.Enum<com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex>
+ minor version: 0
+ major version: 61
+ flags: (0x4031) ACC_PUBLIC, ACC_FINAL, ACC_SUPER, ACC_ENUM
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex
+ super_class: #x // java/lang/Enum
+ interfaces: 0, fields: 6, methods: 7, attributes: 4
+ public static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex RED;
+ descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ flags: (0x4019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
+
+ public static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex GREEN;
+ descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ flags: (0x4019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
+
+ public static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex BLUE;
+ descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ flags: (0x4019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
+
+ private final java.lang.String mLongName;
+ descriptor: Ljava/lang/String;
+ flags: (0x0012) ACC_PRIVATE, ACC_FINAL
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+
+ private final java.lang.String mShortName;
+ descriptor: Ljava/lang/String;
+ flags: (0x0012) ACC_PRIVATE, ACC_FINAL
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+
+ private static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex[] $VALUES;
+ descriptor: [Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ flags: (0x101a) ACC_PRIVATE, ACC_STATIC, ACC_FINAL, ACC_SYNTHETIC
+
+ public static com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex[] values();
+ descriptor: ()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=4, locals=0, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex
+ x: ldc #x // String values
+ x: ldc #x // String ()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: getstatic #x // Field $VALUES:[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ x: invokevirtual #x // Method "[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;".clone:()Ljava/lang/Object;
+ x: checkcast #x // class "[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;"
+ x: areturn
+ LineNumberTable:
+
+ public static com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex valueOf(java.lang.String);
+ descriptor: (Ljava/lang/String;)Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex
+ x: ldc #x // String valueOf
+ x: ldc #x // String (Ljava/lang/String;)Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex
+ x: aload_0
+ x: invokestatic #x // Method java/lang/Enum.valueOf:(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;
+ x: checkcast #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex
+ x: areturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 10 0 name Ljava/lang/String;
+
+ private com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex(java.lang.String, java.lang.String);
+ descriptor: (Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)V
+ flags: (0x0002) ACC_PRIVATE
+ Code:
+ stack=4, locals=5, args_size=5
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex
+ x: ldc #x // String <init>
+ x: ldc #x // String (Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)V
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: aload_0
+ x: aload_1
+ x: iload_2
+ x: invokespecial #x // Method java/lang/Enum."<init>":(Ljava/lang/String;I)V
+ x: aload_0
+ x: aload_3
+ x: putfield #x // Field mLongName:Ljava/lang/String;
+ x: aload_0
+ x: aload 4
+ x: putfield #x // Field mShortName:Ljava/lang/String;
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 18 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ 11 18 3 longName Ljava/lang/String;
+ 11 18 4 shortName Ljava/lang/String;
+ Signature: #x // (Ljava/lang/String;Ljava/lang/String;)V
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
+
+ public java.lang.String getLongName();
+ descriptor: ()Ljava/lang/String;
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex
+ x: ldc #x // String getLongName
+ x: ldc #x // String ()Ljava/lang/String;
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: aload_0
+ x: getfield #x // Field mLongName:Ljava/lang/String;
+ x: areturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
+
+ public java.lang.String getShortName();
+ descriptor: ()Ljava/lang/String;
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex
+ x: ldc #x // String getShortName
+ x: ldc #x // String ()Ljava/lang/String;
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: aload_0
+ x: getfield #x // Field mShortName:Ljava/lang/String;
+ x: areturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
+
+ private static com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex[] $values();
+ descriptor: ()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ flags: (0x100a) ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
+ Code:
+ stack=4, locals=0, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex
+ x: ldc #x // String $values
+ x: ldc #x // String ()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: iconst_3
+ x: anewarray #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex
+ x: dup
+ x: iconst_0
+ x: getstatic #x // Field RED:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ x: aastore
+ x: dup
+ x: iconst_1
+ x: getstatic #x // Field GREEN:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ x: aastore
+ x: dup
+ x: iconst_2
+ x: getstatic #x // Field BLUE:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ x: aastore
+ x: areturn
+ LineNumberTable:
+
+ static {};
+ descriptor: ()V
+ flags: (0x0008) ACC_STATIC
+ Code:
+ stack=6, locals=0, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex
+ x: ldc #x // String <clinit>
+ x: ldc #x // String ()V
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+ x: new #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex
+ x: dup
+ x: ldc #x // String RED
+ x: iconst_0
+ x: ldc #x // String Red
+ x: ldc #x // String R
+ x: invokespecial #x // Method "<init>":(Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)V
+ x: putstatic #x // Field RED:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ x: new #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex
+ x: dup
+ x: ldc #x // String GREEN
+ x: iconst_1
+ x: ldc #x // String Green
+ x: ldc #x // String G
+ x: invokespecial #x // Method "<init>":(Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)V
+ x: putstatic #x // Field GREEN:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ x: new #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex
+ x: dup
+ x: ldc #x // String BLUE
+ x: iconst_2
+ x: ldc #x // String Blue
+ x: ldc #x // String B
+ x: invokespecial #x // Method "<init>":(Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)V
+ x: putstatic #x // Field BLUE:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ x: invokestatic #x // Method $values:()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ x: putstatic #x // Field $VALUES:[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
+ x: return
+ LineNumberTable:
+}
+Signature: #x // Ljava/lang/Enum<Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;>;
+SourceFile: "TinyFrameworkEnumComplex.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple.class
+ Compiled from "TinyFrameworkEnumSimple.java"
+public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple extends java.lang.Enum<com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple>
+ minor version: 0
+ major version: 61
+ flags: (0x4031) ACC_PUBLIC, ACC_FINAL, ACC_SUPER, ACC_ENUM
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple
+ super_class: #x // java/lang/Enum
+ interfaces: 0, fields: 3, methods: 5, attributes: 4
+ public static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple CAT;
+ descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ flags: (0x4019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
+
+ public static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple DOG;
+ descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ flags: (0x4019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
+
+ private static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple[] $VALUES;
+ descriptor: [Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ flags: (0x101a) ACC_PRIVATE, ACC_STATIC, ACC_FINAL, ACC_SYNTHETIC
+
+ public static com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple[] values();
+ descriptor: ()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=4, locals=0, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple
+ x: ldc #x // String values
+ x: ldc #x // String ()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: getstatic #x // Field $VALUES:[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ x: invokevirtual #x // Method "[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;".clone:()Ljava/lang/Object;
+ x: checkcast #x // class "[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;"
+ x: areturn
+ LineNumberTable:
+
+ public static com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple valueOf(java.lang.String);
+ descriptor: (Ljava/lang/String;)Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple
+ x: ldc #x // String valueOf
+ x: ldc #x // String (Ljava/lang/String;)Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple
+ x: aload_0
+ x: invokestatic #x // Method java/lang/Enum.valueOf:(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;
+ x: checkcast #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple
+ x: areturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 10 0 name Ljava/lang/String;
+
+ private com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple();
+ descriptor: (Ljava/lang/String;I)V
+ flags: (0x0002) ACC_PRIVATE
+ Code:
+ stack=4, locals=3, args_size=3
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple
+ x: ldc #x // String <init>
+ x: ldc #x // String (Ljava/lang/String;I)V
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: aload_0
+ x: aload_1
+ x: iload_2
+ x: invokespecial #x // Method java/lang/Enum."<init>":(Ljava/lang/String;I)V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 7 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ Signature: #x // ()V
+
+ private static com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple[] $values();
+ descriptor: ()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ flags: (0x100a) ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
+ Code:
+ stack=4, locals=0, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple
+ x: ldc #x // String $values
+ x: ldc #x // String ()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: iconst_2
+ x: anewarray #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple
+ x: dup
+ x: iconst_0
+ x: getstatic #x // Field CAT:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ x: aastore
+ x: dup
+ x: iconst_1
+ x: getstatic #x // Field DOG:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ x: aastore
+ x: areturn
+ LineNumberTable:
+
+ static {};
+ descriptor: ()V
+ flags: (0x0008) ACC_STATIC
+ Code:
+ stack=4, locals=0, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple
+ x: ldc #x // String <clinit>
+ x: ldc #x // String ()V
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+ x: new #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple
+ x: dup
+ x: ldc #x // String CAT
+ x: iconst_0
+ x: invokespecial #x // Method "<init>":(Ljava/lang/String;I)V
+ x: putstatic #x // Field CAT:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ x: new #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple
+ x: dup
+ x: ldc #x // String DOG
+ x: iconst_1
+ x: invokespecial #x // Method "<init>":(Ljava/lang/String;I)V
+ x: putstatic #x // Field DOG:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ x: invokestatic #x // Method $values:()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ x: putstatic #x // Field $VALUES:[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ x: return
+ LineNumberTable:
+}
+Signature: #x // Ljava/lang/Enum<Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;>;
+SourceFile: "TinyFrameworkEnumSimple.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkExceptionTester.class
Compiled from "TinyFrameworkExceptionTester.java"
public class com.android.hoststubgen.test.tinyframework.TinyFrameworkExceptionTester
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/run-test-manually.sh b/tools/hoststubgen/hoststubgen/test-tiny-framework/run-test-manually.sh
index e212890592ff..872bbf878de4 100755
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/run-test-manually.sh
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/run-test-manually.sh
@@ -93,6 +93,7 @@ run $HOSTSTUBGEN \
--gen-keep-all-file out/tiny-framework_keep_all.txt \
--gen-input-dump-file out/tiny-framework_dump.txt \
--package-redirect com.unsupported:com.supported \
+ --annotation-allowed-classes-file annotation-allowed-classes-tiny-framework.txt \
$HOSTSTUBGEN_OPTS
# Extract the jar files, so we can look into them.
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex.java b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex.java
new file mode 100644
index 000000000000..51f48188fe74
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2023 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.hoststubgen.test.tinyframework;
+
+import android.hosttest.annotation.HostSideTestKeep;
+import android.hosttest.annotation.HostSideTestStub;
+
+@HostSideTestStub
+public enum TinyFrameworkEnumComplex {
+ @HostSideTestStub
+ RED("Red", "R"),
+ @HostSideTestStub
+ GREEN("Green", "G"),
+ @HostSideTestStub
+ BLUE("Blue", "B");
+
+ @HostSideTestKeep
+ private final String mLongName;
+
+ @HostSideTestKeep
+ private final String mShortName;
+
+ @HostSideTestStub
+ TinyFrameworkEnumComplex(String longName, String shortName) {
+ mLongName = longName;
+ mShortName = shortName;
+ }
+
+ @HostSideTestStub
+ public String getLongName() {
+ return mLongName;
+ }
+
+ @HostSideTestStub
+ public String getShortName() {
+ return mShortName;
+ }
+}
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple.java b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple.java
new file mode 100644
index 000000000000..f440d8667fb4
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2023 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.hoststubgen.test.tinyframework;
+
+import android.hosttest.annotation.HostSideTestStub;
+
+@HostSideTestStub
+public enum TinyFrameworkEnumSimple {
+ @HostSideTestStub
+ CAT,
+ @HostSideTestStub
+ DOG,
+}
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-test/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassTest.java b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-test/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassTest.java
index 29aabc702809..ecb181ba4bbf 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-test/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassTest.java
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-test/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassTest.java
@@ -199,4 +199,43 @@ public class TinyFrameworkClassTest {
public void testPackageRedirect() throws Exception {
assertThat(TinyFrameworkPackageRedirect.foo(1)).isEqualTo(1);
}
+
+ @Test
+ public void testEnumSimple() throws Exception {
+ assertThat(TinyFrameworkEnumSimple.CAT.ordinal()).isEqualTo(0);
+ assertThat(TinyFrameworkEnumSimple.CAT.name()).isEqualTo("CAT");
+
+ assertThat(TinyFrameworkEnumSimple.DOG.ordinal()).isEqualTo(1);
+ assertThat(TinyFrameworkEnumSimple.DOG.name()).isEqualTo("DOG");
+
+ assertThat(TinyFrameworkEnumSimple.valueOf("DOG").ordinal()).isEqualTo(1);
+
+ assertThat(TinyFrameworkEnumSimple.values()).isEqualTo(
+ new TinyFrameworkEnumSimple[] {
+ TinyFrameworkEnumSimple.CAT,
+ TinyFrameworkEnumSimple.DOG,
+ }
+ );
+ }
+
+ @Test
+ public void testEnumComplex() throws Exception {
+ assertThat(TinyFrameworkEnumComplex.RED.ordinal()).isEqualTo(0);
+ assertThat(TinyFrameworkEnumComplex.RED.name()).isEqualTo("RED");
+
+ assertThat(TinyFrameworkEnumComplex.RED.getShortName()).isEqualTo("R");
+
+ assertThat(TinyFrameworkEnumComplex.GREEN.ordinal()).isEqualTo(1);
+ assertThat(TinyFrameworkEnumComplex.GREEN.name()).isEqualTo("GREEN");
+
+ assertThat(TinyFrameworkEnumComplex.valueOf("BLUE").ordinal()).isEqualTo(2);
+
+ assertThat(TinyFrameworkEnumComplex.values()).isEqualTo(
+ new TinyFrameworkEnumComplex[] {
+ TinyFrameworkEnumComplex.RED,
+ TinyFrameworkEnumComplex.GREEN,
+ TinyFrameworkEnumComplex.BLUE,
+ }
+ );
+ }
}
diff --git a/tools/hoststubgen/hoststubgen/test/com/android/hoststubgen/utils/ClassFilterTest.kt b/tools/hoststubgen/hoststubgen/test/com/android/hoststubgen/utils/ClassFilterTest.kt
new file mode 100644
index 000000000000..f6515142ccdb
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/test/com/android/hoststubgen/utils/ClassFilterTest.kt
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2023 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.hoststubgen.utils
+
+import com.android.hoststubgen.ParseException
+import com.google.common.truth.Truth.assertThat
+import org.junit.Assert.fail
+import org.junit.Test
+
+class ClassFilterTest {
+ @Test
+ fun testDefaultTrue() {
+ val f = ClassFilter.newNullFilter(true)
+ assertThat(f.matches("a/b/c")).isEqualTo(true)
+ }
+
+ @Test
+ fun testDefaultFalse() {
+ val f = ClassFilter.newNullFilter(false)
+ assertThat(f.matches("a/b/c")).isEqualTo(false)
+ }
+
+ @Test
+ fun testComplex1() {
+ val f = ClassFilter.buildFromString("""
+ # ** this is a comment **
+ a.b.c # allow
+ !a.b.d # disallow
+ * # allow all
+ """.trimIndent(), false, "X")
+ assertThat(f.getCacheSizeForTest()).isEqualTo(0)
+
+ assertThat(f.matches("a/b/c")).isEqualTo(true)
+ assertThat(f.getCacheSizeForTest()).isEqualTo(1)
+
+ assertThat(f.matches("a/b/d")).isEqualTo(false)
+ assertThat(f.matches("x")).isEqualTo(true)
+
+ assertThat(f.getCacheSizeForTest()).isEqualTo(3)
+
+ // Make sure the cache is working
+ assertThat(f.matches("x")).isEqualTo(true)
+ }
+
+ @Test
+ fun testComplex2() {
+ val f = ClassFilter.buildFromString("""
+ a.b.c # allow
+ !a.* # disallow everything else in package "a".
+ !d.e.f # disallow d.e.f.
+
+ # everything else is allowed by default
+ """.trimIndent(), true, "X")
+ assertThat(f.matches("a/b/c")).isEqualTo(true)
+ assertThat(f.matches("a/x")).isEqualTo(false)
+ assertThat(f.matches("d/e/f")).isEqualTo(false)
+ assertThat(f.matches("d/e/f/g")).isEqualTo(true)
+ assertThat(f.matches("x")).isEqualTo(true)
+ }
+
+ @Test
+ fun testBadFilter1() {
+ try {
+ ClassFilter.buildFromString("""
+ a*
+ """.trimIndent(), true, "FILENAME")
+ fail("ParseException didn't happen")
+ } catch (e: ParseException) {
+ assertThat(e.message).contains("Wildcard")
+ assertThat(e.message).contains("FILENAME")
+ assertThat(e.message).contains("line 1")
+ }
+ }
+} \ No newline at end of file
diff --git a/tools/hoststubgen/scripts/run-all-tests.sh b/tools/hoststubgen/scripts/run-all-tests.sh
index ba1d404eba68..4afa2d7a659a 100755
--- a/tools/hoststubgen/scripts/run-all-tests.sh
+++ b/tools/hoststubgen/scripts/run-all-tests.sh
@@ -33,6 +33,9 @@ MUST_BUILD_MODULES=(
# First, build all the test / etc modules. This shouldn't fail.
run m "${MUST_BUILD_MODULES[@]}"
+# Run the hoststubgen unittests / etc
+run atest hoststubgentest hoststubgen-invoke-test
+
# Next, run the golden check. This should always pass too.
# The following scripts _should_ pass too, but they depend on the internal paths to soong generated
# files, and they may fail when something changes in the build system.